Store PatchSets in secondary index

This serves two purposes, one for today, and one for the medium-term
future. In the short term, eagerly populating patch sets on search
results can help speed up submit rule evaluation, since any submit
rule depending on the list of paths requires looking up the patch set
SHA-1 in the PatchListCache. Looking ahead, we plan to serve related
changes results from the secondary index, which requires starting a
RevWalk from multiple changes' patch set SHA-1s.

Change-Id: I2fe841ae272e46db45231cda4d7a0299d1ca5a3a
This commit is contained in:
Dave Borowitz
2015-05-07 14:11:58 -07:00
parent 956b9cf4fd
commit d83709e1a6
4 changed files with 82 additions and 12 deletions

View File

@@ -31,7 +31,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -39,6 +39,7 @@ import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.index.ChangeField;
import com.google.gerrit.server.index.ChangeField.ChangeProtoField;
import com.google.gerrit.server.index.ChangeField.PatchSetApprovalProtoField;
import com.google.gerrit.server.index.ChangeField.PatchSetProtoField;
import com.google.gerrit.server.index.ChangeIndex;
import com.google.gerrit.server.index.FieldDef;
import com.google.gerrit.server.index.FieldDef.FillArgs;
@@ -51,6 +52,7 @@ import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeDataSource;
import com.google.gwtorm.protobuf.ProtobufCodec;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;
@@ -98,6 +100,7 @@ import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -128,12 +131,13 @@ public class LuceneChangeIndex implements ChangeIndex {
private static final String ID_SORT_FIELD =
sortFieldName(ChangeField.LEGACY_ID);
private static final String MERGEABLE_FIELD = ChangeField.MERGEABLE.getName();
private static final String PATCH_SET_FIELD = ChangeField.PATCH_SET.getName();
private static final String UPDATED_SORT_FIELD =
sortFieldName(ChangeField.UPDATED);
private static final ImmutableSet<String> FIELDS = ImmutableSet.of(
ADDED_FIELD, APPROVAL_FIELD, CHANGE_FIELD, DELETED_FIELD, ID_FIELD,
MERGEABLE_FIELD);
MERGEABLE_FIELD, PATCH_SET_FIELD);
private static final Map<String, String> CUSTOM_CHAR_MAPPING = ImmutableMap.of(
"_", " ", ".", " ");
@@ -472,18 +476,19 @@ public class LuceneChangeIndex implements ChangeIndex {
cb.bytes, cb.offset, cb.length);
ChangeData cd = changeDataFactory.create(db.get(), change);
// Approvals.
BytesRef[] approvalsBytes = doc.getBinaryValues(APPROVAL_FIELD);
if (approvalsBytes != null) {
List<PatchSetApproval> approvals =
Lists.newArrayListWithCapacity(approvalsBytes.length);
for (BytesRef ab : approvalsBytes) {
approvals.add(PatchSetApprovalProtoField.CODEC.decode(
ab.bytes, ab.offset, ab.length));
}
cd.setCurrentApprovals(approvals);
// Patch sets.
List<PatchSet> patchSets =
decodeProtos(doc, PATCH_SET_FIELD, PatchSetProtoField.CODEC);
if (!patchSets.isEmpty()) {
// Will be an empty list for schemas prior to when this field was stored;
// this cannot be valid since a change needs at least one patch set.
cd.setPatchSets(patchSets);
}
// Approvals.
cd.setCurrentApprovals(
decodeProtos(doc, APPROVAL_FIELD, PatchSetApprovalProtoField.CODEC));
// Changed lines.
IndexableField added = doc.getField(ADDED_FIELD);
IndexableField deleted = doc.getField(DELETED_FIELD);
@@ -504,6 +509,19 @@ public class LuceneChangeIndex implements ChangeIndex {
return cd;
}
private static <T> List<T> decodeProtos(Document doc, String fieldName,
ProtobufCodec<T> codec) {
BytesRef[] bytesRefs = doc.getBinaryValues(fieldName);
if (bytesRefs.length == 0) {
return Collections.emptyList();
}
List<T> result = new ArrayList<>(bytesRefs.length);
for (BytesRef r : bytesRefs) {
result.add(codec.decode(r.bytes, r.offset, r.length));
}
return result;
}
private Document toDocument(ChangeData cd) {
Document result = new Document();
for (Values<ChangeData> vs : schema.buildFields(cd, fillArgs)) {