MergeSuperSet: Cache open repositories
completeChangeSetWithoutTopic was trying to be nice by grouping changes by project to cut down on opening repositories multiple times. However, it would still open repos multiple times across multiple iterations of the main completeChangeSet loop. Reuse the existing MergeOpRepoManager, since this code is already called in the MergeOp path where we have one available. As it happens, the options (particularly the sort) that are already set in MergeOpRepoManager are more or less what we need here. Change-Id: Icdc78daab3290f5a39dba0e5a162d51ec93ca00a
This commit is contained in:
@@ -412,7 +412,8 @@ public class MergeOp implements AutoCloseable {
|
|||||||
|
|
||||||
logDebug("Beginning integration of {}", change);
|
logDebug("Beginning integration of {}", change);
|
||||||
try {
|
try {
|
||||||
ChangeSet cs = mergeSuperSet.completeChangeSet(db, change, caller);
|
ChangeSet cs = mergeSuperSet.setMergeOpRepoManager(orm)
|
||||||
|
.completeChangeSet(db, change, caller);
|
||||||
checkState(cs.ids().contains(change.getId()),
|
checkState(cs.ids().contains(change.getId()),
|
||||||
"change %s missing from %s", change.getId(), cs);
|
"change %s missing from %s", change.getId(), cs);
|
||||||
if (cs.furtherHiddenChanges()) {
|
if (cs.furtherHiddenChanges()) {
|
||||||
|
|||||||
@@ -14,13 +14,12 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.git;
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableListMultimap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.gerrit.common.data.SubmitTypeRecord;
|
import com.google.gerrit.common.data.SubmitTypeRecord;
|
||||||
import com.google.gerrit.extensions.client.SubmitType;
|
import com.google.gerrit.extensions.client.SubmitType;
|
||||||
import com.google.gerrit.reviewdb.client.Branch;
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
@@ -31,8 +30,10 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
|
|||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.change.Submit;
|
import com.google.gerrit.server.change.Submit;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
|
import com.google.gerrit.server.git.MergeOpRepoManager.OpenRepo;
|
||||||
import com.google.gerrit.server.index.change.ChangeField;
|
import com.google.gerrit.server.index.change.ChangeField;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
|
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||||
import com.google.gerrit.server.project.SubmitRuleEvaluator;
|
import com.google.gerrit.server.project.SubmitRuleEvaluator;
|
||||||
import com.google.gerrit.server.query.change.ChangeData;
|
import com.google.gerrit.server.query.change.ChangeData;
|
||||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||||
@@ -40,15 +41,11 @@ import com.google.gwtorm.server.OrmException;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevSort;
|
import org.eclipse.jgit.revwalk.RevSort;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -82,23 +79,33 @@ public class MergeSuperSet {
|
|||||||
|
|
||||||
private final ChangeData.Factory changeDataFactory;
|
private final ChangeData.Factory changeDataFactory;
|
||||||
private final Provider<InternalChangeQuery> queryProvider;
|
private final Provider<InternalChangeQuery> queryProvider;
|
||||||
private final GitRepositoryManager repoManager;
|
private final Provider<MergeOpRepoManager> repoManagerProvider;
|
||||||
private final Config cfg;
|
private final Config cfg;
|
||||||
|
|
||||||
|
private MergeOpRepoManager orm;
|
||||||
|
private boolean closeOrm;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MergeSuperSet(@GerritServerConfig Config cfg,
|
MergeSuperSet(@GerritServerConfig Config cfg,
|
||||||
ChangeData.Factory changeDataFactory,
|
ChangeData.Factory changeDataFactory,
|
||||||
Provider<InternalChangeQuery> queryProvider,
|
Provider<InternalChangeQuery> queryProvider,
|
||||||
GitRepositoryManager repoManager) {
|
Provider<MergeOpRepoManager> repoManagerProvider) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
this.changeDataFactory = changeDataFactory;
|
this.changeDataFactory = changeDataFactory;
|
||||||
this.queryProvider = queryProvider;
|
this.queryProvider = queryProvider;
|
||||||
this.repoManager = repoManager;
|
this.repoManagerProvider = repoManagerProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeSet completeChangeSet(ReviewDb db, Change change, CurrentUser user)
|
public MergeSuperSet setMergeOpRepoManager(MergeOpRepoManager orm) {
|
||||||
throws MissingObjectException, IncorrectObjectTypeException, IOException,
|
checkState(this.orm == null);
|
||||||
OrmException {
|
this.orm = checkNotNull(orm);
|
||||||
|
closeOrm = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangeSet completeChangeSet(ReviewDb db, Change change,
|
||||||
|
CurrentUser user) throws IOException, OrmException {
|
||||||
|
try {
|
||||||
ChangeData cd =
|
ChangeData cd =
|
||||||
changeDataFactory.create(db, change.getProject(), change.getId());
|
changeDataFactory.create(db, change.getProject(), change.getId());
|
||||||
cd.changeControl(user);
|
cd.changeControl(user);
|
||||||
@@ -107,16 +114,12 @@ public class MergeSuperSet {
|
|||||||
return completeChangeSetIncludingTopics(db, cs, user);
|
return completeChangeSetIncludingTopics(db, cs, user);
|
||||||
}
|
}
|
||||||
return completeChangeSetWithoutTopic(db, cs, user);
|
return completeChangeSetWithoutTopic(db, cs, user);
|
||||||
|
} finally {
|
||||||
|
if (closeOrm && orm != null) {
|
||||||
|
orm.close();
|
||||||
|
orm = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImmutableListMultimap<Project.NameKey, ChangeData>
|
|
||||||
byProject(Iterable<ChangeData> changes) throws OrmException {
|
|
||||||
ImmutableListMultimap.Builder<Project.NameKey, ChangeData> builder =
|
|
||||||
new ImmutableListMultimap.Builder<>();
|
|
||||||
for (ChangeData cd : changes) {
|
|
||||||
builder.put(cd.change().getProject(), cd);
|
|
||||||
}
|
}
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubmitType submitType(ChangeData cd, PatchSet ps, boolean visible)
|
private SubmitType submitType(ChangeData cd, PatchSet ps, boolean visible)
|
||||||
@@ -146,22 +149,17 @@ public class MergeSuperSet {
|
|||||||
return str.type;
|
return str.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChangeSet completeChangeSetWithoutTopic(ReviewDb db, ChangeSet changes,
|
private ChangeSet completeChangeSetWithoutTopic(ReviewDb db,
|
||||||
CurrentUser user) throws MissingObjectException,
|
ChangeSet changes, CurrentUser user) throws IOException, OrmException {
|
||||||
IncorrectObjectTypeException, IOException, OrmException {
|
|
||||||
List<ChangeData> visibleChanges = new ArrayList<>();
|
List<ChangeData> visibleChanges = new ArrayList<>();
|
||||||
List<ChangeData> nonVisibleChanges = new ArrayList<>();
|
List<ChangeData> nonVisibleChanges = new ArrayList<>();
|
||||||
|
|
||||||
Multimap<Project.NameKey, ChangeData> pc =
|
for (ChangeData cd :
|
||||||
byProject(
|
Iterables.concat(changes.changes(), changes.nonVisibleChanges())) {
|
||||||
Iterables.concat(changes.changes(), changes.nonVisibleChanges()));
|
|
||||||
for (Project.NameKey project : pc.keySet()) {
|
|
||||||
try (Repository repo = repoManager.openRepository(project);
|
|
||||||
RevWalk rw = CodeReviewCommit.newRevWalk(repo)) {
|
|
||||||
for (ChangeData cd : pc.get(project)) {
|
|
||||||
checkState(cd.hasChangeControl(),
|
checkState(cd.hasChangeControl(),
|
||||||
"completeChangeSet forgot to set changeControl for current user"
|
"completeChangeSet forgot to set changeControl for current user"
|
||||||
+ " at ChangeData creation time");
|
+ " at ChangeData creation time");
|
||||||
|
OpenRepo or = getRepo(cd.change().getProject());
|
||||||
boolean visible = changes.ids().contains(cd.getId());
|
boolean visible = changes.ids().contains(cd.getId());
|
||||||
if (visible && !cd.changeControl().isVisible(db, cd)) {
|
if (visible && !cd.changeControl().isVisible(db, cd)) {
|
||||||
// We thought the change was visible, but it isn't.
|
// We thought the change was visible, but it isn't.
|
||||||
@@ -192,19 +190,17 @@ public class MergeSuperSet {
|
|||||||
|
|
||||||
// Get the underlying git commit object
|
// Get the underlying git commit object
|
||||||
String objIdStr = ps.getRevision().get();
|
String objIdStr = ps.getRevision().get();
|
||||||
RevCommit commit = rw.parseCommit(ObjectId.fromString(objIdStr));
|
RevCommit commit = or.rw.parseCommit(ObjectId.fromString(objIdStr));
|
||||||
|
|
||||||
// Collect unmerged ancestors
|
// Collect unmerged ancestors
|
||||||
Branch.NameKey destBranch = cd.change().getDest();
|
Branch.NameKey destBranch = cd.change().getDest();
|
||||||
repo.getRefDatabase().refresh();
|
Ref ref = or.repo.getRefDatabase().getRef(destBranch.get());
|
||||||
Ref ref = repo.getRefDatabase().getRef(destBranch.get());
|
|
||||||
|
|
||||||
rw.reset();
|
or.rw.reset();
|
||||||
rw.sort(RevSort.TOPO);
|
or.rw.markStart(commit);
|
||||||
rw.markStart(commit);
|
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
RevCommit head = rw.parseCommit(ref.getObjectId());
|
RevCommit head = or.rw.parseCommit(ref.getObjectId());
|
||||||
rw.markUninteresting(head);
|
or.rw.markUninteresting(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> hashes = new ArrayList<>();
|
List<String> hashes = new ArrayList<>();
|
||||||
@@ -212,7 +208,7 @@ public class MergeSuperSet {
|
|||||||
// SubmitStrategyOp to correct the situation later, assuming it gets
|
// SubmitStrategyOp to correct the situation later, assuming it gets
|
||||||
// returned by byCommitsOnBranchNotMerged below.
|
// returned by byCommitsOnBranchNotMerged below.
|
||||||
hashes.add(objIdStr);
|
hashes.add(objIdStr);
|
||||||
for (RevCommit c : rw) {
|
for (RevCommit c : or.rw) {
|
||||||
if (!c.equals(commit)) {
|
if (!c.equals(commit)) {
|
||||||
hashes.add(c.name());
|
hashes.add(c.name());
|
||||||
}
|
}
|
||||||
@@ -221,19 +217,31 @@ public class MergeSuperSet {
|
|||||||
if (!hashes.isEmpty()) {
|
if (!hashes.isEmpty()) {
|
||||||
Iterable<ChangeData> destChanges = query()
|
Iterable<ChangeData> destChanges = query()
|
||||||
.byCommitsOnBranchNotMerged(
|
.byCommitsOnBranchNotMerged(
|
||||||
repo, db, cd.change().getDest(), hashes);
|
or.repo, db, cd.change().getDest(), hashes);
|
||||||
for (ChangeData chd : destChanges) {
|
for (ChangeData chd : destChanges) {
|
||||||
chd.changeControl(user);
|
chd.changeControl(user);
|
||||||
dest.add(chd);
|
dest.add(chd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ChangeSet(visibleChanges, nonVisibleChanges);
|
return new ChangeSet(visibleChanges, nonVisibleChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OpenRepo getRepo(Project.NameKey project) throws IOException {
|
||||||
|
if (orm == null) {
|
||||||
|
orm = repoManagerProvider.get();
|
||||||
|
closeOrm = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
OpenRepo or = orm.openRepo(project);
|
||||||
|
checkState(or.rw.hasRevSort(RevSort.TOPO));
|
||||||
|
return or;
|
||||||
|
} catch (NoSuchProjectException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completes {@code cs} with any additional changes from its topics
|
* Completes {@code cs} with any additional changes from its topics
|
||||||
* <p>
|
* <p>
|
||||||
@@ -296,8 +304,7 @@ public class MergeSuperSet {
|
|||||||
|
|
||||||
private ChangeSet completeChangeSetIncludingTopics(
|
private ChangeSet completeChangeSetIncludingTopics(
|
||||||
ReviewDb db, ChangeSet changes, CurrentUser user)
|
ReviewDb db, ChangeSet changes, CurrentUser user)
|
||||||
throws MissingObjectException, IncorrectObjectTypeException, IOException,
|
throws IOException, OrmException {
|
||||||
OrmException {
|
|
||||||
Set<String> topicsSeen = new HashSet<>();
|
Set<String> topicsSeen = new HashSet<>();
|
||||||
Set<String> visibleTopicsSeen = new HashSet<>();
|
Set<String> visibleTopicsSeen = new HashSet<>();
|
||||||
int oldSeen;
|
int oldSeen;
|
||||||
|
|||||||
Reference in New Issue
Block a user