in hyracks/hyracks-storage-am-rtree/src/main/java/org/apache/hyracks/storage/am/rtree/impls/RTree.java [205:328]
private ICachedPage findLeaf(RTreeOpContext ctx) throws HyracksDataException {
int pageId = rootPage;
boolean writeLatched = false;
boolean readLatched = false;
boolean succeeded = false;
ICachedPage node = null;
boolean isLeaf = false;
long pageLsn = 0, parentLsn = 0;
try {
while (true) {
if (!writeLatched) {
node = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
ctx.interiorFrame.setPage(node);
isLeaf = ctx.interiorFrame.isLeaf();
if (isLeaf) {
node.acquireWriteLatch();
writeLatched = true;
if (!ctx.interiorFrame.isLeaf()) {
node.releaseWriteLatch(true);
writeLatched = false;
bufferCache.unpin(node);
continue;
}
} else {
// Be optimistic and grab read latch first. We will swap
// it to write latch if we need to enlarge the best
// child tuple.
node.acquireReadLatch();
readLatched = true;
}
}
if (pageId != rootPage && parentLsn < ctx.interiorFrame.getPageNsn()) {
// Concurrent split detected, go back to parent and
// re-choose the best child
if (writeLatched) {
node.releaseWriteLatch(true);
writeLatched = false;
bufferCache.unpin(node);
} else {
node.releaseReadLatch();
readLatched = false;
bufferCache.unpin(node);
}
pageId = ctx.pathList.getLastPageId();
if (pageId != rootPage) {
parentLsn = ctx.pathList.getPageLsn(ctx.pathList.size() - 2);
}
ctx.pathList.moveLast();
continue;
}
pageLsn = ctx.interiorFrame.getPageLsn();
ctx.pathList.add(pageId, pageLsn, -1);
if (!isLeaf) {
// findBestChild must be called *before* checkIfEnlarementIsNeeded
int childPageId = ctx.interiorFrame.findBestChild(ctx.getTuple(), ctx.cmp);
boolean enlarementIsNeeded = ctx.interiorFrame.checkIfEnlarementIsNeeded(ctx.getTuple(), ctx.cmp);
if (enlarementIsNeeded) {
if (!writeLatched) {
node.releaseReadLatch();
readLatched = false;
bufferCache.unpin(node);
node = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, pageId), false);
node.acquireWriteLatch();
writeLatched = true;
ctx.interiorFrame.setPage(node);
if (ctx.interiorFrame.getPageLsn() != pageLsn) {
// The page was changed while we unlocked it;
// thus, retry (re-choose best child)
ctx.pathList.moveLast();
continue;
}
}
// We don't need to reset the frameTuple because it is
// already pointing to the best child
ctx.interiorFrame.enlarge(ctx.getTuple(), ctx.cmp);
node.releaseWriteLatch(true);
writeLatched = false;
bufferCache.unpin(node);
} else {
if (readLatched) {
node.releaseReadLatch();
readLatched = false;
bufferCache.unpin(node);
} else if (writeLatched) {
node.releaseWriteLatch(true);
writeLatched = false;
bufferCache.unpin(node);
}
}
pageId = childPageId;
parentLsn = pageLsn;
} else {
ctx.leafFrame.setPage(node);
succeeded = true;
return node;
}
}
} finally {
if (!succeeded) {
if (readLatched) {
node.releaseReadLatch();
readLatched = false;
bufferCache.unpin(node);
} else if (writeLatched) {
node.releaseWriteLatch(true);
writeLatched = false;
bufferCache.unpin(node);
}
}
}
}