private final void internalCheckNode() { if ( BPT.CheckingNode ) checkNode(null, null) ; }
@Override final void checkNodeDeep() { if ( isRoot() ) { // if ( !isLeaf && count == 0 ) // error("Root is of size zero (one pointer) but not a leaf") ; if ( parent != BPlusTreeParams.RootParent ) BPT.error("Root parent is wrong") ; // if ( count == 0 ) // return ; } checkNodeDeep(null, null) ; }
@Override public String toString() { StringBuilder b = new StringBuilder() ; if ( isLeaf ) b.append("LEAF: ") ; else b.append("NODE: ") ; String labelStr = "??" ; if ( parent >= 0 ) labelStr = Integer.toString(parent) ; else if ( parent == BPlusTreeParams.RootParent ) labelStr = "root" ; if ( isLeaf ) labelStr = labelStr + "/leaf" ; b.append(String.format("%d [%s] (size %d) -- ", getId(), labelStr, count)) ; for ( int i = 0 ; i < maxRecords() ; i++ ) { b.append(childStr(i)) ; b.append(" (") ; b.append(recstr(records, i)) ; b.append(") ") ; } b.append(childStr(params.HighPtr)) ; return b.toString() ; }
/** Find the next page to look at as we walk down the tree */ private final BPTreePage findHere(AccessPath path, Record rec) { int idx = findSlot(rec) ; idx = apply(idx) ; // Find index, or insertion point (immediate higher slot) as (-i-1) // A key is the highest element of the records up to this point // so we search down at slot idx (between something smaller and // something larger). BPTreePage page = get(idx) ; trackPath(path, this, idx, page) ; return page ; }
@Override final Record internalSearch(AccessPath path, Record rec) { if ( BPT.CheckingNode ) internalCheckNode() ; BPTreePage page = findHere(path, rec) ; Record r = page.internalSearch(path, rec) ; page.release() ; return r ; }
log(log, "** delete(%s) / start", rec) ; if ( BPT.DumpTree ) root.dump() ; if ( !root.isRoot() ) throw new BPTreeException("Delete begins but this is not the root") ; BPTreePage page = root.get(0) ; if ( BPT.CheckingNode && !(page instanceof BPTreeRecords) ) BPT.error("Zero size leaf root but not pointing to a records block") ; trackPath(path, root, 0, page) ; Record r = page.internalDelete(path, rec) ; page.release() ; if ( r != null ) root.write() ; if ( BPT.DumpTree ) root.dump() ; return r ; Record v = root.internalDelete(path, rec) ; reduceRoot(root) ; root.bpTree.newRoot(root) ; root.internalCheckNodeDeep() ; log(log, "** delete(%s) / finish", rec) ; if ( BPT.DumpTree ) root.dump() ;
if ( logging(log) ) log(log, ">> internalDelete(%s) : %s", rec, this) ; internalCheckNode() ; int x = findSlot(rec) ; int y = apply(x) ; BPTreePage page = get(y) ; trackPath(path, this, y, page) ; rebalance(path, page, y) ; // Ignore return - need to re-find. x = findSlot(rec) ; y = apply(x) ; page = get(y) ; promote1(page, this, y) ; resetTrackPath(path, this, y, page) ; if ( BPT.CheckingNode ) { internalCheckNode() ; page.checkNode() ; this.write() ; records.set(x, keyRecord(mx)) ; this.write() ;
/** Insert a record - return existing value if any, else null */ public static Record insert(BPTreeNode root, Record record) { if ( logging(log) ) { log(log, "** insert(%s) / root=%d", record, root.getId()) ; if ( DumpTree ) root.dump() ; } if ( !root.isRoot() ) throw new BPTreeException("Insert begins but this is not the root") ; if ( root.isFull() ) { // Root full - root split is a special case. splitRoot(root) ; if ( DumpTree ) root.dump() ; } AccessPath path = new AccessPath(root) ; // Root ready - call insert proper. Record result = root.internalInsert(path, record) ; root.internalCheckNodeDeep() ; if ( logging(log) ) { log(log, "** insert(%s) / finish", record) ; if ( DumpTree ) root.dump() ; } return result ; }
if ( ! root.isRoot() ) BPT.error("Not root: %d (root is id zero)", root.getId()) ; root.internalCheckNode() ; promoteRoot(root) ; BPTreeNode left = create(bpTree, root.getId(), root.isLeaf) ; BPTreeNode right = create(bpTree, root.getId(), root.isLeaf) ; root.records.copy(splitIdx + 1, right.records, 0, root.maxRecords() - (splitIdx + 1)) ; root.ptrs.copy(splitIdx + 1, right.ptrs, 0, root.params.MaxPtr - (splitIdx + 1)) ; right.count = root.maxRecords() - (splitIdx + 1) ; root.ptrs.set(0, left.getId()) ; // slot 0 root.ptrs.set(1, right.getId()) ; // slot 1 left.write() ; right.write() ; left.release() ; right.release() ; root.write() ; root.internalCheckNode() ; left.internalCheckNode() ; right.internalCheckNode() ;
log(log, "reduceRoot >> %s", root) ; if ( BPT.CheckingNode && (!root.isRoot() || root.count != 0) ) BPT.error("Not an empty root") ; BPTreePage sub = root.get(0) ; promote1(sub, root, 0) ; BPTreeNode n = cast(sub) ; root.isLeaf = n.isLeaf ; root.count = n.count ; root.write() ; n.free() ; if ( BPT.CheckingNode ) root.internalCheckNodeDeep() ;
log(log, "internalInsert: %s [%s]", record, this) ; internalCheckNode() ; int idx = findSlot(record) ; BPTreePage page = get(idx) ; trackPath(path, this, idx, page) ; split(path, idx, page) ; page = get(idx) ; path.reset(this, idx, page); internalCheckNode() ;
/** Split this block - return the split record (key only needed) */ @Override final BPTreePage split() { // Median record : will go in parent. int ix = params.SplitIndex ; // New block. BPTreeNode z = create(this.parent, isLeaf) ; // Leave the low end untouched and copy, and clear the high end. // z becomes the new upper node, not the lower node. // 'this' is the lower block. int maxRec = maxRecords() ; // Copy from top of y into z. records.copy(ix + 1, z.records, 0, maxRec - (ix + 1)) ; records.clear(ix, maxRec - ix) ; // Clear copied and median slot records.setSize(ix) ; // Reset size ptrs.copy(ix + 1, z.ptrs, 0, params.MaxPtr - (ix + 1)) ; ptrs.clear(ix + 1, params.MaxPtr - (ix + 1)) ; ptrs.setSize(ix + 1) ; // Set sizes of subnodes setCount(ix) ; // Median is ix internalCheckNode() ; // y finished z.isLeaf = isLeaf ; z.setCount(maxRec - (ix + 1)) ; // Number copied into z // Caller puts the blocks in split(int, BTreePage) z.internalCheckNode() ; return z ; }
private void checkNodeDeep(Record min, Record max) { checkNode(min, max) ; int id = getId() ; Record min1 = min ; Record max1 = max ; BPTreePage n = get(i) ; ((BPTreeNode)n).checkNodeDeep(min1, max1) ; n.release() ;
private static BPTreeNode merge(BPTreeNode left, Record splitKey, BPTreeNode right) { // Merge blocks - does not adjust the parent. // Copy right to top of left. // Caller releases 'right' (needed for testing code). left.records.add(splitKey) ; // Copy over right to top of left. right.records.copyToTop(left.records) ; right.ptrs.copyToTop(left.ptrs) ; // Update count left.count = left.count + right.count + 1 ; left.internalCheckNode() ; right.records.clear() ; right.ptrs.clear() ; return left ; }
@Override Record shiftRight(BPTreePage other, Record splitKey) { BPTreeNode node = cast(other) ; if ( BPT.CheckingNode ) { if ( count == 0 ) BPT.error("Node is empty - can't shift a slot out") ; if ( node.isFull() ) BPT.error("Destination node is full") ; } // Records: promote moving element, replace with splitKey Record r = this.records.getHigh() ; this.records.removeTop() ; node.records.add(0, splitKey) ; // Pointers just shift this.ptrs.shiftRight(node.ptrs) ; this.count-- ; node.count++ ; this.internalCheckNode() ; node.internalCheckNode() ; return r ; }
@Override Record shiftLeft(BPTreePage other, Record splitKey) { BPTreeNode node = cast(other) ; if ( BPT.CheckingNode ) { if ( count == 0 ) BPT.error("Node is empty - can't shift a slot out") ; if ( isFull() ) BPT.error("Destination node is full") ; } Record r = node.records.getLow() ; // Records: promote moving element, replace with splitKey this.records.add(splitKey) ; node.records.shiftDown(0) ; // Pointers just shift this.ptrs.shiftLeft(node.ptrs) ; this.count++ ; node.count-- ; return r ; }
public void dump() { boolean b = BPT.Logging ; BPT.Logging = false ; try { dump(IndentedWriter.stdout) ; } finally { BPT.Logging = b ; } }
@Override public void check() { BPTreeNode root = getRootRead() ; try { root.checkNodeDeep() ; } finally { releaseRootRead(root) ; } }
public Record deleteAndReturnOld(Record record) { startUpdateBlkMgr() ; BPTreeNode root = getRootWrite() ; Record r = BPTreeNode.delete(root, record) ; releaseRootWrite(root) ; finishUpdateBlkMgr() ; return r ; }