Add separate field for exact commit search
Index implementations (including both Lucene and the googlesource.com index) cannot really implement prefix search efficiently: they need to iterate over all tokens in the inverted index with a given prefix. When we have a full commit SHA-1, this indirection is wasteful, particularly in cases like byCommitsOnBranchNotMerged where there might be hundreds or thousands of terms. Add a separate field that indexes the full commit SHA-1 to make these specific queries more efficient. There is no need for a separate query operator; we can just choose the predicate based on the length of the input string. Change-Id: Ie26d58ab82e9efaf2c32d352cf285a2a1d59a8d8
This commit is contained in:
@@ -303,22 +303,37 @@ public class ChangeField {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Commit id of any PatchSet on the change */
|
/** Commit ID of any patch set on the change, using prefix match. */
|
||||||
public static final FieldDef<ChangeData, Iterable<String>> COMMIT =
|
public static final FieldDef<ChangeData, Iterable<String>> COMMIT =
|
||||||
new FieldDef.Repeatable<ChangeData, String>(
|
new FieldDef.Repeatable<ChangeData, String>(
|
||||||
ChangeQueryBuilder.FIELD_COMMIT, FieldType.PREFIX, false) {
|
ChangeQueryBuilder.FIELD_COMMIT, FieldType.PREFIX, false) {
|
||||||
@Override
|
@Override
|
||||||
public Iterable<String> get(ChangeData input, FillArgs args)
|
public Iterable<String> get(ChangeData input, FillArgs args)
|
||||||
throws OrmException {
|
throws OrmException {
|
||||||
|
return getRevisions(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Commit ID of any patch set on the change, using exact match. */
|
||||||
|
public static final FieldDef<ChangeData, Iterable<String>> EXACT_COMMIT =
|
||||||
|
new FieldDef.Repeatable<ChangeData, String>(
|
||||||
|
"exactcommit", FieldType.EXACT, false) {
|
||||||
|
@Override
|
||||||
|
public Iterable<String> get(ChangeData input, FillArgs args)
|
||||||
|
throws OrmException {
|
||||||
|
return getRevisions(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static Set<String> getRevisions(ChangeData cd) throws OrmException {
|
||||||
Set<String> revisions = Sets.newHashSet();
|
Set<String> revisions = Sets.newHashSet();
|
||||||
for (PatchSet ps : input.patchSets()) {
|
for (PatchSet ps : cd.patchSets()) {
|
||||||
if (ps.getRevision() != null) {
|
if (ps.getRevision() != null) {
|
||||||
revisions.add(ps.getRevision().get());
|
revisions.add(ps.getRevision().get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return revisions;
|
return revisions;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/** Tracking id extracted from a footer. */
|
/** Tracking id extracted from a footer. */
|
||||||
public static final FieldDef<ChangeData, Iterable<String>> TR =
|
public static final FieldDef<ChangeData, Iterable<String>> TR =
|
||||||
|
@@ -241,6 +241,7 @@ public class ChangeSchemas {
|
|||||||
ChangeField.EDITBY,
|
ChangeField.EDITBY,
|
||||||
ChangeField.REVIEWEDBY);
|
ChangeField.REVIEWEDBY);
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
static final Schema<ChangeData> V21 = schema(
|
static final Schema<ChangeData> V21 = schema(
|
||||||
ChangeField.LEGACY_ID,
|
ChangeField.LEGACY_ID,
|
||||||
ChangeField.ID,
|
ChangeField.ID,
|
||||||
@@ -273,6 +274,40 @@ public class ChangeSchemas {
|
|||||||
ChangeField.EDITBY,
|
ChangeField.EDITBY,
|
||||||
ChangeField.REVIEWEDBY);
|
ChangeField.REVIEWEDBY);
|
||||||
|
|
||||||
|
static final Schema<ChangeData> V22 = schema(
|
||||||
|
ChangeField.LEGACY_ID,
|
||||||
|
ChangeField.ID,
|
||||||
|
ChangeField.STATUS,
|
||||||
|
ChangeField.PROJECT,
|
||||||
|
ChangeField.PROJECTS,
|
||||||
|
ChangeField.REF,
|
||||||
|
ChangeField.EXACT_TOPIC,
|
||||||
|
ChangeField.FUZZY_TOPIC,
|
||||||
|
ChangeField.UPDATED,
|
||||||
|
ChangeField.FILE_PART,
|
||||||
|
ChangeField.PATH,
|
||||||
|
ChangeField.OWNER,
|
||||||
|
ChangeField.REVIEWER,
|
||||||
|
ChangeField.COMMIT,
|
||||||
|
ChangeField.TR,
|
||||||
|
ChangeField.LABEL,
|
||||||
|
ChangeField.COMMIT_MESSAGE,
|
||||||
|
ChangeField.COMMENT,
|
||||||
|
ChangeField.CHANGE,
|
||||||
|
ChangeField.APPROVAL,
|
||||||
|
ChangeField.MERGEABLE,
|
||||||
|
ChangeField.ADDED,
|
||||||
|
ChangeField.DELETED,
|
||||||
|
ChangeField.DELTA,
|
||||||
|
ChangeField.HASHTAG,
|
||||||
|
ChangeField.COMMENTBY,
|
||||||
|
ChangeField.PATCH_SET,
|
||||||
|
ChangeField.GROUP,
|
||||||
|
ChangeField.EDITBY,
|
||||||
|
ChangeField.REVIEWEDBY,
|
||||||
|
ChangeField.EXACT_COMMIT);
|
||||||
|
|
||||||
|
|
||||||
private static Schema<ChangeData> schema(Collection<FieldDef<ChangeData, ?>> fields) {
|
private static Schema<ChangeData> schema(Collection<FieldDef<ChangeData, ?>> fields) {
|
||||||
return new Schema<>(ImmutableList.copyOf(fields));
|
return new Schema<>(ImmutableList.copyOf(fields));
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,8 @@ import org.eclipse.jgit.errors.ConfigInvalidException;
|
|||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -431,7 +433,10 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
public Predicate<ChangeData> commit(String id) {
|
public Predicate<ChangeData> commit(String id) {
|
||||||
return new CommitPredicate(AbbreviatedObjectId.fromString(id));
|
if (id.length() == Constants.OBJECT_ID_STRING_LENGTH) {
|
||||||
|
return new ExactCommitPredicate(ObjectId.fromString(id));
|
||||||
|
}
|
||||||
|
return new CommitPrefixPredicate(AbbreviatedObjectId.fromString(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operator
|
@Operator
|
||||||
|
@@ -22,10 +22,10 @@ import com.google.gwtorm.server.OrmException;
|
|||||||
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
class CommitPredicate extends IndexPredicate<ChangeData> {
|
class CommitPrefixPredicate extends IndexPredicate<ChangeData> {
|
||||||
private final AbbreviatedObjectId abbrevId;
|
private final AbbreviatedObjectId abbrevId;
|
||||||
|
|
||||||
CommitPredicate(AbbreviatedObjectId id) {
|
CommitPrefixPredicate(AbbreviatedObjectId id) {
|
||||||
super(ChangeField.COMMIT, id.name());
|
super(ChangeField.COMMIT, id.name());
|
||||||
this.abbrevId = id;
|
this.abbrevId = id;
|
||||||
}
|
}
|
@@ -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.query.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
|
import com.google.gerrit.server.index.ChangeField;
|
||||||
|
import com.google.gerrit.server.index.IndexPredicate;
|
||||||
|
import com.google.gwtorm.server.OrmException;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
class ExactCommitPredicate extends IndexPredicate<ChangeData> {
|
||||||
|
private final ObjectId id;
|
||||||
|
|
||||||
|
ExactCommitPredicate(ObjectId id) {
|
||||||
|
super(ChangeField.COMMIT, id.name());
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(final ChangeData object) throws OrmException {
|
||||||
|
String idStr = id.name();
|
||||||
|
for (PatchSet p : object.patchSets()) {
|
||||||
|
if (p.getRevision() != null && p.getRevision().get() != null) {
|
||||||
|
if (Objects.equals(p.getRevision().get(), idStr)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCost() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@@ -35,7 +35,6 @@ import com.google.gerrit.server.query.QueryParseException;
|
|||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.AbbreviatedObjectId;
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -67,8 +66,8 @@ public class InternalChangeQuery {
|
|||||||
return new ChangeStatusPredicate(status);
|
return new ChangeStatusPredicate(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Predicate<ChangeData> commit(AbbreviatedObjectId id) {
|
private static Predicate<ChangeData> commit(ObjectId id) {
|
||||||
return new CommitPredicate(id);
|
return new ExactCommitPredicate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final QueryProcessor qp;
|
private final QueryProcessor qp;
|
||||||
@@ -130,7 +129,7 @@ public class InternalChangeQuery {
|
|||||||
List<String> hashes, int batchSize) throws OrmException {
|
List<String> hashes, int batchSize) throws OrmException {
|
||||||
List<Predicate<ChangeData>> commits = new ArrayList<>(hashes.size());
|
List<Predicate<ChangeData>> commits = new ArrayList<>(hashes.size());
|
||||||
for (String s : hashes) {
|
for (String s : hashes) {
|
||||||
commits.add(commit(AbbreviatedObjectId.fromString(s)));
|
commits.add(commit(ObjectId.fromString(s)));
|
||||||
}
|
}
|
||||||
int numBatches = (hashes.size() / batchSize) + 1;
|
int numBatches = (hashes.size() / batchSize) + 1;
|
||||||
List<Predicate<ChangeData>> queries = new ArrayList<>(numBatches);
|
List<Predicate<ChangeData>> queries = new ArrayList<>(numBatches);
|
||||||
@@ -164,12 +163,8 @@ public class InternalChangeQuery {
|
|||||||
return query(and(new ExactTopicPredicate(schema(indexes), topic), open()));
|
return query(and(new ExactTopicPredicate(schema(indexes), topic), open()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ChangeData> byCommitPrefix(String prefix) throws OrmException {
|
|
||||||
return query(commit(AbbreviatedObjectId.fromString(prefix)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ChangeData> byCommit(ObjectId id) throws OrmException {
|
public List<ChangeData> byCommit(ObjectId id) throws OrmException {
|
||||||
return query(commit(AbbreviatedObjectId.fromObjectId(id)));
|
return query(commit(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ChangeData> byProjectGroups(Project.NameKey project,
|
public List<ChangeData> byProjectGroups(Project.NameKey project,
|
||||||
|
Reference in New Issue
Block a user