Improve performance of ReceiveCommits by reducing RevWalk load
JGit RevWalk does not perform well when a large number of objects are added to the start set by markStart or markUninteresting. Avoid putting existing refs/changes/ or refs/tags/ into the RevWalk and instead use only the refs/heads namespace and the name of the branch used in the refs/for/ push line. Catch existing changes by looking for their exact commit SHA-1, rather than complete ancestory. This should have roughly the same outcome for anyone pushing a new commit on top of an existing open change, but with lower computional cost at the server. Change-Id: Ie2bb9176799528f6422292f3f889e3d28cbf5135
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.git;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.R_HEADS;
|
||||
import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
|
||||
@@ -28,6 +29,7 @@ import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.CheckedFuture;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
@@ -1116,12 +1118,22 @@ public class ReceiveCommits {
|
||||
walk.sort(RevSort.TOPO);
|
||||
walk.sort(RevSort.REVERSE, true);
|
||||
try {
|
||||
Set<ObjectId> existing = Sets.newHashSet();
|
||||
walk.markStart(walk.parseCommit(newChange.getNewId()));
|
||||
for (ObjectId id : existingObjects()) {
|
||||
try {
|
||||
walk.markUninteresting(walk.parseCommit(id));
|
||||
} catch (IOException e) {
|
||||
for (Ref ref : repo.getAllRefs().values()) {
|
||||
if (ref.getObjectId() == null) {
|
||||
continue;
|
||||
} else if (ref.getName().startsWith("refs/changes/")) {
|
||||
existing.add(ref.getObjectId());
|
||||
} else if (ref.getName().startsWith(R_HEADS)
|
||||
|| ref.getName().equals(destBranchCtl.getRefName())) {
|
||||
try {
|
||||
walk.markUninteresting(walk.parseCommit(ref.getObjectId()));
|
||||
} catch (IOException e) {
|
||||
log.warn(String.format("Invalid ref %s in %s",
|
||||
ref.getName(), project.getName()), e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1131,7 +1143,7 @@ public class ReceiveCommits {
|
||||
if (c == null) {
|
||||
break;
|
||||
}
|
||||
if (replaceByCommit.containsKey(c)) {
|
||||
if (existing.contains(c) || replaceByCommit.containsKey(c)) {
|
||||
// This commit was already scheduled to replace an existing PatchSet.
|
||||
//
|
||||
continue;
|
||||
|
Reference in New Issue
Block a user