Search in sources :

Example 46 with DiffEntry

use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.

the class AbstractMappedRemoteRepo method fetchSparseCommit.

/**
     * This function takes all of the changes introduced by the specified commit and filters them
     * based on the repository filter. It then uses the filtered results to construct a new commit
     * that is the descendant of commits that the original's parents are mapped to.
     * 
     * @param commitId the commit id of the original, non-sparse commit
     * @param allowEmpty allow the function to create an empty sparse commit
     */
private void fetchSparseCommit(ObjectId commitId, boolean allowEmpty) {
    Optional<RevObject> object = getObject(commitId);
    if (object.isPresent() && object.get().getType().equals(TYPE.COMMIT)) {
        RevCommit commit = (RevCommit) object.get();
        FilteredDiffIterator changes = getFilteredChanges(commit);
        GraphDatabase graphDatabase = localRepository.graphDatabase();
        ObjectDatabase objectDatabase = localRepository.objectDatabase();
        graphDatabase.put(commit.getId(), commit.getParentIds());
        RevTree rootTree = RevTree.EMPTY;
        if (commit.getParentIds().size() > 0) {
            // Map this commit to the last "sparse" commit in my ancestry
            ObjectId mappedCommit = graphDatabase.getMapping(commit.getParentIds().get(0));
            graphDatabase.map(commit.getId(), mappedCommit);
            Optional<ObjectId> treeId = localRepository.command(ResolveTreeish.class).setTreeish(mappedCommit).call();
            if (treeId.isPresent()) {
                rootTree = localRepository.getTree(treeId.get());
            }
        } else {
            graphDatabase.map(commit.getId(), ObjectId.NULL);
        }
        Iterator<DiffEntry> it = Iterators.filter(changes, new Predicate<DiffEntry>() {

            @Override
            public boolean apply(DiffEntry e) {
                return true;
            }
        });
        if (it.hasNext()) {
            // Create new commit
            WriteTree writeTree = localRepository.command(WriteTree.class).setOldRoot(Suppliers.ofInstance(rootTree)).setDiffSupplier(Suppliers.ofInstance((Iterator<DiffEntry>) it));
            if (changes.isAutoIngesting()) {
                // the iterator already ingests objects into the ObjectDatabase
                writeTree.dontMoveObjects();
            }
            ObjectId newTreeId = writeTree.call();
            CommitBuilder builder = new CommitBuilder(commit);
            List<ObjectId> newParents = new LinkedList<ObjectId>();
            for (ObjectId parentCommitId : commit.getParentIds()) {
                newParents.add(graphDatabase.getMapping(parentCommitId));
            }
            builder.setParentIds(newParents);
            builder.setTreeId(newTreeId);
            RevCommit mapped = builder.build();
            objectDatabase.put(mapped);
            if (changes.wasFiltered()) {
                graphDatabase.setProperty(mapped.getId(), GraphDatabase.SPARSE_FLAG, "true");
            }
            graphDatabase.map(mapped.getId(), commit.getId());
            // Replace the old mapping with the new commit Id.
            graphDatabase.map(commit.getId(), mapped.getId());
        } else if (allowEmpty) {
            CommitBuilder builder = new CommitBuilder(commit);
            List<ObjectId> newParents = new LinkedList<ObjectId>();
            for (ObjectId parentCommitId : commit.getParentIds()) {
                newParents.add(graphDatabase.getMapping(parentCommitId));
            }
            builder.setParentIds(newParents);
            builder.setTreeId(rootTree.getId());
            builder.setMessage(PLACEHOLDER_COMMIT_MESSAGE);
            RevCommit mapped = builder.build();
            objectDatabase.put(mapped);
            graphDatabase.setProperty(mapped.getId(), GraphDatabase.SPARSE_FLAG, "true");
            graphDatabase.map(mapped.getId(), commit.getId());
            // Replace the old mapping with the new commit Id.
            graphDatabase.map(commit.getId(), mapped.getId());
        } else {
            // Mark the mapped commit as sparse, since it wont have these changes
            graphDatabase.setProperty(graphDatabase.getMapping(commit.getId()), GraphDatabase.SPARSE_FLAG, "true");
        }
    }
}
Also used : WriteTree(org.locationtech.geogig.api.plumbing.WriteTree) RevObject(org.locationtech.geogig.api.RevObject) GraphDatabase(org.locationtech.geogig.storage.GraphDatabase) ObjectId(org.locationtech.geogig.api.ObjectId) CommitBuilder(org.locationtech.geogig.api.CommitBuilder) LinkedList(java.util.LinkedList) ObjectDatabase(org.locationtech.geogig.storage.ObjectDatabase) Iterator(java.util.Iterator) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) List(java.util.List) RevTree(org.locationtech.geogig.api.RevTree) RevCommit(org.locationtech.geogig.api.RevCommit) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry)

Example 47 with DiffEntry

use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.

the class BinaryPackedChanges method write.

/**
     * Writes the set of changes to the provided output stream.
     * 
     * @param out the stream to write to
     * @param changes the changes to write
     * @throws IOException
     * @return the number of objects written
     */
