| package edu.uci.ics.hyracks.storage.am.common.freepage; |
| |
| import edu.uci.ics.hyracks.api.exceptions.HyracksDataException; |
| import edu.uci.ics.hyracks.storage.am.common.api.IFreePageManager; |
| import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexMetaDataFrame; |
| import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexMetaDataFrameFactory; |
| import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache; |
| import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage; |
| import edu.uci.ics.hyracks.storage.common.file.BufferedFileHandle; |
| |
| public class LinkedListFreePageManager implements IFreePageManager { |
| |
| private static final byte META_PAGE_LEVEL_INDICATOR = -1; |
| private static final byte FREE_PAGE_LEVEL_INDICATOR = -2; |
| private final IBufferCache bufferCache; |
| private final int headPage; |
| private int fileId = -1; |
| private final ITreeIndexMetaDataFrameFactory metaDataFrameFactory; |
| |
| public LinkedListFreePageManager(IBufferCache bufferCache, |
| int headPage, ITreeIndexMetaDataFrameFactory metaDataFrameFactory) { |
| this.bufferCache = bufferCache; |
| this.headPage = headPage; |
| this.metaDataFrameFactory = metaDataFrameFactory; |
| } |
| |
| @Override |
| public void addFreePage(ITreeIndexMetaDataFrame metaFrame, int freePage) |
| throws HyracksDataException { |
| |
| ICachedPage metaNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, headPage), false); |
| metaNode.acquireWriteLatch(); |
| |
| try { |
| metaFrame.setPage(metaNode); |
| |
| if (metaFrame.hasSpace()) { |
| metaFrame.addFreePage(freePage); |
| } else { |
| // allocate a new page in the chain of meta pages |
| int newPage = metaFrame.getFreePage(); |
| if (newPage < 0) { |
| throw new Exception( |
| "Inconsistent Meta Page State. It has no space, but it also has no entries."); |
| } |
| |
| ICachedPage newNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, newPage), |
| false); |
| newNode.acquireWriteLatch(); |
| |
| try { |
| int metaMaxPage = metaFrame.getMaxPage(); |
| |
| // copy metaDataPage to newNode |
| System.arraycopy(metaNode.getBuffer().array(), 0, newNode |
| .getBuffer().array(), 0, metaNode.getBuffer() |
| .capacity()); |
| |
| metaFrame.initBuffer(META_PAGE_LEVEL_INDICATOR); |
| metaFrame.setNextPage(newPage); |
| metaFrame.setMaxPage(metaMaxPage); |
| metaFrame.addFreePage(freePage); |
| } finally { |
| newNode.releaseWriteLatch(); |
| bufferCache.unpin(newNode); |
| } |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } finally { |
| metaNode.releaseWriteLatch(); |
| bufferCache.unpin(metaNode); |
| } |
| } |
| |
| @Override |
| public int getFreePage(ITreeIndexMetaDataFrame metaFrame) |
| throws HyracksDataException { |
| ICachedPage metaNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, headPage), false); |
| |
| metaNode.acquireWriteLatch(); |
| |
| int freePage = -1; |
| try { |
| metaFrame.setPage(metaNode); |
| freePage = metaFrame.getFreePage(); |
| if (freePage < 0) { // no free page entry on this page |
| int nextPage = metaFrame.getNextPage(); |
| if (nextPage > 0) { // sibling may have free pages |
| ICachedPage nextNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, nextPage), |
| false); |
| |
| nextNode.acquireWriteLatch(); |
| // we copy over the free space entries of nextpage into the |
| // first meta page (metaDataPage) |
| // we need to link the first page properly to the next page |
| // of nextpage |
| try { |
| // remember entries that remain unchanged |
| int maxPage = metaFrame.getMaxPage(); |
| |
| // copy entire page (including sibling pointer, free |
| // page entries, and all other info) |
| // after this copy nextPage is considered a free page |
| System.arraycopy(nextNode.getBuffer().array(), 0, |
| metaNode.getBuffer().array(), 0, nextNode |
| .getBuffer().capacity()); |
| |
| // reset unchanged entry |
| metaFrame.setMaxPage(maxPage); |
| |
| freePage = metaFrame.getFreePage(); |
| // sibling also has no free pages, this "should" not |
| // happen, but we deal with it anyway just to be safe |
| if (freePage < 0) { |
| freePage = nextPage; |
| } else { |
| metaFrame.addFreePage(nextPage); |
| } |
| } finally { |
| nextNode.releaseWriteLatch(); |
| bufferCache.unpin(nextNode); |
| } |
| } else { |
| freePage = metaFrame.getMaxPage(); |
| freePage++; |
| metaFrame.setMaxPage(freePage); |
| } |
| } |
| } finally { |
| metaNode.releaseWriteLatch(); |
| bufferCache.unpin(metaNode); |
| } |
| |
| return freePage; |
| } |
| |
| @Override |
| public int getMaxPage(ITreeIndexMetaDataFrame metaFrame) |
| throws HyracksDataException { |
| ICachedPage metaNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, headPage), false); |
| metaNode.acquireWriteLatch(); |
| int maxPage = -1; |
| try { |
| metaFrame.setPage(metaNode); |
| maxPage = metaFrame.getMaxPage(); |
| } finally { |
| metaNode.releaseWriteLatch(); |
| bufferCache.unpin(metaNode); |
| } |
| return maxPage; |
| } |
| |
| @Override |
| public void init(ITreeIndexMetaDataFrame metaFrame, int currentMaxPage) |
| throws HyracksDataException { |
| // initialize meta data page |
| ICachedPage metaNode = bufferCache.pin( |
| BufferedFileHandle.getDiskPageId(fileId, headPage), true); |
| |
| metaNode.acquireWriteLatch(); |
| try { |
| metaFrame.setPage(metaNode); |
| metaFrame.initBuffer(META_PAGE_LEVEL_INDICATOR); |
| metaFrame.setMaxPage(currentMaxPage); |
| } finally { |
| metaNode.releaseWriteLatch(); |
| bufferCache.unpin(metaNode); |
| } |
| } |
| |
| @Override |
| public ITreeIndexMetaDataFrameFactory getMetaDataFrameFactory() { |
| return metaDataFrameFactory; |
| } |
| |
| @Override |
| public byte getFreePageLevelIndicator() { |
| return FREE_PAGE_LEVEL_INDICATOR; |
| } |
| |
| @Override |
| public byte getMetaPageLevelIndicator() { |
| return META_PAGE_LEVEL_INDICATOR; |
| } |
| |
| @Override |
| public boolean isFreePage(ITreeIndexMetaDataFrame metaFrame) { |
| return metaFrame.getLevel() == FREE_PAGE_LEVEL_INDICATOR; |
| } |
| |
| @Override |
| public boolean isMetaPage(ITreeIndexMetaDataFrame metaFrame) { |
| return metaFrame.getLevel() == META_PAGE_LEVEL_INDICATOR; |
| } |
| |
| @Override |
| public int getFirstMetadataPage() { |
| return headPage; |
| } |
| |
| @Override |
| public void open(int fileId) { |
| this.fileId = fileId; |
| } |
| |
| @Override |
| public void close() { |
| fileId = -1; |
| } |
| } |