/** * @return a new instance of a properly "named" empty tree (as in with a proper object id after * applying {@link HashObject}) */ public static RevTree empty() { RevTree theEmptyTree = new LegacyTreeBuilder().build(); return theEmptyTree; }
RevTree tree; final int numPendingChanges = numPendingChanges(); if (bucketTreesByBucket.isEmpty() && numPendingChanges <= CanonicalNodeNameOrder.normalizedSizeLimit(this.depth)) { tree = normalizeToChildren(); } else { tree = normalizeToBuckets(); checkState(featureChanges.isEmpty()); checkState(treeChanges.isEmpty()); this.bucketTreesByBucket.clear(); if (!tree.buckets().isEmpty()) { tree = moveBucketsToChildren(tree); checkPendingWrites();
private Optional<Node> getInternal(final String key, final boolean deep) { Node found = featureChanges.get(key); if (found == null) { found = treeChanges.get(key); } if (found != null) { return Optional.of(found); } if (!deep) { return Optional.absent(); } if (deletes.contains(key)) { return Optional.absent(); } final Integer bucketIndex = computeBucket(key); final Bucket bucket = bucketTreesByBucket.get(bucketIndex); if (bucket == null) { return Optional.absent(); } RevTree subtree = loadTree(bucket.getObjectId()); DepthSearch depthSearch = new DepthSearch(obStore); Optional<Node> node = depthSearch.getDirectChild(subtree, key, depth + 1); if (node.isPresent()) { return Optional.of(node.get()); } else { return Optional.absent(); } }
/** * */ private RevTree normalizeToChildren() { Preconditions.checkState(this.bucketTreesByBucket.isEmpty()); // remove delete requests, we're building a leaf tree out of our nodes deletes.clear(); long size = featureChanges.size(); if (!treeChanges.isEmpty()) { for (Node node : treeChanges.values()) { size += sizeOf(node); } } Collection<Node> features = featureChanges.values(); Collection<Node> trees = treeChanges.values(); RevTree tree = createLeafTree(size, features, trees); return tree; }
Multimap<Integer, Node> changesByBucket = getChangesByBucket(); Preconditions.checkState(featureChanges.isEmpty()); Preconditions.checkState(treeChanges.isEmpty()); final Map<Integer, RevTree> bucketTrees = getBucketTrees(changedBucketIndexes); List<RevTree> newLeafTreesToSave = Lists.newArrayList(); final RevTree currentBucketTree = bucketTrees.get(bucketIndex); final int bucketDepth = this.depth + 1; final LegacyTreeBuilder bucketTreeBuilder = new LegacyTreeBuilder(this.obStore, currentBucketTree, bucketDepth, this.pendingWritesCache, this.normalizationThreshold); for (Node node : bucketEntries) { if (node.getObjectId().isNull()) { bucketTreeBuilder.remove(node.getName()); } else { bucketTreeBuilder.put(node); final RevTree modifiedBucketTree = bucketTreeBuilder.build(); final long bucketSizeDelta = modifiedBucketTree.size() - currentBucketTree.size(); final int bucketTreesDelta = modifiedBucketTree.numTrees() checkPendingWrites(); checkPendingWrites(); RevTree tree = createNodeTree(accSize, accChildTreeCount, this.bucketTreesByBucket); return tree;
@Test public void bucketDAGShrinksOnRemoveBellowThreshold() { final List<Node> nodes = featureNodes(0, 513, false); final List<Node> removeNodes = nodes.subList(100, 500); final RevTree original; { LegacyTreeBuilder legacyBuilder = new LegacyTreeBuilder(store); for (Node n : nodes) { legacyBuilder.put(n); } original = legacyBuilder.build(); } // original = manuallyCreateBucketsTree(); store.put(original); strategy = canonical.original(original).build(); Stopwatch sw = Stopwatch.createStarted(); for (Node node : removeNodes) { strategy.remove(node); } System.err.printf("Removed %,d nodes in %s\n", removeNodes.size(), sw.stop()); DAG root = strategy.buildRoot(); assertFalse(children(root).isEmpty()); assertTrue(buckets(root).isEmpty()); // assertEquals(1, strategy.depth()); List<NodeId> flattenedNodes = flatten(root); assertEquals(nodes.size() - removeNodes.size(), flattenedNodes.size()); assertTrue(buckets(root).isEmpty()); assertFalse(children(root).isEmpty()); assertEquals(nodes.size() - removeNodes.size(), children(root).size()); }
/** * @param tree * @return */ private RevTree moveBucketsToChildren(RevTree tree) { checkState(!tree.buckets().isEmpty()); checkState(this.bucketTreesByBucket.isEmpty()); for (Bucket bucket : tree.buckets().values()) { ObjectId id = bucket.getObjectId(); RevTree bucketTree = this.loadTree(id); if (!bucketTree.buckets().isEmpty()) { moveBucketsToChildren(bucketTree); } else { Iterator<Node> children = RevObjects.children(bucketTree, CanonicalNodeOrder.INSTANCE); while (children.hasNext()) { Node next = children.next(); putInternal(next); } } } return normalizeToChildren(); }
@SuppressWarnings("deprecation") @Override protected RevTreeBuilder createBuiler() { return new LegacyTreeBuilder(objectStore); }
/** * @return the bucket tree or {@link RevTree#EMPTY} if this tree does not have a bucket for the * given bucket index */ private RevTree getBucketTree(Integer bucketIndex) { final Bucket bucket = bucketTreesByBucket.get(bucketIndex); if (bucket == null) { return RevTree.EMPTY; } else { return loadTree(bucket.getObjectId()); } }
/** * Gets an entry by key, this is potentially slow. * * @param key * @return */ public Optional<Node> get(final String key) { return getInternal(key, true); }
@Override public @Nullable RevTree build(BooleanSupplier abortFlag) { return build(); } }
private Multimap<Integer, Node> getChangesByBucket() { Multimap<Integer, Node> changesByBucket = ArrayListMultimap.create(); if (!featureChanges.isEmpty()) { for (Node change : featureChanges.values()) { Integer bucketIndex = computeBucket(change.getName()); changesByBucket.put(bucketIndex, change); } featureChanges.clear(); } if (!treeChanges.isEmpty()) { for (Node change : treeChanges.values()) { Integer bucketIndex = computeBucket(change.getName()); changesByBucket.put(bucketIndex, change); } treeChanges.clear(); } if (!deletes.isEmpty()) { for (String delete : deletes) { Integer bucketIndex = computeBucket(delete); Node node = Node.create(delete, ObjectId.NULL, ObjectId.NULL, TYPE.FEATURE, null); changesByBucket.put(bucketIndex, node); } deletes.clear(); } return changesByBucket; }
Multimap<Integer, Node> changesByBucket = getChangesByBucket(); Preconditions.checkState(featureChanges.isEmpty()); Preconditions.checkState(treeChanges.isEmpty()); final Map<Integer, RevTree> bucketTrees = getBucketTrees(changedBucketIndexes); List<RevTree> newLeafTreesToSave = Lists.newArrayList(); final RevTree currentBucketTree = bucketTrees.get(bucketIndex); final int bucketDepth = this.depth + 1; final LegacyTreeBuilder bucketTreeBuilder = new LegacyTreeBuilder(this.obStore, currentBucketTree, bucketDepth, this.pendingWritesCache, this.normalizationThreshold); for (Node node : bucketEntries) { if (node.getObjectId().isNull()) { bucketTreeBuilder.remove(node.getName()); } else { bucketTreeBuilder.put(node); final RevTree modifiedBucketTree = bucketTreeBuilder.build(); final long bucketSizeDelta = modifiedBucketTree.size() - currentBucketTree.size(); final int bucketTreesDelta = modifiedBucketTree.numTrees() checkPendingWrites(); checkPendingWrites(); RevTree tree = createNodeTree(accSize, accChildTreeCount, this.bucketTreesByBucket); return tree;
final RevTree original; LegacyTreeBuilder legacyBuilder = new LegacyTreeBuilder(store); for (Node n : nodes) { legacyBuilder.put(n); original = legacyBuilder.build();
/** * @param tree * @return */ private RevTree moveBucketsToChildren(RevTree tree) { checkState(!tree.buckets().isEmpty()); checkState(this.bucketTreesByBucket.isEmpty()); for (Bucket bucket : tree.buckets().values()) { ObjectId id = bucket.getObjectId(); RevTree bucketTree = this.loadTree(id); if (!bucketTree.buckets().isEmpty()) { moveBucketsToChildren(bucketTree); } else { Iterator<Node> children = RevObjects.children(bucketTree, CanonicalNodeOrder.INSTANCE); while (children.hasNext()) { Node next = children.next(); putInternal(next); } } } return normalizeToChildren(); }
/** * */ private RevTree normalizeToChildren() { Preconditions.checkState(this.bucketTreesByBucket.isEmpty()); // remove delete requests, we're building a leaf tree out of our nodes deletes.clear(); long size = featureChanges.size(); if (!treeChanges.isEmpty()) { for (Node node : treeChanges.values()) { size += sizeOf(node); } } Collection<Node> features = featureChanges.values(); Collection<Node> trees = treeChanges.values(); RevTree tree = createLeafTree(size, features, trees); return tree; }