public long write(OutputStream out, Iterator<DiffEntry> changes) throws IOException {
    final ObjectDatabase objectDatabase = repository.objectDatabase();
    out = new CountingOutputStream(out);
    // avoids sending the same metadata object multiple times
    Set<ObjectId> writtenMetadataIds = new HashSet<ObjectId>();
    // buffer to avoid ObjectId cloning its internal state for each object
    byte[] oidbuffer = new byte[ObjectId.NUM_BYTES];
    long objectCount = 0;
    while (changes.hasNext()) {
        DiffEntry diff = changes.next();
        if (diff.isDelete()) {
            out.write(CHUNK_TYPE.DIFF_ENTRY.value());
        } else {
            // its a change or an addition, new object is guaranteed to be present
            NodeRef newObject = diff.getNewObject();
            ObjectId metadataId = newObject.getMetadataId();
            if (writtenMetadataIds.contains(metadataId)) {
                out.write(CHUNK_TYPE.OBJECT_AND_DIFF_ENTRY.value());
            } else {
                out.write(CHUNK_TYPE.METADATA_OBJECT_AND_DIFF_ENTRY.value());
                RevObject metadata = objectDatabase.get(metadataId);
                writeObjectId(metadataId, out, oidbuffer);
                serializer.createObjectWriter(metadata.getType()).write(metadata, out);
                writtenMetadataIds.add(metadataId);
                objectCount++;
            }
            ObjectId objectId = newObject.objectId();
            writeObjectId(objectId, out, oidbuffer);
            RevObject object = objectDatabase.get(objectId);
            serializer.createObjectWriter(object.getType()).write(object, out);
            objectCount++;
        }
        DataOutput dataOut = new DataOutputStream(out);
        FormatCommonV1.writeDiff(diff, dataOut);
    }
    // signal the end of changes
    out.write(CHUNK_TYPE.FILTER_FLAG.value());
    final boolean filtersApplied = changes instanceof FilteredDiffIterator && ((FilteredDiffIterator) changes).wasFiltered();
    out.write(filtersApplied ? 1 : 0);
    LOGGER.info(String.format("Written %,d bytes to remote accounting for %,d objects.", ((CountingOutputStream) out).getCount(), objectCount));
    return objectCount;
}
Also used : DataOutput(java.io.DataOutput) ObjectId(org.locationtech.geogig.api.ObjectId) FormatCommonV1.readObjectId(org.locationtech.geogig.storage.datastream.FormatCommonV1.readObjectId) RevObject(org.locationtech.geogig.api.RevObject) DataOutputStream(java.io.DataOutputStream) NodeRef(org.locationtech.geogig.api.NodeRef) CountingOutputStream(com.google.common.io.CountingOutputStream) ObjectDatabase(org.locationtech.geogig.storage.ObjectDatabase) HashSet(java.util.HashSet) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry)

Example 48 with DiffEntry

use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.

the class Index method stage.

/**
     * Stages the changes indicated by the {@link DiffEntry} iterator.
     * 
     * @param progress the progress listener for the process
     * @param unstaged an iterator for the unstaged changes
     * @param numChanges number of unstaged changes
     */
@Override
public void stage(final ProgressListener progress, final Iterator<DiffEntry> unstaged, final long numChanges) {
    int i = 0;
    progress.started();
    final RevTree currentIndexHead = getTree();
    Map<String, RevTreeBuilder> parentTress = Maps.newHashMap();
    Map<String, ObjectId> parentMetadataIds = Maps.newHashMap();
    Set<String> removedTrees = Sets.newHashSet();
    StagingDatabase database = getDatabase();
    while (unstaged.hasNext()) {
        final DiffEntry diff = unstaged.next();
        final String fullPath = diff.oldPath() == null ? diff.newPath() : diff.oldPath();
        final String parentPath = NodeRef.parentPath(fullPath);
        /*
             * TODO: revisit, ideally the list of diff entries would come with one single entry for
             * the whole removed tree instead of that one and every single children of it.
             */
        if (removedTrees.contains(parentPath)) {
            continue;
        }
        if (null == parentPath) {
            // it is the root tree that's been changed, update head and ignore anything else
            ObjectId newRoot = diff.newObjectId();
            updateStageHead(newRoot);
            progress.setProgress(100f);
            progress.complete();
            return;
        }
        RevTreeBuilder parentTree = getParentTree(currentIndexHead, parentPath, parentTress, parentMetadataIds);
        i++;
        progress.setProgress((float) (i * 100) / numChanges);
        NodeRef oldObject = diff.getOldObject();
        NodeRef newObject = diff.getNewObject();
        if (newObject == null) {
            // Delete
            parentTree.remove(oldObject.name());
            if (TYPE.TREE.equals(oldObject.getType())) {
                removedTrees.add(oldObject.path());
            }
        } else if (oldObject == null) {
            // Add
            Node node = newObject.getNode();
            parentTree.put(node);
            parentMetadataIds.put(newObject.path(), newObject.getMetadataId());
        } else {
            // Modify
            Node node = newObject.getNode();
            parentTree.put(node);
        }
        database.removeConflict(null, fullPath);
    }
    ObjectId newRootTree = currentIndexHead.getId();
    for (Map.Entry<String, RevTreeBuilder> entry : parentTress.entrySet()) {
        String changedTreePath = entry.getKey();
        RevTreeBuilder changedTreeBuilder = entry.getValue();
        RevTree changedTree = changedTreeBuilder.build();
        ObjectId parentMetadataId = parentMetadataIds.get(changedTreePath);
        if (NodeRef.ROOT.equals(changedTreePath)) {
            // root
            database.put(changedTree);
            newRootTree = changedTree.getId();
        } else {
            // parentMetadataId = parentMetadataId == null ?
            Supplier<RevTreeBuilder> rootTreeSupplier = getTreeSupplier();
            newRootTree = context.command(WriteBack.class).setAncestor(rootTreeSupplier).setChildPath(changedTreePath).setMetadataId(parentMetadataId).setToIndex(true).setTree(changedTree).call();
        }
        updateStageHead(newRootTree);
    }
    progress.complete();
}
Also used : ObjectId(org.locationtech.geogig.api.ObjectId) Node(org.locationtech.geogig.api.Node) RevTreeBuilder(org.locationtech.geogig.api.RevTreeBuilder) WriteBack(org.locationtech.geogig.api.plumbing.WriteBack) NodeRef(org.locationtech.geogig.api.NodeRef) Map(java.util.Map) RevTree(org.locationtech.geogig.api.RevTree) StagingDatabase(org.locationtech.geogig.storage.StagingDatabase) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry)

