use of org.locationtech.geogig.api.Bucket in project GeoGig by boundlessgeo.
the class PreOrderDiffWalkTest method testSkipBucket.
@Test
public void testSkipBucket() {
// two bucket trees of depth 2
final int size = RevTree.MAX_BUCKETS * RevTree.NORMALIZED_SIZE_LIMIT;
RevTree left = createFeaturesTree(leftSource, "f", size).build();
// all features
RevTree right = createFeaturesTree(rightSource, "f", size, 0, true).build();
// changed
assertDepth(left, leftSource, 2);
assertDepth(right, rightSource, 2);
PreOrderDiffWalk visitor = new PreOrderDiffWalk(left, right, leftSource, rightSource);
final Node lroot = nodeFor(left);
final Node rroot = nodeFor(right);
// consume the root tree
when(consumer.tree(eq(lroot), eq(rroot))).thenReturn(true);
// skip all buckets of depth 0
when(consumer.bucket(anyInt(), eq(0), any(Bucket.class), any(Bucket.class))).thenReturn(false);
visitor.walk(consumer);
verify(consumer, times(1)).tree(eq(lroot), eq(rroot));
verify(consumer, times(32)).bucket(anyInt(), eq(0), any(Bucket.class), any(Bucket.class));
// should not be any call to consumer.features as we skipped all buckets of depth 0 (which
// point to leaf trees)
verify(consumer, times(0)).feature(any(Node.class), any(Node.class));
verify(consumer, times(32)).endBucket(anyInt(), eq(0), any(Bucket.class), any(Bucket.class));
verify(consumer, times(1)).endTree(eq(lroot), eq(rroot));
verifyNoMoreInteractions(consumer);
}
use of org.locationtech.geogig.api.Bucket in project GeoGig by boundlessgeo.
the class DepthSearch method getDirectChild.
/**
* @param parent
* @param directChildName
* @return
*/
public Optional<Node> getDirectChild(RevTree parent, String directChildName, final int subtreesDepth) {
if (parent.isEmpty()) {
return Optional.absent();
}
if (parent.trees().isPresent() || parent.features().isPresent()) {
if (parent.trees().isPresent()) {
ImmutableList<Node> refs = parent.trees().get();
for (int i = 0; i < refs.size(); i++) {
if (directChildName.equals(refs.get(i).getName())) {
return Optional.of(refs.get(i));
}
}
}
if (parent.features().isPresent()) {
ImmutableList<Node> refs = parent.features().get();
for (int i = 0; i < refs.size(); i++) {
if (directChildName.equals(refs.get(i).getName())) {
return Optional.of(refs.get(i));
}
}
}
return Optional.absent();
}
Integer bucket = refOrder.bucket(directChildName, subtreesDepth);
ImmutableSortedMap<Integer, Bucket> buckets = parent.buckets().get();
Bucket subtreeBucket = buckets.get(bucket);
if (subtreeBucket == null) {
return Optional.absent();
}
RevTree subtree = objectDb.get(subtreeBucket.id(), RevTree.class);
return getDirectChild(subtree, directChildName, subtreesDepth + 1);
}
use of org.locationtech.geogig.api.Bucket in project GeoGig by boundlessgeo.
the class FormatCommonV1 method readTree.
public static RevTree readTree(ObjectId id, DataInput in) throws IOException {
final long size = in.readLong();
final int treeCount = in.readInt();
final ImmutableList.Builder<Node> featuresBuilder = new ImmutableList.Builder<Node>();
final ImmutableList.Builder<Node> treesBuilder = new ImmutableList.Builder<Node>();
final SortedMap<Integer, Bucket> buckets = new TreeMap<Integer, Bucket>();
final int nFeatures = in.readInt();
for (int i = 0; i < nFeatures; i++) {
Node n = readNode(in);
if (n.getType() != RevObject.TYPE.FEATURE) {
throw new IllegalStateException("Non-feature node in tree's feature list.");
}
featuresBuilder.add(n);
}
final int nTrees = in.readInt();
for (int i = 0; i < nTrees; i++) {
Node n = readNode(in);
if (n.getType() != RevObject.TYPE.TREE) {
throw new IllegalStateException("Non-tree node in tree's subtree list.");
}
treesBuilder.add(n);
}
final int nBuckets = in.readInt();
for (int i = 0; i < nBuckets; i++) {
int key = in.readInt();
Bucket bucket = readBucket(in);
buckets.put(key, bucket);
}
ImmutableList<Node> trees = treesBuilder.build();
ImmutableList<Node> features = featuresBuilder.build();
if (nTrees == 0 && nFeatures == 0 && nBuckets == 0) {
return RevTree.EMPTY;
} else if (trees.isEmpty() && features.isEmpty()) {
return RevTreeImpl.createNodeTree(id, size, treeCount, buckets);
} else if (buckets.isEmpty()) {
return RevTreeImpl.createLeafTree(id, size, features, trees);
} else {
throw new IllegalArgumentException("Tree has mixed buckets and nodes; this is not supported.");
}
}
use of org.locationtech.geogig.api.Bucket in project GeoGig by boundlessgeo.
the class FormatCommonV2 method writeTree.
public static void writeTree(RevTree tree, DataOutput data) throws IOException {
writeUnsignedVarLong(tree.size(), data);
writeUnsignedVarInt(tree.numTrees(), data);
Envelope envBuff = new Envelope();
final int nFeatures = tree.features().isPresent() ? tree.features().get().size() : 0;
writeUnsignedVarInt(nFeatures, data);
if (nFeatures > 0) {
for (Node feature : tree.features().get()) {
writeNode(feature, data, envBuff);
}
}
final int nTrees = tree.trees().isPresent() ? tree.trees().get().size() : 0;
writeUnsignedVarInt(nTrees, data);
if (nTrees > 0) {
for (Node subTree : tree.trees().get()) {
writeNode(subTree, data, envBuff);
}
}
final int nBuckets = tree.buckets().isPresent() ? tree.buckets().get().size() : 0;
writeUnsignedVarInt(nBuckets, data);
if (tree.buckets().isPresent()) {
ImmutableSortedMap<Integer, Bucket> buckets = tree.buckets().get();
for (Map.Entry<Integer, Bucket> bucket : buckets.entrySet()) {
writeBucket(bucket.getKey(), bucket.getValue(), data, envBuff);
}
}
}
use of org.locationtech.geogig.api.Bucket in project GeoGig by boundlessgeo.
the class PreOrderDiffWalk method traverseLeafBucket.
/**
* Compares a bucket tree (i.e. its size is greater than {@link RevTree#NORMALIZED_SIZE_LIMIT}
* and hence has been split into buckets) at the right side of the comparison, and a the
* {@link RevTree#children() children} nodes of a leaf tree at the left side of the comparison.
* <p>
* This happens when the right tree is much larger than the left tree
* <p>
* This traversal is symmetric to {@link #traverseBucketLeaf} so be careful that any change made
* to this method shall have a matching change at {@link #traverseBucketLeaf}
*
* @precondition {@code right.buckets().isPresent()}
*/
private void traverseLeafBucket(final Consumer consumer, final Iterator<Node> left, final RevTree right, final int bucketDepth) {
checkState(right.buckets().isPresent());
final SortedMap<Integer, Bucket> rightBuckets = right.buckets().get();
final ListMultimap<Integer, Node> nodesByBucket = splitNodesToBucketsAtDepth(left, bucketDepth);
final SortedSet<Integer> bucketIndexes = Sets.newTreeSet(Sets.union(rightBuckets.keySet(), nodesByBucket.keySet()));
// get all buckets at once, to leverage ObjectDatabase optimizations
final Map<ObjectId, RevObject> bucketTrees;
bucketTrees = uniqueIndex(rightSource.getAll(transform(rightBuckets.values(), BUCKET_ID)), OBJECT_ID);
for (Integer bucketIndex : bucketIndexes) {
Bucket rightBucket = rightBuckets.get(bucketIndex);
// never returns null, but empty
List<Node> leftNodes = nodesByBucket.get(bucketIndex);
if (null == rightBucket) {
traverseLeafLeaf(consumer, leftNodes.iterator(), Iterators.<Node>emptyIterator());
} else if (leftNodes.isEmpty()) {
if (consumer.bucket(bucketIndex, bucketDepth, null, rightBucket)) {
RevTree rightTree = (RevTree) bucketTrees.get(rightBucket.id());
// traverseBucketBucket(consumer, RevTree.EMPTY, rightTree, bucketDepth);
traverseTree(consumer, RevTree.EMPTY, rightTree, bucketDepth + 1);
}
consumer.endBucket(bucketIndex, bucketDepth, null, rightBucket);
} else {
RevTree rightTree = (RevTree) bucketTrees.get(rightBucket.id());
if (rightTree.buckets().isPresent()) {
traverseLeafBucket(consumer, leftNodes.iterator(), rightTree, bucketDepth + 1);
} else {
traverseLeafLeaf(consumer, leftNodes.iterator(), rightTree.children());
}
}
}
}
Aggregations