in environment/src/main/java/jetbrains/exodus/tree/btree/LeafNodeDup.java [103:184]
public void doReclaim(@NotNull final BTreeReclaimTraverser context, final int leafIndex) {
final long keyAddress = context.currentNode.getKeyAddress(leafIndex);
final BTreeDupMutable tree;
final BaseLeafNodeMutable mutable;
final BTreeMutable mainTree = context.mainTree;
if (keyAddress < 0) {
mutable = ((BasePageMutable) context.currentNode).keys[leafIndex];
if (mutable.isDup()) {
tree = ((LeafNodeDupMutable) mutable).tree;
} else {
return; // current node is duplicate no more
}
} else if (keyAddress == getAddress()) {
final BasePageMutable node = context.currentNode.getMutableCopy(mainTree);
final LeafNodeDupMutable converted = LeafNodeDupMutable.convert(this, mainTree);
mainTree.addExpiredLoggable(keyAddress);
tree = converted.tree;
mutable = converted;
node.set(leafIndex, mutable, null);
context.wasReclaim = true;
context.setPage(node);
} else {
final RandomAccessLoggable upToDate = mainTree.getLoggable(keyAddress);
switch (upToDate.getType()) {
case BTreeBase.LEAF_DUP_BOTTOM_ROOT:
case BTreeBase.LEAF_DUP_INTERNAL_ROOT:
mutable = null; // indicates that loggable was not updated
tree = new LeafNodeDup(mainTree, upToDate).getTreeCopyMutable();
tree.mainTree = mainTree;
break;
case BTreeBase.LEAF:
return; // current node is duplicate no more
default:
throw new ExodusException("Unexpected loggable type " + upToDate.getType());
}
}
// TODO: implement mutable lower bound to avoid allocations (yapavel knows how)
final BTreeReclaimTraverser dupStack = new BTreeReclaimTraverser(tree);
for (final RandomAccessLoggable loggable : context.dupLeafsLo) {
switch (loggable.getType()) {
case BTreeBase.DUP_LEAF:
new LeafNode(log, loggable).reclaim(dupStack);
break;
case BTreeBase.DUP_BOTTOM:
tree.reclaimBottom(loggable, dupStack);
break;
case BTreeBase.DUP_INTERNAL:
tree.reclaimInternal(loggable, dupStack);
break;
default:
throw new ExodusException("Unexpected loggable type " + loggable.getType());
}
}
// TODO: less copy-paste
for (final RandomAccessLoggable loggable : context.dupLeafsHi) {
switch (loggable.getType()) {
case BTreeBase.DUP_LEAF:
new LeafNode(log, loggable).reclaim(dupStack);
break;
case BTreeBase.DUP_BOTTOM:
tree.reclaimBottom(loggable, dupStack);
break;
case BTreeBase.DUP_INTERNAL:
tree.reclaimInternal(loggable, dupStack);
break;
default:
throw new ExodusException("Unexpected loggable type " + loggable.getType());
}
}
while (dupStack.canMoveUp()) {
// wire up mutated stuff
dupStack.popAndMutate();
}
if (dupStack.wasReclaim && mutable == null) { // was reclaim in sub-tree
mainTree.addExpiredLoggable(keyAddress);
final BasePageMutable node = context.currentNode.getMutableCopy(mainTree);
node.set(leafIndex, new LeafNodeDupMutable(tree), null);
context.wasReclaim = true;
context.setPage(node);
}
//TODO: remove? dupStack.clear();
}