/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo.map.diskmap.tree; import com.github.geophile.erdo.AbstractKey; import com.github.geophile.erdo.map.diskmap.Manifest; import com.github.geophile.erdo.util.LongArray; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class TreeLevel { // Object interface @Override public String toString() { return String.format("%s/L%s", tree, level); } // TreeLevel interface public int levelNumber() { return level; } public boolean isLeaf() { return level == 0; } public int segments() { return segments.size(); } public TreeSegment segment(int segmentNumber) { return segments.get(segmentNumber); } public boolean leafLevelEmpty() { assert level == 0 : this; return segment(0).summary().keyCount() == 0; } public boolean keyPossiblyPresent(AbstractKey key) { assert level == 0 : this; TreeSegment segment = segmentPossiblyContaining(key); return segment != null && segment.keyPossiblyPresent(key); } public void destroy() { for (TreeSegment segment : segments) { segment.destroy(); } } public static TreeLevel recover(Tree tree, int level, Manifest manifest) throws IOException, InterruptedException { TreeLevel treeLevel = new TreeLevel(tree, level); treeLevel.recover(manifest); return treeLevel; } // For use by this package Tree tree() { return tree; } // For use by subclasses protected TreeSegment lastSegment() { return segments.get(segments.size() - 1); } protected TreeLevel(Tree tree, int level) { this.tree = tree; this.level = level; } // For use by this class private void recover(Manifest manifest) throws IOException, InterruptedException { LongArray segmentIds = manifest.segmentIds(level); for (int s = 0; s < segmentIds.size(); s++) { TreeSegment segment = TreeSegment.recover(this, s, manifest); segments.add(segment); } } private TreeSegment segmentPossiblyContaining(AbstractKey key) { // Adapted from Arrays.binarySearch. Each segment records the last key actually present. The goal is to find // the leftmost segment whose leafLastKey >= key. int lo = 0; int hi = segments.size() - 1; while (lo <= hi) { int mid = (lo + hi) >>> 1; int c = segments.get(mid).leafLastKey().compareTo(key); if (c < 0) { lo = mid + 1; } else if (c > 0) { hi = mid - 1; } else { return segments.get(mid); // key found } } return lo == segments.size() ? null : segments.get(lo); } // Object state protected final Tree tree; protected final int level; protected final List<TreeSegment> segments = new ArrayList<TreeSegment>(); }