Store users that starred a change in change index

Within notedb each change that is starred by a user is tracked by a
refs/starred-changes/XX/YYYY/ZZZZ ref in the All-Users meta repository
where XX/YYYY is the sharded change ID and ZZZZ is the account ID.
With this storage format finding all users that have starred a
change is cheap because we just need to list all refs that have
refs/starred-changes/XX/YYYY/ as prefix and looking up refs with a
prefix that ends on '/' is optimized in jgit. However to find all
changes that were starred by a user we must scan the complete
refs/starred-changes/ namespace and check which of the refs end with
the account ID. This results in bad performance when there are many
starred changes. Having the users that starred a change stored in the
change index makes this lookup cheap.

Looking up all changes that were starred by a user is needed for
supporting the "is:starred" query operator and for populating the
"starred" field in ChangeInfo.

Change-Id: Iecc9ca8ef133b0d0f86f1471b9ed31be78a43f6c
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2016-04-13 14:33:29 +02:00
parent dfe73dc408
commit 8be51b8a57
18 changed files with 280 additions and 88 deletions

View File

@@ -72,6 +72,16 @@ public class SchemaUtil {
return new Schema<>(ImmutableList.copyOf(fields));
}
@SafeVarargs
public static <V> Schema<V> schema(Schema<V> schema,
FieldDef<V, ?>... moreFields) {
return new Schema<>(
new ImmutableList.Builder<FieldDef<V, ?>>()
.addAll(schema.getFields().values())
.addAll(ImmutableList.copyOf(moreFields))
.build());
}
@SafeVarargs
public static <V> Schema<V> schema(FieldDef<V, ?>... fields) {
return schema(ImmutableList.copyOf(fields));

View File

@@ -576,6 +576,23 @@ public class ChangeField {
}
};
/** Users who have starred this change. */
public static final FieldDef<ChangeData, Iterable<Integer>> STARREDBY =
new FieldDef.Repeatable<ChangeData, Integer>(
ChangeQueryBuilder.FIELD_STARREDBY, FieldType.INTEGER, true) {
@Override
public Iterable<Integer> get(ChangeData input, FillArgs args)
throws OrmException {
return Iterables.transform(input.starredBy(),
new Function<Account.Id, Integer>() {
@Override
public Integer apply(Account.Id accountId) {
return accountId.get();
}
});
}
};
/** Opaque group identifiers for this change's patch sets. */
public static final FieldDef<ChangeData, Iterable<String>> GROUP =
new FieldDef.Repeatable<ChangeData, String>(

View File

@@ -186,13 +186,25 @@ public class ChangeIndexer {
/**
* Synchronously index a change.
*
* @param change change to index.
* @param db review database.
* @param change change to index.
*/
public void index(ReviewDb db, Change change) throws IOException {
index(changeDataFactory.create(db, change));
}
/**
* Synchronously index a change.
*
* @param db review database.
* @param project the project to which the change belongs.
* @param changeId ID of the change to index.
*/
public void index(ReviewDb db, Project.NameKey project, Change.Id changeId)
throws IOException {
index(changeDataFactory.create(db, project, changeId));
}
/**
* Start deleting a change.
*

View File

@@ -96,8 +96,11 @@ public class ChangeSchemaDefinitions extends SchemaDefinitions<ChangeData> {
ChangeField.COMMITTER,
ChangeField.DRAFTBY);
@Deprecated
static final Schema<ChangeData> V27 = schema(V26.getFields().values());
static final Schema<ChangeData> V28 = schema(V27, ChangeField.STARREDBY);
public static final ChangeSchemaDefinitions INSTANCE =
new ChangeSchemaDefinitions();