实现这几个类
src/java/simpledb/storage/HeapPage.java
src/java/simpledb/storage/HeapFile.java
其中HeapPage的实现比较简单,就是在前面BitMap的基础上,数组上实现插入和删除。
HeapPage.java
先把dirty部分的get和set方法封装好。
/**
* Marks this page as dirty/not dirty and record that transaction
* that did the dirtying
*/
public void markDirty(boolean dirty, TransactionId tid) {
// some code goes here
this.dirty = dirty;
this.dirtyId = tid;
}
/**
* Returns the tid of the transaction that last dirtied this page, or null if the page is not dirty
*/
public TransactionId isDirty() {
// some code goes here
return (dirty? dirtyId : null);
}
封装一个BitMap的操作
/**
* Abstraction to fill or clear a slot on this page.
*/
private void markSlotUsed(int i, boolean value) {
// some code goes here
byte b = header[i/8];
byte mask = (byte)(1 << (i % 8));
if(value){
header[i / 8] = (byte) (b | mask);
}else{
header[i / 8] &= (byte) ~(b & mask);
}
}
然后就是insert和delete操作,都比较常规
/**
* Adds the specified tuple to the page; the tuple should be updated to reflect
* that it is now stored on this page.
* @throws DbException if the page is full (no empty slots) or tupledesc
* is mismatch.
* @param t The tuple to add.
*/
public void insertTuple(Tuple t) throws DbException {
// some code goes here
if(getNumEmptySlots() == 0){
throw new DbException("page is full");
}
if(!t.getTupleDesc().equals(td)){
throw new DbException("tuple descriptor does not match");
}
for(int i = 0; i < numSlots; i++){
if(!isSlotUsed(i)){
markSlotUsed(i, true);
t.setRecordId(new RecordId(pid, i));
tuples[i] = t;
break;
}
}
}
delete操作
/**
* Delete the specified tuple from the page; the corresponding header bit should be updated to reflect
* that it is no longer stored on any page.
* @throws DbException if this tuple is not on this page, or tuple slot is
* already empty.
* @param t The tuple to delete
*/
public void deleteTuple(Tuple t) throws DbException {
// some code goes here
int tid = t.getRecordId().getTupleNumber();
if(tuples[tid] == null || !tuples[tid].equals(t)){
throw new DbException("tuple does not exist");
}
if(!isSlotUsed(tid)){
throw new DbException("the slot is already empty");
}
markSlotUsed(tid, false);
tuples[tid] = null;
}
HeapFile的insert,需要首先找到的File对应的所有Page,然后如果Page能找到空位,那么就执行insert page,如果所有page都满,那么需要新开一页。
// see DbFile.java for javadocs
public List<Page> insertTuple(TransactionId tid, Tuple t)
throws DbException, IOException, TransactionAbortedException {
// some code goes here
List<Page> pageList = new ArrayList<>();
for(int i = 0; i < numPages(); i++){
HeapPage page = (HeapPage) Database.getBufferPool()
.getPage(tid, new HeapPageId(this.getId(), i),Permissions.READ_WRITE);
if(page.getNumEmptySlots() == 0){
continue;
}
page.insertTuple(t);
pageList.add(page);
return pageList;
}
// no page (缺页) 将数据写到数据文件中,并增加到缓存中。
BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(f,true));
byte[] emptyData = HeapPage.createEmptyPageData();
bw.write(emptyData);
bw.close();
// load into cache
HeapPage p = (HeapPage) Database.getBufferPool().getPage(tid,
new HeapPageId(getId(),numPages()-1),Permissions.READ_WRITE);
p.insertTuple(t);
pageList.add(p);
return pageList;
}
Delete操作直接可以由tuple找到对应的pageId,然后直接执行delete
// see DbFile.java for javadocs
public ArrayList<Page> deleteTuple(TransactionId tid, Tuple t) throws DbException,
TransactionAbortedException {
// some code goes here
ArrayList<Page> pageList = new ArrayList<>();
HeapPage p = (HeapPage) Database.getBufferPool().getPage(tid,
new HeapPageId(getId(),t.getRecordId().getPageId().getPageNumber()),
Permissions.READ_WRITE);
pageList.add(p);
p.deleteTuple(t);
return pageList;
}