bTree.getBTreeSpec().setRootPageNumber(ByteTool.bytesToInt(metaData, BTreeSpec.ROOT_OFF, bTree.getBTreeSpec().getMsbFirst()));
bTree.getBTreeSpec().setNodeSize(ByteTool.bytesToInt(metaData, BTreeSpec.NODE_SIZE_OFF, bTree.getBTreeSpec().getMsbFirst()));
// set latest dataPage PageNumber in bufferedPage
PageNumber ldpReservedPage = new PageNumber(ByteTool.bytesToInt(metaData, BTreeSpec.LATEST_DATA_PAGE_LIST_OFF, bTree.getBTreeSpec().getMsbFirst()));
ldpReservedPage.setTreeId(bTree.getBtreeId());
LinkedList reservedList = new LinkedList();
if (ldpReservedPage.getPageNumber() > 0) {
// (page size - page number - next page number) / 4
int pageTotalSpace = (bTree.getBTreeSpec().getPageSize() - BTreeSpec.PAGENUMBER_BYTE_SIZE - BTreeSpec.PAGENUMBER_BYTE_SIZE) / BTreeSpec.PAGENUMBER_BYTE_SIZE;
int nextLDPReservedPageNum = ldpReservedPage.getPageNumber();
byte[] page = bTree.getBuffer().getPage(bTree.getBtreeId(), ldpReservedPage);
if (page != null) {
int ldpNumOffset = BTreeSpec.OFF_PAGENUMBER + BTreeSpec.PAGENUMBER_BYTE_SIZE;
int ldpNum = ByteTool.bytesToInt(page, ldpNumOffset, bTree.getBTreeSpec().getMsbFirst());
while (nextLDPReservedPageNum > 0) {
for (int i = 0; i < ldpNum; i++) {
PageNumber latestDataPage = new PageNumber(ByteTool.bytesToInt(page, ldpNumOffset + 4 + i * BTreeSpec.PAGENUMBER_BYTE_SIZE, bTree.getBTreeSpec().getMsbFirst()));
latestDataPage.setTreeId(bTree.getBtreeId());
bTree.getBuffer().addToLatestDataPageListWhenOpenBTree(bTree.getBtreeId(), latestDataPage);
}
if ((ldpNum < pageTotalSpace - 1) || (ldpNum == pageTotalSpace)) {
nextLDPReservedPageNum = -1;
} else {
nextLDPReservedPageNum = ByteTool.bytesToInt(page, bTree.getBTreeSpec()
.getPageSize() - 4, bTree.getBTreeSpec().getMsbFirst());
}
/* this page can't be used because if btree is closed abnormally in the way
metapage contains old info whereas other pages has been updated. Thus maybe
this "ldpReservedPage" is reused and occurs in some BTree(Data)Node's links. Then
btree reopen we read obsolete data from meta page and put this "ldpReservedPage" to
free page list, which later may cause to "Used Freed page" exception. The same
thing happens to pages storing free pages. We prefer to losing these "savePages".
*/
bTree.getBuffer().releasePage(bTree.getBtreeId(), ldpReservedPage, false);
reservedList.add(ldpReservedPage);
if (nextLDPReservedPageNum > 0) {
ldpReservedPage = new PageNumber(nextLDPReservedPageNum);
ldpReservedPage.setTreeId(bTree.getBtreeId());
page = bTree.getBuffer().getPage(bTree.getBtreeId(), ldpReservedPage);
if (page == null) {
break;
}
ldpNum = ByteTool.bytesToInt(page, ldpNumOffset, bTree.getBTreeSpec().getMsbFirst());
}
}
}
}
// set free list in buffererdPage
int freePageNums = ByteTool.bytesToInt(metaData, BTreeSpec.FREE_PAGE_LIST_OFF, bTree.getBTreeSpec().getMsbFirst());
if (freePageNums == 0) {
bTree.getBuffer().setReserveredList(bTree.getBtreeId(), reservedList);
return;
}
logger.debug("freePageNums = " + freePageNums);
int leftSpace = (bTree.getBTreeSpec().getPageSize() - BTreeSpec.FREE_PAGE_LIST_OFF - 4) / BTreeSpec.PAGENUMBER_BYTE_SIZE;
int size = (freePageNums <= leftSpace) ? freePageNums : (leftSpace - 1);
for (int i = 0; i < size; i++) {
PageNumber freePage = new PageNumber(ByteTool.bytesToInt(metaData, BTreeSpec.FREE_PAGE_LIST_OFF + 4 + i * BTreeSpec.PAGENUMBER_BYTE_SIZE, bTree.getBTreeSpec().getMsbFirst()));
freePage.setTreeId(bTree.getBtreeId());
bTree.getBuffer().addToFreeListWhenOpenBTree(bTree.getBtreeId(), freePage);
}
if (freePageNums > leftSpace) {
//(page size - free page number - next page number)/ 4
int pageTotalSpace = (bTree.getBTreeSpec().getPageSize() - 4 - BTreeSpec.PAGENUMBER_BYTE_SIZE) / BTreeSpec.PAGENUMBER_BYTE_SIZE;
int nextFPReservedPageNum = ByteTool.bytesToInt(metaData, BTreeSpec.FREE_PAGE_LIST_OFF + 4 + size * BTreeSpec.PAGENUMBER_BYTE_SIZE, bTree.getBTreeSpec().getMsbFirst());
PageNumber fpReservedPage = new PageNumber(nextFPReservedPageNum);
fpReservedPage.setTreeId(bTree.getBtreeId());
byte[] page = bTree.getBuffer().getPage(bTree.getBtreeId(), fpReservedPage);
if (page != null) {
int freePageNumOffset = BTreeSpec.OFF_PAGENUMBER + BTreeSpec.PAGENUMBER_BYTE_SIZE;
int freeNum = ByteTool.bytesToInt(page, freePageNumOffset, bTree.getBTreeSpec().getMsbFirst());
while (nextFPReservedPageNum > 0) {
for (int i = 0; i < freeNum; i++) {
PageNumber freePage = new PageNumber(ByteTool.bytesToInt(page, freePageNumOffset + 4 + i * BTreeSpec.PAGENUMBER_BYTE_SIZE, bTree.getBTreeSpec().getMsbFirst()));
freePage.setTreeId(bTree.getBtreeId());
bTree.getBuffer().addToFreeListWhenOpenBTree(bTree.getBtreeId(), freePage);
}
if ((freeNum < pageTotalSpace - 1) || (freeNum == pageTotalSpace)) {
nextFPReservedPageNum = -1;
} else {
nextFPReservedPageNum = ByteTool.bytesToInt(page, bTree.getBTreeSpec().getPageSize() - BTreeSpec.PAGENUMBER_BYTE_SIZE, bTree.getBTreeSpec().getMsbFirst());
}
/* add the page which save freelist to freelist,becuase it's unuseful later */
fpReservedPage.setTreeId(bTree.getBtreeId());
reservedList.add(fpReservedPage);
bTree.getBuffer().releasePage(bTree.getBtreeId(), fpReservedPage, false);
if (nextFPReservedPageNum > 0) {
fpReservedPage = new PageNumber(nextFPReservedPageNum);
fpReservedPage.setTreeId(bTree.getBtreeId());
page = bTree.getBuffer().getPage(bTree.getBtreeId(), fpReservedPage);
if (page == null) {
break;
}