use of org.apache.hyracks.storage.common.buffercache.ICachedPage in project asterixdb by apache.
the class BloomFilter method contains.
public boolean contains(ITupleReference tuple, long[] hashes) throws HyracksDataException {
if (numPages == 0) {
return false;
}
MurmurHash128Bit.hash3_x64_128(tuple, keyFields, SEED, hashes);
for (int i = 0; i < numHashes; ++i) {
long hash = Math.abs((hashes[0] + i * hashes[1]) % numBits);
// we increment the page id by one, since the metadata page id of the filter is 0.
ICachedPage page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, (int) (hash / numBitsPerPage) + 1), false);
page.acquireReadLatch();
try {
ByteBuffer buffer = page.getBuffer();
// divide by 8
int byteIndex = (int) (hash % numBitsPerPage) >> 3;
byte b = buffer.get(byteIndex);
// mod 8
int bitIndex = (int) (hash % numBitsPerPage) & 0x07;
if (!((b & (1L << bitIndex)) != 0)) {
return false;
}
} finally {
page.releaseReadLatch();
bufferCache.unpin(page);
}
}
return true;
}
use of org.apache.hyracks.storage.common.buffercache.ICachedPage in project asterixdb by apache.
the class BTree method performOp.
private void performOp(int pageId, ICachedPage parent, boolean parentIsReadLatched, BTreeOpContext ctx) throws HyracksDataException {
ICachedPage node = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
ctx.getInteriorFrame().setPage(node);
// this check performs an unprotected read in the page
// the following could happen: TODO fill out
boolean unsafeIsLeaf = ctx.getInteriorFrame().isLeaf();
boolean isReadLatched = acquireLatch(node, ctx, unsafeIsLeaf);
boolean smFlag = ctx.getInteriorFrame().getSmFlag();
// re-check leafness after latching
boolean isLeaf = ctx.getInteriorFrame().isLeaf();
// remember trail of pageLsns, to unwind recursion in case of an ongoing
// structure modification
ctx.getPageLsns().add(ctx.getInteriorFrame().getPageLsn());
try {
// Latch coupling: unlatch parent.
if (parent != null) {
if (parentIsReadLatched) {
parent.releaseReadLatch();
} else {
parent.releaseWriteLatch(true);
}
bufferCache.unpin(parent);
}
if (!isLeaf || smFlag) {
if (!smFlag) {
// We use this loop to deal with possibly multiple operation
// restarts due to ongoing structure modifications during
// the descent.
boolean repeatOp = true;
while (repeatOp && ctx.getOpRestarts() < MAX_RESTARTS) {
int childPageId = ctx.getInteriorFrame().getChildPageId(ctx.getPred());
performOp(childPageId, node, isReadLatched, ctx);
node = null;
if (!ctx.getPageLsns().isEmpty()) {
if (ctx.getPageLsns().getLast() == FULL_RESTART_OP) {
break;
} else if (ctx.getPageLsns().getLast() == RESTART_OP) {
// Pop the restart op indicator.
ctx.getPageLsns().removeLast();
node = isConsistent(pageId, ctx);
if (node != null) {
isReadLatched = true;
// Descend the tree again.
continue;
} else {
// Pop pageLsn of this page (version seen by this op during descent).
ctx.getPageLsns().removeLast();
// This node is not consistent set the restart indicator for upper level.
ctx.getPageLsns().add(RESTART_OP);
break;
}
}
}
switch(ctx.getOperation()) {
case INSERT:
case UPSERT:
case UPDATE:
{
// Is there a propagated split key?
if (ctx.getSplitKey().getBuffer() != null) {
ICachedPage interiorNode = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
interiorNode.acquireWriteLatch();
try {
// Insert or update op. Both can cause split keys to propagate upwards.
insertInterior(interiorNode, pageId, ctx.getSplitKey().getTuple(), ctx);
} finally {
interiorNode.releaseWriteLatch(true);
bufferCache.unpin(interiorNode);
}
} else {
unsetSmPages(ctx);
}
break;
}
case DELETE:
{
if (ctx.getSplitKey().getBuffer() != null) {
throw new HyracksDataException("Split key was propagated during delete. Delete allows empty leaf pages.");
}
break;
}
default:
{
// Do nothing for Search and DiskOrderScan.
break;
}
}
// Operation completed.
repeatOp = false;
}
// end while
} else {
// smFlag
ctx.setOpRestarts(ctx.getOpRestarts() + 1);
if (isReadLatched) {
node.releaseReadLatch();
} else {
node.releaseWriteLatch(true);
}
bufferCache.unpin(node);
// TODO: this should be an instant duration lock, how to do
// this in java?
// instead we just immediately release the lock. this is
// inefficient but still correct and will not cause
// latch-deadlock
treeLatch.readLock().lock();
treeLatch.readLock().unlock();
// unwind recursion and restart operation, find lowest page
// with a pageLsn as seen by this operation during descent
// pop current page lsn
ctx.getPageLsns().removeLast();
// put special value on the stack to inform caller of
// restart
ctx.getPageLsns().add(RESTART_OP);
}
} else {
// isLeaf and !smFlag
// We may have to restart an op to avoid latch deadlock.
boolean restartOp = false;
ctx.getLeafFrame().setPage(node);
switch(ctx.getOperation()) {
case INSERT:
{
int targetTupleIndex = ctx.getLeafFrame().findInsertTupleIndex(ctx.getPred().getLowKey());
restartOp = insertLeaf(ctx.getPred().getLowKey(), targetTupleIndex, pageId, ctx);
break;
}
case UPSERT:
{
int targetTupleIndex = ctx.getLeafFrame().findUpsertTupleIndex(ctx.getPred().getLowKey());
restartOp = upsertLeaf(ctx.getPred().getLowKey(), targetTupleIndex, pageId, ctx);
break;
}
case UPDATE:
{
int oldTupleIndex = ctx.getLeafFrame().findUpdateTupleIndex(ctx.getPred().getLowKey());
restartOp = updateLeaf(ctx.getPred().getLowKey(), oldTupleIndex, pageId, ctx);
break;
}
case DELETE:
{
restartOp = deleteLeaf(node, pageId, ctx.getPred().getLowKey(), ctx);
break;
}
case SEARCH:
{
ctx.getCursorInitialState().setSearchOperationCallback(ctx.getSearchCallback());
ctx.getCursorInitialState().setOriginialKeyComparator(ctx.getCmp());
ctx.getCursorInitialState().setPage(node);
ctx.getCursorInitialState().setPageId(pageId);
ctx.getCursor().open(ctx.getCursorInitialState(), ctx.getPred());
break;
}
}
if (ctx.getOperation() != IndexOperation.SEARCH) {
node.releaseWriteLatch(true);
bufferCache.unpin(node);
}
if (restartOp) {
// Wait for the SMO to persistFrontiers before restarting.
treeLatch.readLock().lock();
treeLatch.readLock().unlock();
ctx.getPageLsns().removeLast();
ctx.getPageLsns().add(FULL_RESTART_OP);
}
}
} catch (HyracksDataException e) {
if (!ctx.isExceptionHandled()) {
if (node != null) {
if (isReadLatched) {
node.releaseReadLatch();
} else {
node.releaseWriteLatch(true);
}
bufferCache.unpin(node);
ctx.setExceptionHandled(true);
}
}
throw e;
} catch (Exception e) {
if (node != null) {
if (isReadLatched) {
node.releaseReadLatch();
} else {
node.releaseWriteLatch(true);
}
bufferCache.unpin(node);
}
HyracksDataException wrappedException = HyracksDataException.create(e);
ctx.setExceptionHandled(true);
throw wrappedException;
}
}
use of org.apache.hyracks.storage.common.buffercache.ICachedPage in project asterixdb by apache.
the class BTree method validate.
private void validate(BTreeOpContext ctx, int pageId) throws HyracksDataException {
ICachedPage page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
ctx.getInteriorFrame().setPage(page);
PageValidationInfo currentPvi = ctx.getValidationInfos().peekFirst();
boolean isLeaf = ctx.getInteriorFrame().isLeaf();
if (isLeaf) {
ctx.getLeafFrame().setPage(page);
ctx.getLeafFrame().validate(currentPvi);
} else {
PageValidationInfo nextPvi = ctx.createPageValidationInfo(currentPvi);
List<Integer> children = ((BTreeNSMInteriorFrame) ctx.getInteriorFrame()).getChildren(ctx.getCmp());
ctx.getInteriorFrame().validate(currentPvi);
for (int i = 0; i < children.size(); i++) {
ctx.getInteriorFrame().setPage(page);
if (children.size() == 1) {
// There is a single child pointer with no keys, so propagate both low and high ranges
nextPvi.propagateLowRangeKey(currentPvi);
nextPvi.propagateHighRangeKey(currentPvi);
} else if (i == 0) {
// There is more than one child pointer and this is the left-most child pointer, so:
// 1) propagate the low range key from the parent
// 2) adjust the high range key
nextPvi.propagateLowRangeKey(currentPvi);
ctx.getInteriorFrameTuple().resetByTupleIndex(ctx.getInteriorFrame(), i);
nextPvi.adjustHighRangeKey(ctx.getInteriorFrameTuple());
} else if (i == children.size() - 1) {
// There is more than one child pointer and this is the right-most child pointer, so:
// 1) propagate the high range key from the parent
// 2) adjust the low range key
nextPvi.propagateHighRangeKey(currentPvi);
ctx.getInteriorFrameTuple().resetByTupleIndex(ctx.getInteriorFrame(), i - 1);
nextPvi.adjustLowRangeKey(ctx.getInteriorFrameTuple());
} else {
// There is more than one child pointer and this pointer is not the left/right-most pointer, so:
// 1) adjust the low range key
// 2) adjust the high range key
ctx.getInteriorFrameTuple().resetByTupleIndex(ctx.getInteriorFrame(), i - 1);
nextPvi.adjustLowRangeKey(ctx.getInteriorFrameTuple());
ctx.getInteriorFrameTuple().resetByTupleIndex(ctx.getInteriorFrame(), i);
nextPvi.adjustHighRangeKey(ctx.getInteriorFrameTuple());
}
ctx.getValidationInfos().addFirst(nextPvi);
validate(ctx, children.get(i));
}
}
bufferCache.unpin(page);
ctx.getValidationInfos().removeFirst();
}
use of org.apache.hyracks.storage.common.buffercache.ICachedPage in project asterixdb by apache.
the class BTree method createNewRoot.
private void createNewRoot(BTreeOpContext ctx) throws HyracksDataException {
// Make sure the root is always in the same page.
ICachedPage leftNode = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, ctx.getSplitKey().getLeftPage()), false);
leftNode.acquireWriteLatch();
try {
int newLeftId = freePageManager.takePage(ctx.getMetaFrame());
ICachedPage newLeftNode = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, newLeftId), true);
newLeftNode.acquireWriteLatch();
try {
boolean largePage = false;
if (leftNode.getBuffer().capacity() > newLeftNode.getBuffer().capacity()) {
bufferCache.resizePage(newLeftNode, leftNode.getBuffer().capacity() / bufferCache.getPageSize(), ctx);
largePage = true;
}
// Copy left child to new left child.
System.arraycopy(leftNode.getBuffer().array(), 0, newLeftNode.getBuffer().array(), 0, newLeftNode.getBuffer().capacity());
ctx.getInteriorFrame().setPage(newLeftNode);
ctx.getInteriorFrame().setSmFlag(false);
// Remember LSN to set it in the root.
long leftNodeLSN = ctx.getInteriorFrame().getPageLsn();
// Initialize new root (leftNode becomes new root).
if (largePage) {
bufferCache.resizePage(leftNode, 1, ctx);
ctx.getInteriorFrame().setPage(leftNode);
ctx.getInteriorFrame().setLargeFlag(false);
} else {
ctx.getInteriorFrame().setPage(leftNode);
ctx.getInteriorFrame().setLargeFlag(false);
}
ctx.getInteriorFrame().initBuffer((byte) (ctx.getInteriorFrame().getLevel() + 1));
// Copy over LSN.
ctx.getInteriorFrame().setPageLsn(leftNodeLSN);
// Will be cleared later in unsetSmPages.
ctx.getInteriorFrame().setSmFlag(true);
ctx.getSplitKey().setLeftPage(newLeftId);
int targetTupleIndex = ctx.getInteriorFrame().findInsertTupleIndex(ctx.getSplitKey().getTuple());
int tupleSize = ctx.getInteriorFrame().getBytesRequiredToWriteTuple(ctx.getSplitKey().getTuple());
if (tupleSize > maxTupleSize) {
throw HyracksDataException.create(ErrorCode.RECORD_IS_TOO_LARGE, tupleSize, maxTupleSize);
}
ctx.getInteriorFrame().insert(ctx.getSplitKey().getTuple(), targetTupleIndex);
} finally {
newLeftNode.releaseWriteLatch(true);
bufferCache.unpin(newLeftNode);
}
} finally {
leftNode.releaseWriteLatch(true);
bufferCache.unpin(leftNode);
}
}
use of org.apache.hyracks.storage.common.buffercache.ICachedPage in project asterixdb by apache.
the class BTreeCountingSearchCursor method fetchNextLeafPage.
private void fetchNextLeafPage(int nextLeafPage) throws HyracksDataException {
do {
ICachedPage nextLeaf = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, nextLeafPage), false);
if (exclusiveLatchNodes) {
nextLeaf.acquireWriteLatch();
page.releaseWriteLatch(isPageDirty);
} else {
nextLeaf.acquireReadLatch();
page.releaseReadLatch();
}
bufferCache.unpin(page);
page = nextLeaf;
isPageDirty = false;
frame.setPage(page);
nextLeafPage = frame.getNextLeaf();
} while (frame.getTupleCount() == 0 && nextLeafPage > 0);
}
Aggregations