Example 49 with DiffEntry

use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.

the class LocalCopyingDiffIterator method computeNext.

/**
     * @return the next {@link DiffEntry}
     */
protected DiffEntry computeNext() {
    if (source.hasNext()) {
        DiffEntry next = source.next();
        if (next.getNewObject() != null) {
            NodeRef newObject = next.getNewObject();
            RevObject object = sourceRepo.command(RevObjectParse.class).setObjectId(newObject.getNode().getObjectId()).call().get();
            RevObject metadata = null;
            if (newObject.getMetadataId() != ObjectId.NULL) {
                metadata = sourceRepo.command(RevObjectParse.class).setObjectId(newObject.getMetadataId()).call().get();
            }
            if (!destinationRepo.blobExists(object.getId())) {
                destinationRepo.objectDatabase().put(object);
            }
            if (metadata != null && !destinationRepo.blobExists(metadata.getId())) {
                destinationRepo.objectDatabase().put(metadata);
            }
        }
        return next;
    }
    return endOfData();
}
Also used : NodeRef(org.locationtech.geogig.api.NodeRef) RevObject(org.locationtech.geogig.api.RevObject) RevObjectParse(org.locationtech.geogig.api.plumbing.RevObjectParse) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry)

Example 50 with DiffEntry

use of org.locationtech.geogig.api.plumbing.diff.DiffEntry in project GeoGig by boundlessgeo.

the class LocalMappedRemoteRepo method getFilteredChanges.

/**
     * Gets all of the changes from the target commit that should be applied to the sparse clone.
     * 
     * @param commit the commit to get changes from
     * @return an iterator for changes that match the repository filter
     */
@Override
protected FilteredDiffIterator getFilteredChanges(RevCommit commit) {
    ObjectId parent = ObjectId.NULL;
    if (commit.getParentIds().size() > 0) {
        parent = commit.getParentIds().get(0);
    }
    Iterator<DiffEntry> changes = remoteGeoGig.command(DiffOp.class).setNewVersion(commit.getId()).setOldVersion(parent).setReportTrees(true).call();
    return new LocalFilteredDiffIterator(changes, remoteGeoGig.getRepository(), localRepository, filter);
}
Also used : ObjectId(org.locationtech.geogig.api.ObjectId) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry)

Aggregations

DiffEntry (org.locationtech.geogig.api.plumbing.diff.DiffEntry)83 ObjectId (org.locationtech.geogig.api.ObjectId)38 Test (org.junit.Test)31 RevCommit (org.locationtech.geogig.api.RevCommit)31 NodeRef (org.locationtech.geogig.api.NodeRef)24 DiffOp (org.locationtech.geogig.api.porcelain.DiffOp)17 RevFeature (org.locationtech.geogig.api.RevFeature)15 RevTree (org.locationtech.geogig.api.RevTree)15 RevFeatureType (org.locationtech.geogig.api.RevFeatureType)14 RevObjectParse (org.locationtech.geogig.api.plumbing.RevObjectParse)14 RevObject (org.locationtech.geogig.api.RevObject)11 Patch (org.locationtech.geogig.api.plumbing.diff.Patch)11 Feature (org.opengis.feature.Feature)10 Optional (com.google.common.base.Optional)9 GeoGIG (org.locationtech.geogig.api.GeoGIG)8 Repository (org.locationtech.geogig.repository.Repository)8 ObjectDatabase (org.locationtech.geogig.storage.ObjectDatabase)8 PropertyDescriptor (org.opengis.feature.type.PropertyDescriptor)8 SimpleFeature (org.opengis.feature.simple.SimpleFeature)7 IOException (java.io.IOException)5