Skip to content

Commit

Permalink
Implement fast-path for single-commit push
Browse files Browse the repository at this point in the history
  • Loading branch information
justinsb committed Jun 16, 2016
1 parent 48cb5ff commit 9db165e
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
Expand Up @@ -97,6 +97,8 @@
import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.BitmapObject;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
Expand All @@ -119,6 +121,7 @@
import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.ObjectCountCallback;
import org.eclipse.jgit.transport.WriteAbortedException;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.TemporaryBuffer;

Expand Down Expand Up @@ -270,6 +273,8 @@ public static Iterable<PackWriter> getInstances() {

private boolean useBitmaps;

private boolean useFastSingleCommit;

private boolean ignoreMissingUninteresting = true;

private boolean pruneCurrentObjectList;
Expand Down Expand Up @@ -509,6 +514,19 @@ public void setUseBitmaps(boolean useBitmaps) {
this.useBitmaps = useBitmaps;
}

/** @return true to switch to a fast-path for single commits. */
public boolean isUseFastSingleCommit() {
return useFastSingleCommit;
}

/**
* @param useFastSingleCommit
* if set to true, a fast-path will be used for single commits.
*/
public void setUseFastSingleCommit(boolean useFastSingleCommit) {
this.useFastSingleCommit = useFastSingleCommit;
}

/** @return true if the index file cannot be created by this PackWriter. */
public boolean isIndexDisabled() {
return indexDisabled || !cachedPacks.isEmpty();
Expand Down Expand Up @@ -1631,6 +1649,12 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
}
}

if (useFastSingleCommit && findObjectsToPackOneCommit(walker, want, have)) {
endPhase(countingMonitor);
stats.timeCounting = System.currentTimeMillis() - countingStart;
return;
}

List<ObjectId> all = new ArrayList<ObjectId>(want.size() + have.size());
all.addAll(want);
all.addAll(have);
Expand Down Expand Up @@ -1807,6 +1831,89 @@ private void findObjectsToPack(@NonNull ProgressMonitor countingMonitor,
stats.bitmapIndexMisses = -1;
}

private boolean findObjectsToPackOneCommit(
@NonNull ObjectWalk walker,
@NonNull Set<? extends ObjectId> wants,
@NonNull Set<? extends ObjectId> have) throws MissingObjectException, IncorrectObjectTypeException, IOException {
if (wants.size() != 1) {
return false;
}
ObjectId want = wants.iterator().next();
RevCommit commit = walker.parseCommit(want);
RevCommit[] parents = commit.getParents();
if (parents.length != 1) {
return false;
}
RevCommit parent = parents[0];
if (!have.contains(parent)) {
return false;
}

addObject(commit);

RevTree commitTree = commit.getTree();
RevCommit parentCommit = walker.parseCommit(parent);
RevTree parentTree = parentCommit.getTree();

addObject(commitTree);

addDiffs(commitTree, parentTree);

return true;
}

private void addDiffs(@NonNull AnyObjectId commitTree, @NonNull AnyObjectId parentTree) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException {
MutableObjectId commitObjectId = new MutableObjectId();

TreeWalk treeWalk = new TreeWalk(reader);
treeWalk.setRecursive(false);
treeWalk.addTree(commitTree);

if (parentTree.equals(ObjectId.zeroId())) {
while (treeWalk.next()) {
treeWalk.getObjectId(commitObjectId, 0);

FileMode commitFileMode = treeWalk.getFileMode(0);

int type = commitFileMode.getObjectType();
int hash = 0; // TODO: ????
addObject(commitObjectId.copy(), type, hash);

if (type == Constants.OBJ_TREE) {
addDiffs(commitObjectId, ObjectId.zeroId());
}
}
} else {
MutableObjectId parentObjectId = new MutableObjectId();

treeWalk.addTree(parentTree);

while (treeWalk.next()) {
if (treeWalk.idEqual(0, 1)) {
continue;
}
treeWalk.getObjectId(commitObjectId, 0);
treeWalk.getObjectId(parentObjectId, 1);

FileMode commitFileMode = treeWalk.getFileMode(0);

if (commitFileMode.equals(FileMode.TYPE_MISSING)) {
continue;
}

int type = commitFileMode.getObjectType();
int hash = 0; // TODO: ????
addObject(commitObjectId.copy(), type, hash);

if (type == Constants.OBJ_TREE) {
addDiffs(commitObjectId, parentObjectId);
}
}
}

treeWalk.close();
}

private void findObjectsToPackUsingBitmaps(
PackWriterBitmapWalker bitmapWalker, Set<? extends ObjectId> want,
Set<? extends ObjectId> have)
Expand Down
Expand Up @@ -123,6 +123,7 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen

private boolean sentCommand;
private boolean writePack;
private boolean useFastSingleCommit;

/** Time in milliseconds spent transferring the pack data. */
private long packTransferTime;
Expand All @@ -137,6 +138,7 @@ public BasePackPushConnection(final PackTransport packTransport) {
super(packTransport);
thinPack = transport.isPushThin();
atomic = transport.isPushAtomic();
useFastSingleCommit = transport.isUseFastSingleCommit();
}

public void push(final ProgressMonitor monitor,
Expand Down Expand Up @@ -313,6 +315,7 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
writer.setIndexDisabled(true);
writer.setUseCachedPacks(true);
writer.setUseBitmaps(true);
writer.setUseFastSingleCommit(useFastSingleCommit);
writer.setThin(thinPack);
writer.setReuseValidatingObjects(false);
writer.setDeltaBaseAsOffset(capableOfsDelta);
Expand Down
30 changes: 30 additions & 0 deletions org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
Expand Up @@ -755,6 +755,9 @@ private static String findTrackingRefName(final String remoteName,
/** Should push be all-or-nothing atomic behavior? */
private boolean pushAtomic;

/** Use the fast-path when building a single-commit? */
private boolean useFastSingleCommit;

/** Should push just check for operation result, not really push. */
private boolean dryRun;

Expand Down Expand Up @@ -997,6 +1000,33 @@ public void setPushAtomic(final boolean atomic) {
this.pushAtomic = atomic;
}

/**
* Default setting is false.
*
* @return true if we use the fast-path for pushing single commits
* @since 4.5
*/
public boolean isUseFastSingleCommit() {
return useFastSingleCommit;
}

/**
* Request fast-path for single commits.
* <p>
* The fast-path checks to see if we are pushing a single commit,
* on top of a remote ref. If so, it adds all objects that are different
* from the parent, without checking whether they already exist previously.
* This is much faster, though at the expense of possibly sending objects
* that the remote already has.
*
* @param useFastSingleCommit
* true when we should enable the fast-path
* @since 4.5
*/
public void setUseFastSingleCommit(final boolean useFastSingleCommit) {
this.useFastSingleCommit = useFastSingleCommit;
}

/**
* @return true if destination refs should be removed if they no longer
* exist at the source repository.
Expand Down

0 comments on commit 9db165e

Please sign in to comment.