Defer object flushing when merging
Mergers in the most recent JGit know how to read previously-inserted objects back, so a series of merges does not require aggressively flushing the objects. Instead, flush objects in MergeOp just before updating the relevant refs. Change-Id: Ia85c5114e86739b4a480bea65f3413fe47cf572d
This commit is contained in:
@@ -113,16 +113,15 @@ public class CherryPickChange {
|
||||
|
||||
Project.NameKey project = change.getProject();
|
||||
IdentifiedUser identifiedUser = (IdentifiedUser) currentUser.get();
|
||||
final Repository git;
|
||||
try {
|
||||
git = gitManager.openRepository(project);
|
||||
} catch (RepositoryNotFoundException e) {
|
||||
throw new NoSuchChangeException(change.getId(), e);
|
||||
}
|
||||
Repository git = null;
|
||||
ObjectInserter oi = null;
|
||||
RevWalk revWalk = null;
|
||||
|
||||
try {
|
||||
RevWalk revWalk = new RevWalk(git);
|
||||
try {
|
||||
git = gitManager.openRepository(project);
|
||||
oi = git.newObjectInserter();
|
||||
revWalk = new RevWalk(oi.newReader());
|
||||
|
||||
Ref destRef = git.getRef(destinationBranch);
|
||||
if (destRef == null) {
|
||||
throw new InvalidChangeOperationException("Branch "
|
||||
@@ -146,17 +145,11 @@ public class CherryPickChange {
|
||||
ChangeIdUtil.insertId(message, computedChangeId).trim() + '\n';
|
||||
|
||||
RevCommit cherryPickCommit;
|
||||
ObjectInserter oi = git.newObjectInserter();
|
||||
try {
|
||||
ProjectState projectState = refControl.getProjectControl().getProjectState();
|
||||
cherryPickCommit =
|
||||
mergeUtilFactory.create(projectState).createCherryPickFromCommit(git, oi, mergeTip,
|
||||
commitToCherryPick, committerIdent, commitMessage, revWalk);
|
||||
} catch (MergeIdenticalTreeException | MergeConflictException e) {
|
||||
throw new MergeException("Cherry pick failed: " + e.getMessage());
|
||||
} finally {
|
||||
oi.release();
|
||||
}
|
||||
oi.flush();
|
||||
|
||||
Change.Key changeKey;
|
||||
final List<String> idList = cherryPickCommit.getFooterLines(
|
||||
@@ -189,13 +182,22 @@ public class CherryPickChange {
|
||||
patch.getId(), destRef, cherryPickCommit, refControl,
|
||||
identifiedUser, change.getTopic());
|
||||
}
|
||||
} catch (MergeIdenticalTreeException | MergeConflictException e) {
|
||||
throw new MergeException("Cherry pick failed: " + e.getMessage());
|
||||
} catch (RepositoryNotFoundException e) {
|
||||
throw new NoSuchChangeException(change.getId(), e);
|
||||
} finally {
|
||||
if (revWalk != null) {
|
||||
revWalk.release();
|
||||
}
|
||||
} finally {
|
||||
if (oi != null) {
|
||||
oi.release();
|
||||
}
|
||||
if (git != null) {
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Change.Id insertPatchSet(Repository git, RevWalk revWalk, Change change,
|
||||
RevCommit cherryPickCommit, RefControl refControl,
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.gerrit.server.project.ChangeControl;
|
||||
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
@@ -50,12 +51,11 @@ public class CodeReviewCommit extends RevCommit {
|
||||
}).nullsFirst();
|
||||
|
||||
public static RevWalk newRevWalk(Repository repo) {
|
||||
return new RevWalk(repo) {
|
||||
@Override
|
||||
protected RevCommit createCommit(AnyObjectId id) {
|
||||
return new CodeReviewCommit(id);
|
||||
return new CodeReviewRevWalk(repo);
|
||||
}
|
||||
};
|
||||
|
||||
public static RevWalk newRevWalk(ObjectReader reader) {
|
||||
return new CodeReviewRevWalk(reader);
|
||||
}
|
||||
|
||||
static CodeReviewCommit revisionGone(ChangeControl ctl) {
|
||||
@@ -85,6 +85,21 @@ public class CodeReviewCommit extends RevCommit {
|
||||
return r;
|
||||
}
|
||||
|
||||
private static class CodeReviewRevWalk extends RevWalk {
|
||||
private CodeReviewRevWalk(Repository repo) {
|
||||
super(repo);
|
||||
}
|
||||
|
||||
private CodeReviewRevWalk(ObjectReader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RevCommit createCommit(AnyObjectId id) {
|
||||
return new CodeReviewCommit(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique key of the PatchSet entity from the code review system.
|
||||
* <p>
|
||||
|
||||
@@ -430,13 +430,11 @@ public class MergeOp {
|
||||
String m = "Error opening repository \"" + name.get() + '"';
|
||||
throw new MergeException(m, err);
|
||||
}
|
||||
|
||||
rw = CodeReviewCommit.newRevWalk(repo);
|
||||
inserter = repo.newObjectInserter();
|
||||
rw = CodeReviewCommit.newRevWalk(inserter.newReader());
|
||||
rw.sort(RevSort.TOPO);
|
||||
rw.sort(RevSort.COMMIT_TIME_DESC, true);
|
||||
canMergeFlag = rw.newFlag("CAN_MERGE");
|
||||
|
||||
inserter = repo.newObjectInserter();
|
||||
}
|
||||
|
||||
private RefUpdate openBranch()
|
||||
@@ -674,6 +672,11 @@ public class MergeOp {
|
||||
+ destProject.getProject().getName(), e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
inserter.flush();
|
||||
} catch (IOException e) {
|
||||
throw new MergeException("Cannot flush merge results", e);
|
||||
}
|
||||
|
||||
branchUpdate.setRefLogIdent(refLogIdent);
|
||||
branchUpdate.setForceUpdate(false);
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.eclipse.jgit.errors.LargeObjectException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.errors.NoMergeBaseException;
|
||||
import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
@@ -67,7 +66,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -79,6 +77,12 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Utilities for various kinds of merges and cherry-picks.
|
||||
* <p>
|
||||
* <b>Note:</b> Unless otherwise noted, the methods in this class do not flush
|
||||
* the {@link ObjectInserter}s passed in after performing a merge.
|
||||
*/
|
||||
public class MergeUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(MergeUtil.class);
|
||||
private static final String R_HEADS_MASTER =
|
||||
@@ -177,7 +181,7 @@ public class MergeUtil {
|
||||
final ThreeWayMerger m = newThreeWayMerger(repo, inserter);
|
||||
|
||||
m.setBase(originalCommit.getParent(0));
|
||||
if (m.merge(mergeTip, originalCommit)) {
|
||||
if (m.merge(false, mergeTip, originalCommit)) {
|
||||
ObjectId tree = m.getResultTreeId();
|
||||
if (tree.equals(mergeTip.getTree())) {
|
||||
throw new MergeIdenticalTreeException("identical tree");
|
||||
@@ -189,7 +193,7 @@ public class MergeUtil {
|
||||
mergeCommit.setAuthor(originalCommit.getAuthorIdent());
|
||||
mergeCommit.setCommitter(cherryPickCommitterIdent);
|
||||
mergeCommit.setMessage(commitMsg);
|
||||
return rw.parseCommit(commit(inserter, mergeCommit));
|
||||
return rw.parseCommit(inserter.insert(mergeCommit));
|
||||
} else {
|
||||
throw new MergeConflictException("merge conflict");
|
||||
}
|
||||
@@ -393,7 +397,7 @@ public class MergeUtil {
|
||||
|
||||
ThreeWayMerger m = newThreeWayMerger(repo, createDryRunInserter(repo));
|
||||
try {
|
||||
return m.merge(new AnyObjectId[] {mergeTip, toMerge});
|
||||
return m.merge(false, mergeTip, toMerge);
|
||||
} catch (LargeObjectException e) {
|
||||
log.warn("Cannot merge due to LargeObjectException: " + toMerge.name());
|
||||
return false;
|
||||
@@ -442,7 +446,7 @@ public class MergeUtil {
|
||||
try {
|
||||
ThreeWayMerger m = newThreeWayMerger(repo, createDryRunInserter(repo));
|
||||
m.setBase(toMerge.getParent(0));
|
||||
return m.merge(mergeTip, toMerge);
|
||||
return m.merge(false, mergeTip, toMerge);
|
||||
} catch (IOException e) {
|
||||
throw new MergeException("Cannot merge " + toMerge.name(), e);
|
||||
}
|
||||
@@ -494,7 +498,7 @@ public class MergeUtil {
|
||||
throws MergeException {
|
||||
final ThreeWayMerger m = newThreeWayMerger(repo, inserter);
|
||||
try {
|
||||
if (m.merge(new AnyObjectId[] {mergeTip, n})) {
|
||||
if (m.merge(false, mergeTip, n)) {
|
||||
return writeMergeCommit(myIdent, rw, inserter, canMergeFlag, destBranch,
|
||||
mergeTip, m.getResultTreeId(), n);
|
||||
} else {
|
||||
@@ -582,7 +586,7 @@ public class MergeUtil {
|
||||
mergeCommit.setMessage(msgbuf.toString());
|
||||
|
||||
CodeReviewCommit mergeResult =
|
||||
(CodeReviewCommit) rw.parseCommit(commit(inserter, mergeCommit));
|
||||
(CodeReviewCommit) rw.parseCommit(inserter.insert(mergeCommit));
|
||||
mergeResult.setControl(n.getControl());
|
||||
return mergeResult;
|
||||
}
|
||||
@@ -656,31 +660,10 @@ public class MergeUtil {
|
||||
Merger m = strategy.newMerger(repo, true);
|
||||
checkArgument(m instanceof ThreeWayMerger,
|
||||
"merge strategy %s does not support three-way merging", strategyName);
|
||||
m.setObjectInserter(new ObjectInserter.Filter() {
|
||||
@Override
|
||||
protected ObjectInserter delegate() {
|
||||
return inserter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
});
|
||||
m.setObjectInserter(inserter);
|
||||
return (ThreeWayMerger) m;
|
||||
}
|
||||
|
||||
public ObjectId commit(final ObjectInserter inserter,
|
||||
final CommitBuilder mergeCommit) throws IOException,
|
||||
UnsupportedEncodingException {
|
||||
ObjectId id = inserter.insert(mergeCommit);
|
||||
inserter.flush();
|
||||
return id;
|
||||
}
|
||||
|
||||
public PatchSetApproval markCleanMerges(final RevWalk rw,
|
||||
final RevFlag canMergeFlag, final CodeReviewCommit mergeTip,
|
||||
final Set<RevCommit> alreadyAccepted) throws MergeException {
|
||||
|
||||
@@ -275,24 +275,11 @@ public class PatchListLoader extends CacheLoader<PatchListKey, PatchList> {
|
||||
try {
|
||||
DirCache dc = DirCache.newInCore();
|
||||
m.setDirCache(dc);
|
||||
m.setObjectInserter(new ObjectInserter.Filter() {
|
||||
@Override
|
||||
protected ObjectInserter delegate() {
|
||||
return ins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
});
|
||||
m.setObjectInserter(ins);
|
||||
|
||||
boolean couldMerge;
|
||||
try {
|
||||
couldMerge = m.merge(b.getParents());
|
||||
couldMerge = m.merge(false, b.getParents());
|
||||
} catch (IOException e) {
|
||||
// It is not safe to continue further down in this method as throwing
|
||||
// an exception most likely means that the merge tree was not created
|
||||
|
||||
Reference in New Issue
Block a user