diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java index c1f8de37f7..5b39f48111 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java @@ -40,6 +40,7 @@ import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.ApprovalsUtil; +import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.project.PutConfig; import com.google.gson.reflect.TypeToken; @@ -73,6 +74,8 @@ public abstract class AbstractSubmit extends AbstractDaemonTest { @Inject private ApprovalsUtil approvalsUtil; + @Inject + private ChangeIndexer indexer; @Before public void setUp() throws Exception { @@ -166,6 +169,7 @@ public abstract class AbstractSubmit extends AbstractDaemonTest { PatchSetApproval.LabelId.SUBMIT), (short) 1, new Timestamp(System.currentTimeMillis())))); + indexer.index(db, c); } private void submit(String changeId, int expectedStatus) throws IOException { diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java index ec466380f1..c4978193a6 100644 --- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java +++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java @@ -14,9 +14,7 @@ package com.google.gerrit.reviewdb.server; -import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.client.Project; import com.google.gwtorm.server.Access; import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.PrimaryKey; @@ -35,26 +33,6 @@ public interface ChangeAccess extends Access { ResultSet byKeyRange(Change.Key reva, Change.Key revb) throws OrmException; - @Query("WHERE dest = ? AND changeKey = ?") - ResultSet byBranchKey(Branch.NameKey p, Change.Key key) - throws OrmException; - - @Query("WHERE dest.projectName = ?") - ResultSet byProject(Project.NameKey p) throws OrmException; - - @Query("WHERE dest = ? AND status = '" + Change.STATUS_SUBMITTED - + "' ORDER BY lastUpdatedOn") - ResultSet submitted(Branch.NameKey dest) throws OrmException; - - @Query("WHERE status = '" + Change.STATUS_SUBMITTED + "'") - ResultSet allSubmitted() throws OrmException; - - @Query("WHERE open = true AND dest.projectName = ?") - ResultSet byProjectOpenAll(Project.NameKey p) throws OrmException; - - @Query("WHERE open = true AND dest = ?") - ResultSet byBranchOpenAll(Branch.NameKey p) throws OrmException; - @Query ResultSet all() throws OrmException; } diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql index 59e6934f4c..b9216a7a37 100644 --- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql +++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql @@ -69,18 +69,6 @@ ON account_project_watches (project_name); -- ********************************************************************* -- ChangeAccess --- covers: submitted, allSubmitted -CREATE INDEX changes_submitted -ON changes (status, dest_project_name, dest_branch_name, last_updated_on); - --- covers: byProjectOpenAll -CREATE INDEX changes_byProjectOpen -ON changes (open, dest_project_name, last_updated_on); - --- covers: byProject -CREATE INDEX changes_byProject -ON changes (dest_project_name); - CREATE INDEX changes_key ON changes (change_key); diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql index de86ff6e9d..48836acde2 100644 --- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql +++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_maxdb.sql @@ -76,21 +76,6 @@ ON account_project_watches (project_name) -- ********************************************************************* -- ChangeAccess --- covers: submitted, allSubmitted -CREATE INDEX changes_submitted -ON changes (status, dest_project_name, dest_branch_name, last_updated_on) -# - --- covers: byProjectOpenPrev, byProjectOpenNext -CREATE INDEX changes_byProjectOpen -ON changes (open, dest_project_name, last_updated_on); -# - --- covers: byProject -CREATE INDEX changes_byProject -ON changes (dest_project_name) -# - CREATE INDEX changes_key ON changes (change_key) # diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql index ef50f24d05..95fc4bd174 100644 --- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql +++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql @@ -117,20 +117,6 @@ ON account_project_watches (project_name); -- ********************************************************************* -- ChangeAccess --- covers: submitted, allSubmitted -CREATE INDEX changes_submitted -ON changes (dest_project_name, dest_branch_name, last_updated_on) -WHERE status = 's'; - --- covers: byProjectOpenAll -CREATE INDEX changes_byProjectOpen -ON changes (dest_project_name, last_updated_on) -WHERE open = 'Y'; - --- covers: byProject -CREATE INDEX changes_byProject -ON changes (dest_project_name); - CREATE INDEX changes_key ON changes (change_key); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java index b3c470999c..f2fefbed79 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java @@ -15,6 +15,7 @@ package com.google.gerrit.server; import static com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy.RECEIVE_COMMITS; +import static com.google.gerrit.server.query.change.ChangeData.asChanges; import com.google.common.base.Optional; import com.google.common.base.Strings; @@ -42,6 +43,7 @@ import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.RefControl; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.ssh.SshInfo; import com.google.gerrit.server.util.IdGenerator; import com.google.gerrit.server.util.MagicBranch; @@ -182,6 +184,7 @@ public class ChangeUtil { private final Provider userProvider; private final CommitValidators.Factory commitValidatorsFactory; private final Provider db; + private final Provider queryProvider; private final RevertedSender.Factory revertedSenderFactory; private final ChangeInserter.Factory changeInserterFactory; private final PatchSetInserter.Factory patchSetInserterFactory; @@ -193,6 +196,7 @@ public class ChangeUtil { ChangeUtil(Provider userProvider, CommitValidators.Factory commitValidatorsFactory, Provider db, + Provider queryProvider, RevertedSender.Factory revertedSenderFactory, ChangeInserter.Factory changeInserterFactory, PatchSetInserter.Factory patchSetInserterFactory, @@ -202,6 +206,7 @@ public class ChangeUtil { this.userProvider = userProvider; this.commitValidatorsFactory = commitValidatorsFactory; this.db = db; + this.queryProvider = queryProvider; this.revertedSenderFactory = revertedSenderFactory; this.changeInserterFactory = changeInserterFactory; this.patchSetInserterFactory = patchSetInserterFactory; @@ -532,9 +537,9 @@ public class ChangeUtil { // Try change triplet Optional triplet = ChangeTriplet.parse(id); if (triplet.isPresent()) { - return db.get().changes().byBranchKey( + return asChanges(queryProvider.get().byBranchKey( triplet.get().branch(), - triplet.get().id()).toList(); + triplet.get().id())); } throw new ResourceNotFoundException(id); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java b/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java index 9c3d052372..1cbab8ac48 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/args4j/ChangeIdHandler.java @@ -17,9 +17,11 @@ package com.google.gerrit.server.args4j; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; import org.kohsuke.args4j.CmdLineException; @@ -30,17 +32,16 @@ import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Setter; public class ChangeIdHandler extends OptionHandler { - - @Inject - private ReviewDb db; + private final Provider queryProvider; @Inject public ChangeIdHandler( - final ReviewDb db, + // TODO(dborowitz): Not sure whether this is injectable here. + Provider queryProvider, @Assisted final CmdLineParser parser, @Assisted final OptionDef option, @Assisted final Setter setter) { super(parser, option, setter); - this.db = db; + this.queryProvider = queryProvider; } @Override @@ -58,8 +59,8 @@ public class ChangeIdHandler extends OptionHandler { final Project.NameKey project = new Project.NameKey(tokens[0]); final Branch.NameKey branch = new Branch.NameKey(project, "refs/heads/" + tokens[1]); - for (final Change change : db.changes().byBranchKey(branch, key)) { - setter.addValue(change.getId()); + for (final ChangeData cd : queryProvider.get().byBranchKey(branch, key)) { + setter.addValue(cd.getId()); return 1; } } catch (IllegalArgumentException e) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java index 9cb11283df..374cde3139 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java @@ -39,6 +39,8 @@ import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.RefControl; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.ssh.NoSshInfo; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; @@ -67,6 +69,7 @@ import java.util.TimeZone; public class CherryPickChange { private final Provider db; + private final Provider queryProvider; private final GitRepositoryManager gitManager; private final TimeZone serverTimeZone; private final Provider currentUser; @@ -76,15 +79,17 @@ public class CherryPickChange { final MergeUtil.Factory mergeUtilFactory; @Inject - CherryPickChange(final Provider db, - @GerritPersonIdent final PersonIdent myIdent, - final GitRepositoryManager gitManager, - final Provider currentUser, - final CommitValidators.Factory commitValidatorsFactory, - final ChangeInserter.Factory changeInserterFactory, - final PatchSetInserter.Factory patchSetInserterFactory, - final MergeUtil.Factory mergeUtilFactory) { + CherryPickChange(Provider db, + Provider queryProvider, + @GerritPersonIdent PersonIdent myIdent, + GitRepositoryManager gitManager, + Provider currentUser, + CommitValidators.Factory commitValidatorsFactory, + ChangeInserter.Factory changeInserterFactory, + PatchSetInserter.Factory patchSetInserterFactory, + MergeUtil.Factory mergeUtilFactory) { this.db = db; + this.queryProvider = queryProvider; this.gitManager = gitManager; this.serverTimeZone = myIdent.getTimeZone(); this.currentUser = currentUser; @@ -163,11 +168,11 @@ public class CherryPickChange { changeKey = new Change.Key("I" + computedChangeId.name()); } - List destChanges = - db.get().changes() - .byBranchKey(new Branch.NameKey(project, destRef.getName()), - changeKey).toList(); - + Branch.NameKey newDest = + new Branch.NameKey(change.getProject(), destRef.getName()); + List destChanges = queryProvider.get() + .setLimit(2) + .byBranchKey(newDest, changeKey); if (destChanges.size() > 1) { throw new InvalidChangeOperationException("Several changes with key " + changeKey + " reside on the same branch. " @@ -175,7 +180,7 @@ public class CherryPickChange { } else if (destChanges.size() == 1) { // The change key exists on the destination branch. The cherry pick // will be added as a new patch set. - return insertPatchSet(git, revWalk, destChanges.get(0), + return insertPatchSet(git, revWalk, destChanges.get(0).change(), cherryPickCommit, refControl, identifiedUser); } else { // Change key not found on destination branch. We can create a new diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java index 6056e5f7aa..e69e26836e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java @@ -32,6 +32,8 @@ import com.google.gerrit.server.CommonConverters; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ProjectControl; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.ResultSet; import com.google.inject.Inject; @@ -64,11 +66,15 @@ public class GetRelated implements RestReadView { private final GitRepositoryManager gitMgr; private final Provider dbProvider; + private final Provider queryProvider; @Inject - GetRelated(GitRepositoryManager gitMgr, Provider db) { + GetRelated(GitRepositoryManager gitMgr, + Provider db, + Provider queryProvider) { this.gitMgr = gitMgr; this.dbProvider = db; + this.queryProvider = queryProvider; } @Override @@ -92,8 +98,8 @@ public class GetRelated implements RestReadView { private List walk(RevisionResource rsrc, RevWalk rw, Ref ref) throws OrmException, IOException { - Map changes = allOpenChanges(rsrc); - Map patchSets = allPatchSets(rsrc, changes.keySet()); + Map changes = allOpenChanges(rsrc); + Map patchSets = allPatchSets(rsrc, changes.values()); Map commits = Maps.newHashMap(); for (PatchSet p : patchSets.values()) { @@ -119,7 +125,7 @@ public class GetRelated implements RestReadView { PatchSet p = commits.get(c.name()); Change g = null; if (p != null) { - g = changes.get(p.getId().getParentKey()); + g = changes.get(p.getId().getParentKey()).change(); added.add(p.getId().getParentKey()); } else { // check if there is a merged or abandoned change for this commit @@ -148,25 +154,18 @@ public class GetRelated implements RestReadView { return list; } - private Map allOpenChanges(RevisionResource rsrc) + private Map allOpenChanges(RevisionResource rsrc) throws OrmException { - ReviewDb db = dbProvider.get(); - return db.changes().toMap( - db.changes().byBranchOpenAll(rsrc.getChange().getDest())); + return ChangeData.asMap( + queryProvider.get().byBranchOpen(rsrc.getChange().getDest())); } private Map allPatchSets(RevisionResource rsrc, - Collection ids) throws OrmException { - int n = ids.size(); - ReviewDb db = dbProvider.get(); - List> t = Lists.newArrayListWithCapacity(n); - for (Change.Id id : ids) { - t.add(db.patchSets().byChange(id)); - } - - Map r = Maps.newHashMapWithExpectedSize(n * 2); - for (ResultSet rs : t) { - for (PatchSet p : rs) { + Collection cds) throws OrmException { + Map r = + Maps.newHashMapWithExpectedSize(cds.size() * 2); + for (ChangeData cd : cds) { + for (PatchSet p : cd.patches()) { r.put(p.getId(), p); } } @@ -178,7 +177,7 @@ public class GetRelated implements RestReadView { } private List children(RevisionResource rsrc, RevWalk rw, - Map changes, Map patchSets, + Map changes, Map patchSets, Set added) throws OrmException, IOException { // children is a map of parent commit name to PatchSet built on it. @@ -205,9 +204,9 @@ public class GetRelated implements RestReadView { } for (Map.Entry e : matches.entrySet()) { - Change change = changes.get(e.getKey()); + ChangeData cd = changes.get(e.getKey()); PatchSet ps = patchSets.get(e.getValue()); - if (change == null || ps == null || !seenChange.add(e.getKey())) { + if (cd == null || ps == null || !seenChange.add(e.getKey())) { continue; } @@ -218,7 +217,7 @@ public class GetRelated implements RestReadView { q.addFirst(ps.getRevision().get()); if (added.add(ps.getId().getParentKey())) { rw.parseBody(c); - graph.add(new ChangeAndCommit(change, ps, c)); + graph.add(new ChangeAndCommit(cd.change(), ps, c)); } } } @@ -228,13 +227,15 @@ public class GetRelated implements RestReadView { } private boolean isVisible(ProjectControl projectCtl, - Map changes, + Map changes, Map patchSets, PatchSet.Id psId) throws OrmException { - Change c = changes.get(psId.getParentKey()); + ChangeData cd = changes.get(psId.getParentKey()); PatchSet ps = patchSets.get(psId); - if (c != null && ps != null) { - ChangeControl ctl = projectCtl.controlFor(c); + if (cd != null && ps != null) { + // Related changes are in the same project, so reuse the existing + // ProjectControl. + ChangeControl ctl = projectCtl.controlFor(cd.change()); return ctl.isVisible(dbProvider.get()) && ctl.isPatchVisible(ps, dbProvider.get()); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeCache.java index eb4acfc59e..d1c968f3b3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeCache.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeCache.java @@ -20,11 +20,13 @@ import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; -import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.cache.CacheModule; -import com.google.gwtorm.server.SchemaFactory; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; +import com.google.gerrit.server.util.OneOffRequestContext; import com.google.inject.Inject; import com.google.inject.Module; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; @@ -79,20 +81,21 @@ public class ChangeCache implements GitReferenceUpdatedListener { } static class Loader extends CacheLoader> { - private final SchemaFactory schema; + private final OneOffRequestContext requestContext; + private final Provider queryProvider; @Inject - Loader(SchemaFactory schema) { - this.schema = schema; + Loader(OneOffRequestContext requestContext, + Provider queryProvider) { + this.requestContext = requestContext; + this.queryProvider = queryProvider; } @Override public List load(Project.NameKey key) throws Exception { - final ReviewDb db = schema.open(); - try { - return Collections.unmodifiableList(db.changes().byProject(key).toList()); - } finally { - db.close(); + try (AutoCloseable ctx = requestContext.open()) { + return Collections.unmodifiableList( + ChangeData.asChanges(queryProvider.get().byProject(key))); } } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java index 6c2092b85b..ba38f8f789 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java @@ -65,11 +65,13 @@ import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.SubmitRuleEvaluator; import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.util.RequestScopePropagator; import com.google.gwtorm.server.AtomicUpdate; import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; import org.eclipse.jgit.errors.IncorrectObjectTypeException; @@ -148,6 +150,7 @@ public class MergeOp { private final MergeValidators.Factory mergeValidatorsFactory; private final PatchSetInfoFactory patchSetInfoFactory; private final ProjectCache projectCache; + private final Provider queryProvider; private final RequestScopePropagator requestScopePropagator; private final SchemaFactory schemaFactory; private final SubmitStrategyFactory submitStrategyFactory; @@ -191,6 +194,7 @@ public class MergeOp { MergeValidators.Factory mergeValidatorsFactory, PatchSetInfoFactory patchSetInfoFactory, ProjectCache projectCache, + Provider queryProvider, RequestScopePropagator requestScopePropagator, SchemaFactory schemaFactory, SubmitStrategyFactory submitStrategyFactory, @@ -216,6 +220,7 @@ public class MergeOp { this.mergeValidatorsFactory = mergeValidatorsFactory; this.patchSetInfoFactory = patchSetInfoFactory; this.projectCache = projectCache; + this.queryProvider = queryProvider; this.requestScopePropagator = requestScopePropagator; this.schemaFactory = schemaFactory; this.submitStrategyFactory = submitStrategyFactory; @@ -256,7 +261,7 @@ public class MergeOp { boolean reopen = false; ListMultimap toSubmit = - validateChangeList(db.changes().submitted(destBranch).toList()); + validateChangeList(queryProvider.get().submitted(destBranch)); ListMultimap toMergeNextTurn = ArrayListMultimap.create(); List potentiallyStillSubmittableOnNextRun = @@ -444,9 +449,14 @@ public class MergeOp { branchTip = null; branchUpdate.setExpectedOldObjectId(ObjectId.zeroId()); } else { - for (Change c : db.changes().submitted(destBranch).toList()) { - setNew(c, message(c, "Your change could not be merged, " - + "because the destination branch does not exist anymore.")); + for (ChangeData cd : queryProvider.get().submitted(destBranch)) { + try { + Change c = cd.change(); + setNew(c, message(c, "Your change could not be merged, " + + "because the destination branch does not exist anymore.")); + } catch (OrmException e) { + log.error("Error setting change new", e); + } } } return branchUpdate; @@ -481,7 +491,7 @@ public class MergeOp { } private ListMultimap validateChangeList( - List submitted) throws MergeException { + List submitted) throws MergeException { ListMultimap toSubmit = ArrayListMultimap.create(); Map allRefs; @@ -496,15 +506,16 @@ public class MergeOp { tips.add(r.getObjectId()); } - for (Change chg : submitted) { + for (ChangeData cd : submitted) { ChangeControl ctl; + Change chg; try { - ctl = changeControlFactory.controlFor(chg, - identifiedUserFactory.create(chg.getOwner())); - } catch (NoSuchChangeException e) { + ctl = cd.changeControl(); + chg = cd.change(); + } catch (OrmException e) { throw new MergeException("Failed to validate changes", e); } - Change.Id changeId = chg.getId(); + Change.Id changeId = cd.getId(); if (chg.currentPatchSetId() == null) { logError("Missing current patch set on change " + changeId); commits.put(changeId, CodeReviewCommit.noPatchSet(ctl)); @@ -514,7 +525,7 @@ public class MergeOp { PatchSet ps; try { - ps = db.patchSets().get(chg.currentPatchSetId()); + ps = cd.currentPatchSet(); } catch (OrmException e) { throw new MergeException("Cannot query the database", e); } @@ -565,6 +576,7 @@ public class MergeOp { continue; } + // TODO(dborowitz): Consider putting ChangeData in CodeReviewCommit. commit.setControl(ctl); commit.setPatchsetId(ps.getId()); commits.put(changeId, commit); @@ -733,7 +745,7 @@ public class MergeOp { private void updateChangeStatus(List submitted) throws NoSuchChangeException { - logDebug("Updating change status for {} changes", submitted); + logDebug("Updating change status for {} changes", submitted.size()); for (Change c : submitted) { CodeReviewCommit commit = commits.get(c.getId()); CommitMergeStatus s = commit != null ? commit.getStatusCode() : null; @@ -747,7 +759,8 @@ public class MergeOp { } String txt = s.getMessage(); - logDebug("Status of change {} on {}: {}", c.getId(), c.getDest(), s); + logDebug("Status of change {} ({}) on {}: {}", c.getId(), commit.name(), + c.getDest(), s); try { switch (s) { @@ -1207,9 +1220,9 @@ public class MergeOp { Exception err = null; try { openSchema(); - for (Change c - : db.changes().byProjectOpenAll(destBranch.getParentKey())) { - abandonOneChange(c); + for (ChangeData cd + : queryProvider.get().byProjectOpen(destBranch.getParentKey())) { + abandonOneChange(cd.change()); } db.close(); db = null; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java index 0606dcca79..02f8643231 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java @@ -272,6 +272,7 @@ public class ReceiveCommits { private final IdentifiedUser currentUser; private final ReviewDb db; + private final Provider queryProvider; private final ChangeData.Factory changeDataFactory; private final ChangeUpdate.Factory updateFactory; private final SchemaFactory schemaFactory; @@ -377,6 +378,7 @@ public class ReceiveCommits { final NotesMigration notesMigration) throws IOException { this.currentUser = (IdentifiedUser) projectControl.getCurrentUser(); this.db = db; + this.queryProvider = queryProvider; this.changeDataFactory = changeDataFactory; this.updateFactory = updateFactory; this.schemaFactory = schemaFactory; @@ -1523,7 +1525,7 @@ public class ReceiveCommits { return; } - List changes = p.destChanges.toList(); + List changes = p.destChanges; if (changes.size() > 1) { // WTF, multiple changes in this project have the same key? // Since the commit is new, the user should recreate it with @@ -1538,7 +1540,8 @@ public class ReceiveCommits { if (changes.size() == 1) { // Schedule as a replacement to this one matching change. // - if (requestReplace(magicBranch.cmd, false, changes.get(0), p.commit)) { + if (requestReplace( + magicBranch.cmd, false, changes.get(0).change(), p.commit)) { continue; } else { newChanges = Collections.emptyList(); @@ -1602,12 +1605,12 @@ public class ReceiveCommits { private class ChangeLookup { final RevCommit commit; final Change.Key changeKey; - final ResultSet destChanges; + final List destChanges; ChangeLookup(RevCommit c, Change.Key key) throws OrmException { commit = c; changeKey = key; - destChanges = db.changes().byBranchKey(magicBranch.dest, key); + destChanges = queryProvider.get().byBranchKey(magicBranch.dest, key); } } @@ -2353,7 +2356,7 @@ public class ReceiveCommits { closeProgress.update(1); if (closedChange != null) { if (byKey == null) { - byKey = openChangesByKey(branch); + byKey = openChangesByBranch(branch); } byKey.remove(closedChange); } @@ -2361,7 +2364,7 @@ public class ReceiveCommits { for (final String changeId : c.getFooterLines(CHANGE_ID)) { if (byKey == null) { - byKey = openChangesByKey(branch); + byKey = openChangesByBranch(branch); } final Change onto = byKey.get(new Change.Key(changeId.trim())); @@ -2436,11 +2439,11 @@ public class ReceiveCommits { return change.getKey(); } - private Map openChangesByKey(Branch.NameKey branch) + private Map openChangesByBranch(Branch.NameKey branch) throws OrmException { final Map r = new HashMap<>(); - for (Change c : db.changes().byBranchOpenAll(branch)) { - r.put(c.getKey(), c); + for (ChangeData cd : queryProvider.get().byBranchOpen(branch)) { + r.put(cd.change().getKey(), cd.change()); } return r; } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java index 5580f2053c..7095552e4c 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java @@ -101,8 +101,10 @@ public class ReceiveCommitsAdvertiseRefsHook implements AdvertiseRefsHook { final int limit = 32; try { Set toGet = Sets.newHashSetWithExpectedSize(limit); - for (ChangeData cd : - queryProvider.get().setLimit(limit).byProjectOpen(projectName)) { + for (ChangeData cd : queryProvider.get() + .enforceVisibility(true) + .setLimit(limit) + .byProjectOpen(projectName)) { PatchSet.Id id = cd.change().currentPatchSetId(); if (id != null) { toGet.add(id); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java index 266ce1aaea..734512fbb3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java @@ -15,11 +15,12 @@ package com.google.gerrit.server.git; import com.google.gerrit.reviewdb.client.Branch; -import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.query.change.InternalChangeQuery; +import com.google.gerrit.server.util.OneOffRequestContext; import com.google.gwtorm.server.OrmException; -import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import org.slf4j.Logger; @@ -32,35 +33,39 @@ public class ReloadSubmitQueueOp extends DefaultQueueOp { private static final Logger log = LoggerFactory.getLogger(ReloadSubmitQueueOp.class); - private final SchemaFactory schema; + private final OneOffRequestContext requestContext; + private final Provider queryProvider; private final MergeQueue mergeQueue; @Inject - ReloadSubmitQueueOp(final WorkQueue wq, final SchemaFactory sf, - final MergeQueue mq) { + ReloadSubmitQueueOp( + OneOffRequestContext rc, + WorkQueue wq, + Provider qp, + MergeQueue mq) { super(wq); - schema = sf; + requestContext = rc; + queryProvider = qp; mergeQueue = mq; } @Override public void run() { - final HashSet pending = new HashSet<>(); - try { - final ReviewDb c = schema.open(); - try { - for (final Change change : c.changes().allSubmitted()) { - pending.add(change.getDest()); + try (AutoCloseable ctx = requestContext.open()) { + HashSet pending = new HashSet<>(); + for (ChangeData cd : queryProvider.get().allSubmitted()) { + try { + pending.add(cd.change().getDest()); + } catch (OrmException e) { + log.error("Error reading submitted change", e); } - } finally { - c.close(); } - } catch (OrmException e) { - log.error("Cannot reload MergeQueue", e); - } - for (final Branch.NameKey branch : pending) { - mergeQueue.schedule(branch); + for (Branch.NameKey branch : pending) { + mergeQueue.schedule(branch); + } + } catch (Exception e) { + log.error("Cannot reload MergeQueue", e); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java index 6bcd92dccf..982f8973c0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java @@ -14,28 +14,27 @@ package com.google.gerrit.server.index; +import static com.google.gerrit.server.query.change.ChangeData.asChanges; + import com.google.common.collect.Lists; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; -import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.git.QueueProvider.QueueType; +import com.google.gerrit.server.query.change.InternalChangeQuery; +import com.google.gerrit.server.util.ManualRequestContext; +import com.google.gerrit.server.util.OneOffRequestContext; import com.google.gerrit.server.util.RequestContext; -import com.google.gerrit.server.util.ThreadLocalRequestContext; import com.google.gwtorm.server.OrmException; -import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; import com.google.inject.Provider; -import com.google.inject.util.Providers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,24 +47,21 @@ public class ReindexAfterUpdate implements GitReferenceUpdatedListener { private static final Logger log = LoggerFactory .getLogger(ReindexAfterUpdate.class); - private final ThreadLocalRequestContext tl; - private final SchemaFactory schemaFactory; - private final IdentifiedUser.GenericFactory userFactory; + private final OneOffRequestContext requestContext; + private final Provider queryProvider; private final ChangeIndexer.Factory indexerFactory; private final IndexCollection indexes; private final ListeningExecutorService executor; @Inject ReindexAfterUpdate( - ThreadLocalRequestContext tl, - SchemaFactory schemaFactory, - IdentifiedUser.GenericFactory userFactory, + OneOffRequestContext requestContext, + Provider queryProvider, ChangeIndexer.Factory indexerFactory, IndexCollection indexes, @IndexExecutor(QueueType.BATCH) ListeningExecutorService executor) { - this.tl = tl; - this.schemaFactory = schemaFactory; - this.userFactory = userFactory; + this.requestContext = requestContext; + this.queryProvider = queryProvider; this.indexerFactory = indexerFactory; this.indexes = indexes; this.executor = executor; @@ -81,8 +77,7 @@ public class ReindexAfterUpdate implements GitReferenceUpdatedListener { List> result = Lists.newArrayListWithCapacity(changes.size()); for (Change c : changes) { - result.add(executor.submit( - new Index(event, c.getOwner(), c.getId()))); + result.add(executor.submit(new Index(event, c.getId()))); } return Futures.allAsList(result); } @@ -90,7 +85,6 @@ public class ReindexAfterUpdate implements GitReferenceUpdatedListener { } private abstract class Task implements Callable { - protected ReviewDb db; protected Event event; protected Task(Event event) { @@ -99,20 +93,15 @@ public class ReindexAfterUpdate implements GitReferenceUpdatedListener { @Override public final V call() throws Exception { - try { - db = schemaFactory.open(); - return impl(); + try (ManualRequestContext ctx = requestContext.open()) { + return impl(ctx); } catch (Exception e) { log.error("Failed to reindex changes after " + event, e); throw e; - } finally { - if (db != null) { - db.close(); - } } } - protected abstract V impl() throws Exception; + protected abstract V impl(RequestContext ctx) throws Exception; } private class GetChanges extends Task> { @@ -121,49 +110,33 @@ public class ReindexAfterUpdate implements GitReferenceUpdatedListener { } @Override - protected List impl() throws OrmException { + protected List impl(RequestContext ctx) throws OrmException { String ref = event.getRefName(); Project.NameKey project = new Project.NameKey(event.getProjectName()); if (ref.equals(RefNames.REFS_CONFIG)) { - return db.changes().byProjectOpenAll(project).toList(); + return asChanges(queryProvider.get().byProjectOpen(project)); } else { - return db.changes().byBranchOpenAll(new Branch.NameKey(project, ref)) - .toList(); + return asChanges(queryProvider.get().byBranchOpen( + new Branch.NameKey(project, ref))); } } } private class Index extends Task { - private final Account.Id user; private final Change.Id id; - Index(Event event, Account.Id user, Change.Id id) { + Index(Event event, Change.Id id) { super(event); - this.user = user; this.id = id; } @Override - protected Void impl() throws OrmException, IOException { - RequestContext context = new RequestContext() { - @Override - public CurrentUser getCurrentUser() { - return userFactory.create(user); - } - - @Override - public Provider getReviewDbProvider() { - return Providers.of(db); - } - }; - RequestContext old = tl.setContext(context); - try { - Change c = db.changes().get(id); - indexerFactory.create(executor, indexes).index(db, c); - return null; - } finally { - tl.setContext(old); - } + protected Void impl(RequestContext ctx) throws OrmException, IOException { + // Reload change, as some time may have passed since GetChanges. + ReviewDb db = ctx.getReviewDbProvider().get(); + Change c = db.changes().get(id); + indexerFactory.create(executor, indexes).index(db, c); + return null; } } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java index 8b029ddad5..d5c34bcdc0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java @@ -21,6 +21,7 @@ import static org.eclipse.jgit.lib.RefDatabase.ALL; import com.google.common.base.Stopwatch; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -31,6 +32,7 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.git.GitRepositoryManager; @@ -39,6 +41,7 @@ import com.google.gerrit.server.git.MultiProgressMonitor; import com.google.gerrit.server.git.MultiProgressMonitor.Task; import com.google.gerrit.server.patch.PatchListLoader; import com.google.gerrit.server.query.change.ChangeData; +import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.SchemaFactory; import com.google.inject.Inject; @@ -65,9 +68,11 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -237,7 +242,7 @@ public class SiteIndexer { repo = repoManager.openRepository(project); Map refs = repo.getRefDatabase().getRefs(ALL); db = schemaFactory.open(); - for (Change c : db.changes().byProject(project)) { + for (Change c : scanChanges(db, repo)) { Ref r = refs.get(c.currentPatchSetId().toRefName()); if (r != null) { byId.put(r.getObjectId(), changeDataFactory.create(db, c)); @@ -268,6 +273,26 @@ public class SiteIndexer { }; } + private static List scanChanges(ReviewDb db, Repository repo) + throws OrmException, IOException { + Map refs = + repo.getRefDatabase().getRefs(RefNames.REFS_CHANGES); + Set ids = new LinkedHashSet<>(); + for (Ref r : refs.values()) { + Change.Id id = Change.Id.fromRef(r.getName()); + if (id != null) { + ids.add(id); + } + } + List changes = new ArrayList<>(ids.size()); + // A batch size of N may overload get(Iterable), so use something smaller, + // but still >1. + for (List batch : Iterables.partition(ids, 30)) { + Iterables.addAll(changes, db.changes().get(batch)); + } + return changes; + } + private static class ProjectIndexer implements Callable { private final ChangeIndexer indexer; private final ThreeWayMergeStrategy mergeStrategy; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java index 162a97dea5..9a714f86e8 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java @@ -25,6 +25,7 @@ import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.project.DeleteBranch.Input; +import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.ResultSet; import com.google.inject.Inject; @@ -48,16 +49,19 @@ public class DeleteBranch implements RestModifyView{ private final Provider identifiedUser; private final GitRepositoryManager repoManager; private final Provider dbProvider; + private final Provider queryProvider; private final GitReferenceUpdated referenceUpdated; private final ChangeHooks hooks; @Inject DeleteBranch(Provider identifiedUser, GitRepositoryManager repoManager, Provider dbProvider, + Provider queryProvider, GitReferenceUpdated referenceUpdated, ChangeHooks hooks) { this.identifiedUser = identifiedUser; this.repoManager = repoManager; this.dbProvider = dbProvider; + this.queryProvider = queryProvider; this.referenceUpdated = referenceUpdated; this.hooks = hooks; } @@ -68,8 +72,8 @@ public class DeleteBranch implements RestModifyView{ if (!rsrc.getControl().controlForRef(rsrc.getBranchKey()).canDelete()) { throw new AuthException("Cannot delete branch"); } - if (dbProvider.get().changes().byBranchOpenAll(rsrc.getBranchKey()) - .iterator().hasNext()) { + if (!queryProvider.get().setLimit(1) + .byBranchOpen(rsrc.getBranchKey()).isEmpty()) { throw new ResourceConflictException("branch " + rsrc.getBranchKey() + " has open changes"); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java index dcb492450f..b3a0a9a5c1 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java @@ -75,6 +75,24 @@ import java.util.List; import java.util.Map; public class ChangeData { + public static List asChanges(List changeDatas) + throws OrmException { + List result = new ArrayList<>(changeDatas.size()); + for (ChangeData cd : changeDatas) { + result.add(cd.change()); + } + return result; + } + + public static Map asMap(List changes) { + Map result = + Maps.newHashMapWithExpectedSize(changes.size()); + for (ChangeData cd : changes) { + result.put(cd.getId(), cd); + } + return result; + } + public static void ensureChangeLoaded(Iterable changes) throws OrmException { Map missing = Maps.newHashMap(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java index 40ae816da7..7a0609a513 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java @@ -17,6 +17,8 @@ package com.google.gerrit.server.query.change; import static com.google.gerrit.server.query.Predicate.and; import static com.google.gerrit.server.query.change.ChangeStatusPredicate.open; +import com.google.gerrit.reviewdb.client.Branch; +import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.query.Predicate; import com.google.gerrit.server.query.QueryParseException; @@ -25,17 +27,36 @@ import com.google.inject.Inject; import java.util.List; -/** Execute a single query over changes, for use by Gerrit internals. */ +/** + * Execute a single query over changes, for use by Gerrit internals. + *

+ * By default, visibility of returned changes is not enforced (unlike in {@link + * QueryProcessor}). The methods in this class are not typically used by + * user-facing paths, but rather by internal callers that need to process all + * matching results. + */ public class InternalChangeQuery { - private static Predicate project(Project.NameKey projectName) { - return new ProjectPredicate(projectName.get()); + private static Predicate ref(Branch.NameKey branch) { + return new RefPredicate(branch.get()); + } + + private static Predicate change(Change.Key key) { + return new ChangeIdPredicate(key.get()); + } + + private static Predicate project(Project.NameKey project) { + return new ProjectPredicate(project.get()); + } + + private static Predicate status(Change.Status status) { + return new ChangeStatusPredicate(status); } private final QueryProcessor qp; @Inject InternalChangeQuery(QueryProcessor queryProcessor) { - qp = queryProcessor; + qp = queryProcessor.enforceVisibility(false); } public InternalChangeQuery setLimit(int n) { @@ -43,9 +64,47 @@ public class InternalChangeQuery { return this; } - public List byProjectOpen(Project.NameKey projectName) + public InternalChangeQuery enforceVisibility(boolean enforce) { + qp.enforceVisibility(enforce); + return this; + } + + + public List byBranchKey(Branch.NameKey branch, Change.Key key) throws OrmException { - return query(and(project(projectName), open())); + return query(and( + ref(branch), + project(branch.getParentKey()), + change(key))); + } + + public List byProject(Project.NameKey project) + throws OrmException { + return query(project(project)); + } + + public List submitted(Branch.NameKey branch) throws OrmException { + return query(and( + ref(branch), + project(branch.getParentKey()), + status(Change.Status.SUBMITTED))); + } + + public List allSubmitted() throws OrmException { + return query(status(Change.Status.SUBMITTED)); + } + + public List byBranchOpen(Branch.NameKey branch) + throws OrmException { + return query(and( + ref(branch), + project(branch.getParentKey()), + open())); + } + + public List byProjectOpen(Project.NameKey project) + throws OrmException { + return query(and(project(project), open())); } private List query(Predicate p) throws OrmException { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/ManualRequestContext.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/ManualRequestContext.java new file mode 100644 index 0000000000..0ef4a18452 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/ManualRequestContext.java @@ -0,0 +1,57 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.util; + +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.CurrentUser; +import com.google.gwtorm.server.OrmException; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Provider; +import com.google.inject.util.Providers; + +/** + * Closeable version of a {@link RequestContext} with manually-specified + * providers. + */ +public class ManualRequestContext implements RequestContext, AutoCloseable { + private final CurrentUser user; + private final Provider db; + private final ThreadLocalRequestContext requestContext; + private final RequestContext old; + + ManualRequestContext(CurrentUser user, SchemaFactory schemaFactory, + ThreadLocalRequestContext requestContext) throws OrmException { + this.user = user; + this.db = Providers.of(schemaFactory.open()); + this.requestContext = requestContext; + old = requestContext.setContext(this); + } + + @Override + public CurrentUser getCurrentUser() { + return user; + } + + @Override + public Provider getReviewDbProvider() { + return db; + } + + @Override + public void close() { + requestContext.setContext(old); + db.get().close(); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/OneOffRequestContext.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/OneOffRequestContext.java new file mode 100644 index 0000000000..6feb182ddf --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/OneOffRequestContext.java @@ -0,0 +1,51 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.util; + +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.InternalUser; +import com.google.gwtorm.server.OrmException; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Helper to create one-off request contexts. + *

+ * Each call to {@link #open()} opens a new {@link ReviewDb}, so this class + * should only be used in a bounded try/finally block. + *

+ * The user in the request context is {@link InternalUser}. + */ +@Singleton +public class OneOffRequestContext { + private final InternalUser.Factory userFactory; + private final SchemaFactory schemaFactory; + private final ThreadLocalRequestContext requestContext; + + @Inject + OneOffRequestContext(InternalUser.Factory userFactory, + SchemaFactory schemaFactory, + ThreadLocalRequestContext requestContext) { + this.userFactory = userFactory; + this.schemaFactory = schemaFactory; + this.requestContext = requestContext; + } + + public ManualRequestContext open() throws OrmException { + return new ManualRequestContext(userFactory.create(), + schemaFactory, requestContext); + } +} diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java index c59381e616..e75c1c8ddf 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java @@ -21,6 +21,7 @@ import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.RevId; import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.change.ChangesCollection; import com.google.gerrit.server.change.DeleteReviewer; @@ -29,7 +30,6 @@ import com.google.gerrit.server.change.ReviewerResource; import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.ProjectControl; -import com.google.gerrit.server.CurrentUser; import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.SshCommand; import com.google.gwtorm.server.OrmException;