ChangeJson: Use reviewedBy set for setting reviewed bit
Tweak the value of this field slightly to match the field we recently
started indexing.
Change-Id: Iaf4887fb1dafb3cae36e5a957f2d49abb1f54435
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 97169ab..4cd6ccf 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -294,8 +294,13 @@
[[reviewed]]
--
-* `REVIEWED`: include the `reviewed` field if the caller is
- authenticated and has commented on the current revision.
+* `REVIEWED`: include the `reviewed` field if all of the following are
+ true:
+ * the change is open
+ * the caller is authenticated
+ * the caller has commented on the change more recently than the last update
+ from the change owner, i.e. this change would show up in the results of
+ link:user-search.html#reviewedby[reviewedby:self].
--
[[web-links]]
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 26c3b37..c7a705f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -43,9 +43,7 @@
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -94,7 +92,6 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LabelNormalizer;
import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectCache;
@@ -128,9 +125,6 @@
public class ChangeJson {
private static final Logger log = LoggerFactory.getLogger(ChangeJson.class);
- private static final List<ChangeMessage> NO_MESSAGES =
- ImmutableList.of();
-
private final Provider<ReviewDb> db;
private final LabelNormalizer labelNormalizer;
private final Provider<CurrentUser> userProvider;
@@ -242,11 +236,7 @@
throws OrmException {
try {
accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
- Set<Change.Id> reviewed = Sets.newHashSet();
- if (has(REVIEWED)) {
- reviewed = loadReviewed(Collections.singleton(cd));
- }
- ChangeInfo res = toChangeInfo(cd, reviewed, limitToPsId);
+ ChangeInfo res = toChangeInfo(cd, limitToPsId);
accountLoader.fill();
return res;
} catch (PatchListNotAvailableException | OrmException | IOException
@@ -280,16 +270,15 @@
} else if (has(CURRENT_REVISION) || has(MESSAGES)) {
ChangeData.ensureCurrentPatchSetLoaded(all);
}
- Set<Change.Id> reviewed = Sets.newHashSet();
- if (has(REVIEWED)) {
- reviewed = loadReviewed(all);
+ if (has(REVIEWED) && userProvider.get().isIdentifiedUser()) {
+ ChangeData.ensureReviewedByLoadedForOpenChanges(all);
}
ChangeData.ensureCurrentApprovalsLoaded(all);
List<List<ChangeInfo>> res = Lists.newArrayListWithCapacity(in.size());
Map<Change.Id, ChangeInfo> out = Maps.newHashMap();
for (QueryResult r : in) {
- List<ChangeInfo> infos = toChangeInfo(out, r.changes(), reviewed);
+ List<ChangeInfo> infos = toChangeInfo(out, r.changes());
if (r.moreChanges()) {
infos.get(infos.size() - 1)._moreChanges = true;
}
@@ -304,13 +293,13 @@
}
private List<ChangeInfo> toChangeInfo(Map<Change.Id, ChangeInfo> out,
- List<ChangeData> changes, Set<Change.Id> reviewed) {
+ List<ChangeData> changes) {
List<ChangeInfo> info = Lists.newArrayListWithCapacity(changes.size());
for (ChangeData cd : changes) {
ChangeInfo i = out.get(cd.getId());
if (i == null) {
try {
- i = toChangeInfo(cd, reviewed, Optional.<PatchSet.Id> absent());
+ i = toChangeInfo(cd, Optional.<PatchSet.Id> absent());
} catch (PatchListNotAvailableException | OrmException | IOException
| RuntimeException e) {
if (has(CHECK)) {
@@ -354,7 +343,7 @@
return info;
}
- private ChangeInfo toChangeInfo(ChangeData cd, Set<Change.Id> reviewed,
+ private ChangeInfo toChangeInfo(ChangeData cd,
Optional<PatchSet.Id> limitToPsId)
throws PatchListNotAvailableException, OrmException, IOException {
ChangeInfo out = new ChangeInfo();
@@ -371,7 +360,8 @@
}
Change in = cd.change();
- ChangeControl ctl = cd.changeControl().forUser(userProvider.get());
+ CurrentUser user = userProvider.get();
+ ChangeControl ctl = cd.changeControl().forUser(user);
out.project = in.getProject().get();
out.branch = in.getDest().getShortName();
out.topic = in.getTopic();
@@ -392,12 +382,13 @@
out.created = in.getCreatedOn();
out.updated = in.getLastUpdatedOn();
out._number = in.getId().get();
- out.starred = userProvider.get().getStarredChanges().contains(in.getId())
+ out.starred = user.getStarredChanges().contains(in.getId())
? true
: null;
- out.reviewed = in.getStatus().isOpen()
- && has(REVIEWED)
- && reviewed.contains(cd.getId()) ? true : null;
+ if (in.getStatus().isOpen() && has(REVIEWED) && user.isIdentifiedUser()) {
+ Account.Id accountId = ((IdentifiedUser) user).getAccountId();
+ out.reviewed = cd.reviewedBy().contains(accountId) ? true : null;
+ }
out.labels = labelsFor(ctl, cd, has(LABELS), has(DETAILED_LABELS));
@@ -802,49 +793,6 @@
return result;
}
- private Set<Change.Id> loadReviewed(Iterable<ChangeData> all)
- throws OrmException {
- Set<Change.Id> reviewed = Sets.newHashSet();
- if (userProvider.get().isIdentifiedUser()) {
- Account.Id self = ((IdentifiedUser) userProvider.get()).getAccountId();
- List<Iterable<ChangeMessage>> m = new ArrayList<>(50);
- for (List<ChangeData> batch : Iterables.partition(all, 50)) {
- m.clear();
- for (ChangeData cd : batch) {
- PatchSet.Id ps = cd.change().currentPatchSetId();
- if (ps != null && cd.change().getStatus().isOpen()) {
- m.add(cmUtil.byPatchSet(db.get(), cd.notes(), ps));
- } else {
- m.add(NO_MESSAGES);
- }
- }
- for (int i = 0; i < m.size(); i++) {
- if (isChangeReviewed(self, batch.get(i), m.get(i))) {
- reviewed.add(batch.get(i).getId());
- }
- }
- }
- }
- return reviewed;
- }
-
- public static boolean isChangeReviewed(Account.Id self, ChangeData cd,
- Iterable<ChangeMessage> msgs) throws OrmException {
- // Sort messages to keep the most recent ones at the beginning.
- List<ChangeMessage> reversed = ChangeNotes.MESSAGE_BY_TIME.reverse()
- .sortedCopy(msgs);
-
- Account.Id changeOwnerId = cd.change().getOwner();
- for (ChangeMessage cm : reversed) {
- if (self.equals(cm.getAuthor())) {
- return true;
- } else if (changeOwnerId.equals(cm.getAuthor())) {
- return false;
- }
- }
- return false;
- }
-
private Map<String, RevisionInfo> revisions(ChangeControl ctl,
Map<PatchSet.Id, PatchSet> map)
throws PatchListNotAvailableException, OrmException, IOException {
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 ed29d92..33b7b26 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
@@ -179,6 +179,56 @@
}
}
+ public static void ensureMessagesLoaded(Iterable<ChangeData> changes)
+ throws OrmException {
+ ChangeData first = Iterables.getFirst(changes, null);
+ if (first == null) {
+ return;
+ } else if (first.notesMigration.readChanges()) {
+ for (ChangeData cd : changes) {
+ cd.messages();
+ }
+ return;
+ }
+
+ List<ResultSet<ChangeMessage>> results = new ArrayList<>(BATCH_SIZE);
+ for (List<ChangeData> batch : Iterables.partition(changes, BATCH_SIZE)) {
+ results.clear();
+ for (ChangeData cd : batch) {
+ if (cd.messages == null) {
+ PatchSet.Id psId = cd.change().currentPatchSetId();
+ results.add(cd.db.changeMessages().byPatchSet(psId));
+ } else {
+ results.add(null);
+ }
+ }
+ for (int i = 0; i < batch.size(); i++) {
+ ResultSet<ChangeMessage> result = results.get(i);
+ if (result != null) {
+ batch.get(i).messages = result.toList();
+ }
+ }
+ }
+ }
+
+ public static void ensureReviewedByLoadedForOpenChanges(
+ Iterable<ChangeData> changes) throws OrmException {
+ List<ChangeData> pending = new ArrayList<>();
+ for (ChangeData cd : changes) {
+ if (cd.reviewedBy == null && cd.change().getStatus().isOpen()) {
+ pending.add(cd);
+ }
+ }
+
+ if (!pending.isEmpty()) {
+ ensureAllPatchSetsLoaded(pending);
+ ensureMessagesLoaded(pending);
+ for (ChangeData cd : pending) {
+ cd.reviewedBy();
+ }
+ }
+ }
+
public interface Factory {
ChangeData create(ReviewDb db, Change.Id id);
ChangeData create(ReviewDb db, Change c);
@@ -718,6 +768,10 @@
return reviewedBy;
}
+ public void setReviewedBy(Set<Account.Id> reviewedBy) {
+ this.reviewedBy = reviewedBy;
+ }
+
@AutoValue
abstract static class ReviewedByEvent implements Comparable<ReviewedByEvent> {
private static ReviewedByEvent create(PatchSet ps) {