@Override public boolean isEmpty() { // could also use (sizeAsLong() == 0) return root.isLeaf() && root.getKeyCount() == 0; }
/** * Add all node keys (including internal bounds) to the given list. * This is mainly used to visualize the internal splits. * * @param list the list * @param p the root page */ public void addNodeKeys(ArrayList<SpatialKey> list, Page p) { if (p != null && !p.isLeaf()) { for (int i = 0; i < p.getKeyCount(); i++) { list.add((SpatialKey) p.getKey(i)); addNodeKeys(list, p.getChildPage(i)); } } }
/** * Split the page. This modifies the current page. * * @param at the split index * @return the page with the entries after the split index */ Page split(int at) { Page page = isLeaf() ? splitLeaf(at) : splitNode(at); if(isPersistent()) { recalculateMemory(); } return page; }
/** * Unlink the children recursively after all data is written. */ void writeEnd() { if (isLeaf()) { return; } int len = children.length; for (int i = 0; i < len; i++) { PageReference ref = children[i]; if (ref.page != null) { if (ref.page.getPos() == 0) { throw DataUtils.newIllegalStateException( DataUtils.ERROR_INTERNAL, "Page not written"); } ref.page.writeEnd(); children[i] = new PageReference(null, ref.pos, ref.count); } } }
/** * Get the value for the given key, or null if not found. * * @param p the page * @param key the key * @return the value or null */ protected Object binarySearch(Page p, Object key) { int x = p.binarySearch(key); if (!p.isLeaf()) { if (x < 0) { x = -x - 1; } else { x++; } p = p.getChildPage(x); return binarySearch(p, key); } if (x >= 0) { return p.getValue(x); } return null; }
private static void move(Page source, Page target, int sourceIndex) { Object k = source.getKey(sourceIndex); if (source.isLeaf()) { Object v = source.getValue(sourceIndex); target.insertLeaf(0, k, v); } else { Page c = source.getChildPage(sourceIndex); target.insertNode(0, k, c); } source.remove(sourceIndex); }
/** * Get the first (lowest) or last (largest) key. * * @param first whether to retrieve the first key * @return the key, or null if the map is empty */ @SuppressWarnings("unchecked") protected K getFirstLast(boolean first) { if (size() == 0) { return null; } Page p = root; while (true) { if (p.isLeaf()) { return (K) p.getKey(first ? 0 : p.getKeyCount() - 1); } p = p.getChildPage(first ? 0 : getChildPageCount(p) - 1); } }
while (true) { int x = p.binarySearch(key); if (p.isLeaf()) { if (x < 0) { return -offset + x;
private void recalculateMemory() { int mem = DataUtils.PAGE_MEMORY; DataType keyType = map.getKeyType(); for (Object key : keys) { mem += keyType.getMemory(key); } if (this.isLeaf()) { DataType valueType = map.getValueType(); for (int i = 0; i < keys.length; i++) { mem += valueType.getMemory(values[i]); } } else { mem += this.getRawChildPageCount() * DataUtils.PAGE_MEMORY_CHILD; } addMemory(mem - memory); }
/** * Fetch the next entry that is equal or larger than the given key, starting * from the given page. This method retains the stack. * * @param p the page to start * @param from the key to search */ private void min(Page p, K from) { while (true) { if (p.isLeaf()) { int x = from == null ? 0 : p.binarySearch(from); if (x < 0) { x = -x - 1; } pos = new CursorPos(p, x, pos); break; } int x = from == null ? -1 : p.binarySearch(from); if (x < 0) { x = -x - 1; } else { x++; } pos = new CursorPos(p, x + 1, pos); p = p.getChildPage(x); } }
long offset = 0; while (true) { if (p.isLeaf()) { if (index >= offset + p.getKeyCount()) { return null;
@SuppressWarnings("unchecked") private K getMinMax(Page p, K key, boolean min, boolean excluding) { if (p.isLeaf()) { int x = p.binarySearch(key); if (x < 0) {
/** * Get the object for the given key. An exact match is required. * * @param p the page * @param key the key * @return the value, or null if not found */ protected Object get(Page p, Object key) { if (!p.isLeaf()) { for (int i = 0; i < p.getKeyCount(); i++) { if (contains(p, i, key)) { Object o = get(p.getChildPage(i), key); if (o != null) { return o; } } } } else { for (int i = 0; i < p.getKeyCount(); i++) { if (keyType.equals(p.getKey(i), key)) { return p.getValue(i); } } } return null; }
/** * Store this page and all children that are changed, in reverse order, and * update the position and the children. * * @param chunk the chunk * @param buff the target buffer */ void writeUnsavedRecursive(Chunk chunk, WriteBuffer buff) { if (pos != 0) { // already stored before return; } int patch = write(chunk, buff); if (!isLeaf()) { int len = children.length; for (int i = 0; i < len; i++) { Page p = children[i].page; if (p != null) { p.writeUnsavedRecursive(chunk, buff); children[i] = new PageReference(p, p.getPos(), p.totalCount); } } int old = buff.position(); buff.position(patch); writeChildren(buff); buff.position(old); } }
while (pos != null) { Page p = pos.page; if (p.isLeaf()) { while (pos.index < p.getKeyCount()) { SpatialKey c = (SpatialKey) p.getKey(pos.index++);
/** * Remove a key-value pair, if the key exists. * * @param key the key (may not be null) * @return the old value if the key existed, or null otherwise */ @Override @SuppressWarnings("unchecked") public V remove(Object key) { beforeWrite(); V result = get(key); if (result == null) { return null; } long v = writeVersion; synchronized (this) { Page p = root.copy(v); result = (V) remove(p, v, key); if (!p.isLeaf() && p.getTotalCount() == 0) { p.removePage(); p = Page.createEmpty(this, p.getVersion()); } newRoot(p); } return result; }
private Page copy(Page source, CursorPos parent) { Page target = Page.create(this, writeVersion, source); if (source.isLeaf()) { Page child = target; for (CursorPos p = parent; p != null; p = p.parent) {
if (p.isLeaf()) { for (int i = 0; i < p.getKeyCount(); i++) { if (keyType.equals(p.getKey(i), key)) {
if (p.isLeaf()) { if (index < 0) { index = -index - 1;