@Override @Nullable public BasePageMutable putRight(@NotNull ByteIterable key, @NotNull ByteIterable value) { final BTreeMutable tree = (BTreeMutable) getTree(); if (size > 0) { final int pos = size - 1; final BaseLeafNode ln = getKey(pos); final int cmp = ln.compareKeyTo(key); if (cmp > 0) { throw new IllegalArgumentException("Key must be greater"); } else if (cmp == 0) { if (tree.allowsDuplicates) { set(pos, LeafNodeDupMutable.convert(ln, tree).putRight(value), null); tree.addExpiredLoggable(ln.getAddress()); return null; } else { throw new IllegalArgumentException("Key must not be equal"); } } } final BasePageMutable page = insertAt(size, tree.createMutableLeaf(key, value), null); tree.incrementSize(); return page; }
@Override @Nullable public BasePageMutable put( @NotNull ByteIterable key, @NotNull ByteIterable value, boolean overwrite, boolean[] result) { final SearchRes res = binarySearch(key); final BTreeMutable tree = (BTreeMutable) getTree(); int pos = res.index; if (pos >= 0) { if (overwrite) { // key found final ILeafNode ln = res.key; if (ln == null) { throw new IllegalStateException("Leaf is expected to be found"); } if (tree.allowsDuplicates) { // overwrite for tree with duplicates means add new value to existing key // manage sub-tree of duplicates // ln may be mutable or immutable, with dups or without LeafNodeDupMutable lnm = LeafNodeDupMutable.convert(ln, tree); if (lnm.put(value)) { tree.addExpiredLoggable(ln.getAddress()); set(pos, lnm, null); result[0] = true; } // main tree size will be auto-incremented with some help from duplicates tree } else { if (!ln.isDupLeaf()) { // TODO: remove this forced update when we no longer need meta tree cloning tree.addExpiredLoggable(keysAddresses[pos]); set(pos, tree.createMutableLeaf(key, value), null); // this should be always true in order to keep up with keysAddresses[pos] expiration result[0] = true; } } } return null; } // if found - insert at this position, else insert after found if (pos < 0) pos = -pos - 1; else pos++; final BasePageMutable page = insertAt(pos, tree.createMutableLeaf(key, value), null); result[0] = true; tree.incrementSize(); return page; }
@Override public boolean delete(@NotNull ByteIterable key, @Nullable ByteIterable value) { final SearchRes sp = binarySearch(key); final int pos = sp.index; if (pos < 0) return false; final BTreeMutable tree = (BTreeMutable) getTree(); if (tree.allowsDuplicates) { final ILeafNode ln = sp.key; if (value == null) { // size will be decreased dramatically, all dup sub-tree will expire tree.addExpiredLoggable(keysAddresses[pos]); LongIterator it = ln.addressIterator(); while (it.hasNext()) tree.addExpiredLoggable(it.next()); copyChildren(pos + 1, pos); tree.decrementSize(ln.getDupCount()); decrementSize(1); return true; } if (ln.isDup()) { LeafNodeDupMutable lnm; boolean res; if (ln.isMutable()) { lnm = (LeafNodeDupMutable) ln; res = lnm.delete(value); } else { LeafNodeDup lnd = (LeafNodeDup) ln; final BTreeDupMutable dupTree = lnd.getTreeCopyMutable(); dupTree.mainTree = tree; if (res = dupTree.delete(value)) { tree.addExpiredLoggable(ln.getAddress()); lnm = LeafNodeDupMutable.convert(ln, tree, dupTree); // remember in page set(pos, lnm, null); } else { return false; } } if (res) { // if only one node left if (lnm.getRootPage().isBottom() && lnm.getRootPage().getSize() == 1) { // expire previous address tree.addExpiredLoggable(keysAddresses[pos]); // expire single duplicate from sub-tree LongIterator it = ln.addressIterator(); tree.addExpiredLoggable(it.next()); // convert back to leaf without duplicates set(pos, tree.createMutableLeaf(lnm.getKey(), lnm.getValue()), null); } return true; } return false; } } tree.addExpiredLoggable(keysAddresses[pos]); copyChildren(pos + 1, pos); tree.decrementSize(1); decrementSize(1); return true; }