blob: 036aa09f3df4d99d007b4bb40895904280a4d593 [file] [log] [blame]
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;
}
}