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");
}
}
}
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;
}
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();
}
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();
}
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);
}
Aggregations