private void afterRemoveProcessing() { if (root instanceof InnerNode && root.getLength() == 0) { InnerNode<K, V> inner = (InnerNode<K, V>) root; this.root = inner.getFirstChild(); } this.size--; }
/** * Remove an element from the right digit. * * @param pos position inside the right digit * @return resulting tree */ private FingerTree<N, E> removeRight(final long pos) { if (right.length > 1) { // right digit cannot underflow, just delete the element return new DeepTree<>(left, leftSize, middle, remove(right, pos), size - 1); } // singleton digit might underflow final Node<N, E> node = right[0]; if (!middle.isEmpty()) { // potentially balance with middle tree final InnerNode<N, E> last = (InnerNode<N, E>) middle.last(); final Node<N, E> lastSub = last.getSub(last.arity() - 1); final NodeLike<N, E>[] rem = node.remove(lastSub, null, pos); final Node<N, E> newLastSub = (Node<N, E>) rem[0], newNode = (Node<N, E>) rem[1]; if (newNode == null) { // nodes were merged final Node<N, E>[] newRight = last.children.clone(); newRight[newRight.length - 1] = newLastSub; return new DeepTree<>(left, leftSize, middle.init(), newRight, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newNode}; // replace last node in middle tree final Node<Node<N, E>, E> newLast = last.replaceLast(newLastSub); return new DeepTree<>(left, leftSize, middle.replaceLast(newLast), newRight, size - 1); } // balance with left digit final Node<N, E> lastLeft = left[left.length - 1]; final NodeLike<N, E>[] rem = node.remove(lastLeft, null, pos); final Node<N, E> newLastLeft = (Node<N, E>) rem[0], newNode = (Node<N, E>) rem[1]; if (newNode == null) { // nodes were merged if (left.length == 1) { // only one node left return new SingletonTree<>(newLastLeft); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newLastLeft}; return get(slice(left, 0, left.length - 1), newRight, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newNode}; if (newLastLeft == lastLeft) { // deletion could be absorbed return get(left, leftSize, newRight, size - 1); } // adapt the left digit final Node<N, E>[] newLeft = left.clone(); newLeft[newLeft.length - 1] = newLastLeft; return get(newLeft, newRight, size - 1); }
@Override public FingerTree<N, E> tail() { final long fstSize = left[0].size(), newSize = size - fstSize; if (left.length > 1) { // left digit is safe, just shrink it final Node<N, E>[] newLeft = slice(left, 1, left.length); return new DeepTree<>(newLeft, leftSize - fstSize, middle, right, newSize); } if (middle.isEmpty()) { // middle tree empty, make a tree from the right list if (right.length == 1) return new SingletonTree<>(right[0]); final int mid = right.length / 2; return get(slice(right, 0, mid), slice(right, mid, right.length), newSize); } // extract values for the left digit from the middle final InnerNode<N, E> head = (InnerNode<N, E>) middle.head(); return new DeepTree<>(head.children, head.size(), middle.tail(), right, newSize); }
public boolean colocate(LocatedKey treeKey) { List<InnerNode>[] allRoots = new List[this.keys.length]; sleep(); int cutoff = tree.getCutoff(true, tree.cutoffKey); BPlusTree.wrapper.startTransaction(false); tree.applyCutoff(treeKey, cutoff); BPlusTree.wrapper.endTransaction(true); boolean successful = false; while (!successful) { try { BPlusTree.wrapper.startTransaction(false); int i = 0; int s = 0; List<InnerNode> source = null; for (LocatedKey lrKey : this.keys) { allRoots[i] = BPlusTree.getLocalRoots(lrKey); if (allRoots[i] != null && allRoots[i].size() > 0) { source = allRoots[i]; s = i; System.out.println("Found source for local roots with length: " + source.size()); } i++; } int members = allRoots.length; int localRoots = source.size(); int division = (int) Math.floor((localRoots + 0.0) / (members + 0.0)); if (division == 0) { BPlusTree.wrapper.endTransaction(true); System.out.println("Division is zero, not co-locating! Had members: " + members); return false; } int groupFrom = s; int groupTo = -1; InnerNode toMove = null; source = new ArrayList<InnerNode>(source); for (int k = 0; k < allRoots.length; k++) { if (k == s) { continue; } List<InnerNode> otherRoots = allRoots[k]; if (otherRoots == null) { otherRoots = new ArrayList<InnerNode>(); } else { otherRoots = new ArrayList<InnerNode>(otherRoots); } groupTo = k; for (int l = 0; l < division; l++) { toMove = source.remove(source.size() - 1); toMove = toMove.startChangeGroup(this.keys[k].getGroup()); otherRoots.add(toMove); BPlusTree.wrapper.endTransaction(true); System.out.println( "Async ColocationThread moved Root " + toMove + " from " + this.keys[groupFrom].getGroup() + " to " + this.keys[groupTo].getGroup()); BPlusTree.wrapper.startTransaction(false); } BPlusTree.setLocalRoots(this.keys[k], otherRoots); } BPlusTree.setLocalRoots(this.keys[s], source); BPlusTree.wrapper.endTransaction(true); successful = true; } catch (Exception e) { e.printStackTrace(); System.out.println("Colocation should not have exceptions"); System.exit(-1); // try { BPlusTree.wrapper.endTransaction(false); } // catch (Exception e2) { // // } // sleep(); } } return false; }
@Override public TreeSlice<N, E> slice(final long from, final long len) { if (from == 0 && len == size) return new TreeSlice<>(this); final long midSize = middle.size(), rightOff = leftSize + midSize; final long inLeft = from + len <= leftSize ? len : from < leftSize ? leftSize - from : 0; final long inRight = from >= rightOff ? len : from + len > rightOff ? from + len - rightOff : 0; @SuppressWarnings("unchecked") final NodeLike<N, E>[] buffer = new NodeLike[2 * MAX_DIGIT + 1]; int inBuffer = splitDigit(left, from, inLeft, buffer, 0); if (inLeft == len) { if (inBuffer == 1) return new TreeSlice<>(buffer[0]); final int mid1 = inBuffer / 2; final Node<N, E>[] ls = slice(buffer, 0, mid1), rs = slice(buffer, mid1, inBuffer); return new TreeSlice<>(get(ls, rs, len)); } final long inMiddle = len - inLeft - inRight; final FingerTree<Node<N, E>, E> mid; final TreeSlice<Node<N, E>, E> slice; if (inMiddle == 0) { mid = EmptyTree.getInstance(); slice = new TreeSlice<>(mid); } else { final long midOff = from <= leftSize ? 0 : from - leftSize; slice = middle.slice(midOff, inMiddle); if (slice.isTree()) { mid = slice.getTree(); } else { final NodeLike<N, E> sub = ((PartialInnerNode<N, E>) slice.getPartial()).sub; inBuffer = sub.append(buffer, inBuffer); mid = EmptyTree.getInstance(); } } final long rightFrom = from < rightOff ? 0 : from - rightOff; if (mid.isEmpty()) { inBuffer = splitDigit(right, rightFrom, inRight, buffer, inBuffer); return slice.setNodes(buffer, inBuffer, len); } final FingerTree<Node<N, E>, E> mid2; if (inBuffer > 1 || buffer[0] instanceof Node) { mid2 = mid; } else { final InnerNode<N, E> head = (InnerNode<N, E>) mid.head(); final int k = head.arity(); inBuffer = head.getSub(0).append(buffer, inBuffer); for (int i = 1; i < k; i++) buffer[inBuffer++] = head.getSub(i); mid2 = mid.tail(); } if (mid2.isEmpty()) { inBuffer = splitDigit(right, rightFrom, inRight, buffer, inBuffer); return slice.setNodes(buffer, inBuffer, len); } final Node<N, E>[] newLeft = slice(buffer, 0, inBuffer); inBuffer = splitDigit(right, rightFrom, inRight, buffer, 0); final FingerTree<Node<N, E>, E> mid3; final Node<N, E>[] newRight; if (inBuffer == 0) { mid3 = mid2.init(); newRight = ((InnerNode<N, E>) mid2.last()).children; } else if (inBuffer > 1 || buffer[0] instanceof Node) { mid3 = mid2; newRight = slice(buffer, 0, inBuffer); } else { final NodeLike<N, E> partial = buffer[0]; final InnerNode<N, E> last = (InnerNode<N, E>) mid2.last(); final int k = last.arity(); for (int i = 0; i < k; i++) buffer[i] = last.getSub(i); inBuffer = partial.append(buffer, k); mid3 = mid2.init(); newRight = slice(buffer, 0, inBuffer); } return slice.setTree(get(newLeft, mid3, newRight, len)); }
/** * Remove an element from the left digit. * * @param pos position inside the left digit * @return resulting tree */ private FingerTree<N, E> removeLeft(final long pos) { if (left.length > 1) { // left digit cannot underflow, just delete the element return new DeepTree<>(remove(left, pos), leftSize - 1, middle, right, size - 1); } // singleton digit might underflow final Node<N, E> node = left[0]; if (!middle.isEmpty()) { // next node for balancing is in middle tree final InnerNode<N, E> head = (InnerNode<N, E>) middle.head(); final Node<N, E> first = head.getSub(0); final NodeLike<N, E>[] rem = node.remove(null, first, pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirst = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged final Node<N, E>[] newLeft = head.children.clone(); newLeft[0] = newFirst; return get(newLeft, middle.tail(), right, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirst != first) { // nodes were balanced final FingerTree<Node<N, E>, E> newMid = middle.replaceHead(head.replaceFirst(newFirst)); return new DeepTree<>(newLeft, newNode.size(), newMid, right, size - 1); } // no changes to this tree's structure return new DeepTree<>(newLeft, newNode.size(), middle, right, size - 1); } // potentially balance with right digit final NodeLike<N, E>[] rem = node.remove(null, right[0], pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirstRight = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged if (right.length == 1) return new SingletonTree<>(newFirstRight); final int mid = right.length / 2; final Node<N, E>[] newLeft = slice(right, 0, mid); newLeft[0] = newFirstRight; return get(newLeft, middle, slice(right, mid, right.length), size - 1); } // structure does not change @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirstRight == right[0]) { // right digit stays the same return new DeepTree<>(newLeft, newLeft[0].size(), middle, right, size - 1); } // adapt the right digit final Node<N, E>[] newRight = right.clone(); newRight[0] = newFirstRight; return new DeepTree<>(newLeft, newNode.size(), middle, newRight, size - 1); }