Merge "Fix reading changes from index for older schema versions"

This commit is contained in:
Dave Borowitz
2016-02-10 20:16:41 +00:00
committed by Gerrit Code Review
4 changed files with 105 additions and 24 deletions

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.lucene;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.gerrit.server.git.QueueProvider.QueueType.INTERACTIVE;
import static com.google.gerrit.server.index.ChangeField.CHANGE;
import static com.google.gerrit.server.index.ChangeField.LEGACY_ID;
import static com.google.gerrit.server.index.ChangeField.PROJECT;
import static com.google.gerrit.server.index.IndexRewriter.CLOSED_STATUSES;
@@ -431,18 +432,30 @@ public class LuceneChangeIndex implements ChangeIndex {
}
private Set<String> fields(QueryOptions opts) {
if (schemaHasRequestedField(ChangeField.LEGACY_ID, opts.fields())
|| schemaHasRequestedField(ChangeField.CHANGE, opts.fields())) {
return opts.fields();
// Ensure we request enough fields to construct a ChangeData.
Set<String> fs = opts.fields();
if (fs.contains(CHANGE.getName())) {
// A Change is always sufficient.
return fs;
}
// Request the numeric ID field even if the caller did not request it,
// otherwise we can't actually construct a ChangeData.
return Sets.union(opts.fields(), ImmutableSet.of(LEGACY_ID.getName()));
}
private boolean schemaHasRequestedField(FieldDef<ChangeData, ?> field,
Set<String> requested) {
return schema.hasField(field) && requested.contains(field.getName());
if (!schema.hasField(PROJECT)) {
// Schema is not new enough to have project field. Ensure we have ID
// field, and call createOnlyWhenNotedbDisabled from toChangeData below.
if (fs.contains(LEGACY_ID.getName())) {
return fs;
} else {
return Sets.union(fs, ImmutableSet.of(LEGACY_ID.getName()));
}
}
// New enough schema to have project field, so ensure that is requested.
if (fs.contains(PROJECT.getName()) && fs.contains(LEGACY_ID.getName())) {
return fs;
} else {
return Sets.union(fs,
ImmutableSet.of(LEGACY_ID.getName(), PROJECT.getName()));
}
}
private ChangeData toChangeData(Document doc, Set<String> fields,
@@ -455,10 +468,17 @@ public class LuceneChangeIndex implements ChangeIndex {
cd = changeDataFactory.create(db.get(),
ChangeProtoField.CODEC.decode(cb.bytes, cb.offset, cb.length));
} else {
int id = doc.getField(idFieldName).numericValue().intValue();
Project.NameKey project =
new Project.NameKey(doc.getField(PROJECT.getName()).stringValue());
cd = changeDataFactory.create(db.get(), project, new Change.Id(id));
Change.Id id =
new Change.Id(doc.getField(idFieldName).numericValue().intValue());
IndexableField project = doc.getField(PROJECT.getName());
if (project == null) {
// Old schema without project field: we can safely assume notedb is
// disabled.
cd = changeDataFactory.createOnlyWhenNotedbDisabled(db.get(), id);
} else {
cd = changeDataFactory.create(
db.get(), new Project.NameKey(project.stringValue()), id);
}
}
if (fields.contains(PATCH_SET_FIELD)) {

View File

@@ -381,7 +381,7 @@ public class ChangeJson {
// If any problems were fixed, the ChangeData needs to be reloaded.
for (ProblemInfo p : out.problems) {
if (p.status == ProblemInfo.Status.FIXED) {
cd = changeDataFactory.create(cd.db(), cd.getProject(), cd.getId());
cd = changeDataFactory.create(cd.db(), cd.project(), cd.getId());
break;
}
}

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.notedb;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.GERRIT_PLACEHOLDER_HOST;
import com.google.common.annotations.VisibleForTesting;
@@ -134,6 +135,16 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
return new ChangeNotes(repoManager, migration, allUsersProvider,
change.getProject(), change).load();
}
// TODO(dborowitz): Remove when deleting index schemas <27.
public ChangeNotes createFromIdOnlyWhenNotedbDisabled(
ReviewDb db, Change.Id changeId) throws OrmException {
checkState(!migration.readChanges(), "do not call"
+ " createFromIdOnlyWhenNotedbDisabled when notedb is enabled");
Change change = db.changes().get(changeId);
return new ChangeNotes(repoManager, migration, allUsersProvider,
change.getProject(), change).load();
}
}
private final Project.NameKey project;

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.query.change;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.ApprovalsUtil.sortApprovals;
import com.google.auto.value.AutoValue;
@@ -275,6 +276,9 @@ public class ChangeData {
ChangeData create(ReviewDb db, Project.NameKey project, Change.Id id);
ChangeData create(ReviewDb db, Change c);
ChangeData create(ReviewDb db, ChangeControl c);
// TODO(dborowitz): Remove when deleting index schemas <27.
ChangeData createOnlyWhenNotedbDisabled(ReviewDb db, Change.Id id);
}
/**
@@ -309,8 +313,8 @@ public class ChangeData {
private final NotesMigration notesMigration;
private final MergeabilityCache mergeabilityCache;
private final Change.Id legacyId;
private final Project.NameKey project;
private ChangeDataSource returnedBySource;
private Project.NameKey project;
private Change change;
private ChangeNotes notes;
private String commitMessage;
@@ -444,6 +448,43 @@ public class ChangeData {
project = notes.getProjectName();
}
@AssistedInject
private ChangeData(
GitRepositoryManager repoManager,
ChangeControl.GenericFactory changeControlFactory,
IdentifiedUser.GenericFactory userFactory,
ProjectCache projectCache,
MergeUtil.Factory mergeUtilFactory,
ChangeNotes.Factory notesFactory,
ApprovalsUtil approvalsUtil,
ChangeMessagesUtil cmUtil,
PatchLineCommentsUtil plcUtil,
PatchSetUtil psUtil,
PatchListCache patchListCache,
NotesMigration notesMigration,
MergeabilityCache mergeabilityCache,
@Assisted ReviewDb db,
@Assisted Change.Id id) {
checkState(!notesMigration.readChanges(),
"do not call createOnlyWhenNotedbDisabled when notedb is enabled");
this.db = db;
this.repoManager = repoManager;
this.changeControlFactory = changeControlFactory;
this.userFactory = userFactory;
this.projectCache = projectCache;
this.mergeUtilFactory = mergeUtilFactory;
this.notesFactory = notesFactory;
this.approvalsUtil = approvalsUtil;
this.cmUtil = cmUtil;
this.plcUtil = plcUtil;
this.psUtil = psUtil;
this.patchListCache = patchListCache;
this.notesMigration = notesMigration;
this.mergeabilityCache = mergeabilityCache;
this.legacyId = id;
this.project = null;
}
public ReviewDb db() {
return db;
}
@@ -545,7 +586,12 @@ public class ChangeData {
return legacyId;
}
public Project.NameKey getProject() {
public Project.NameKey project() throws OrmException {
if (project == null) {
checkState(!notesMigration.readChanges(), "should not have created "
+ " ChangeData without a project when notedb is enabled");
project = change().getProject();
}
return project;
}
@@ -580,7 +626,7 @@ public class ChangeData {
changeControl = changeControlFactory.controlFor(db, change, user);
} else {
changeControl =
changeControlFactory.controlFor(db, project, legacyId, user);
changeControlFactory.controlFor(db, project(), legacyId, user);
}
} catch (NoSuchChangeException e) {
throw new OrmException(e);
@@ -605,7 +651,11 @@ public class ChangeData {
}
public Change reloadChange() throws OrmException {
notes = notesFactory.create(db, project, legacyId);
if (project == null) {
notes = notesFactory.createFromIdOnlyWhenNotedbDisabled(db, legacyId);
} else {
notes = notesFactory.create(db, project, legacyId);
}
change = notes.getChange();
if (change == null) {
throw new OrmException("Unable to load change " + legacyId);
@@ -615,7 +665,7 @@ public class ChangeData {
public ChangeNotes notes() throws OrmException {
if (notes == null) {
notes = notesFactory.create(db, project, legacyId);
notes = notesFactory.create(db, project(), legacyId);
}
return notes;
}
@@ -698,7 +748,7 @@ public class ChangeData {
return false;
}
String sha1 = ps.getRevision().get();
try (Repository repo = repoManager.openRepository(project);
try (Repository repo = repoManager.openRepository(project());
RevWalk walk = new RevWalk(repo)) {
RevCommit c = walk.parseCommit(ObjectId.fromString(sha1));
commitMessage = c.getFullMessage();
@@ -821,7 +871,7 @@ public class ChangeData {
if (ps == null || !changeControl().isPatchVisible(ps, db)) {
return null;
}
try (Repository repo = repoManager.openRepository(project)) {
try (Repository repo = repoManager.openRepository(project())) {
Ref ref = repo.getRefDatabase().exactRef(c.getDest().get());
SubmitTypeRecord str = submitTypeRecord();
if (!str.isOk()) {
@@ -830,7 +880,7 @@ public class ChangeData {
return false;
}
String mergeStrategy = mergeUtilFactory
.create(projectCache.get(project))
.create(projectCache.get(project()))
.mergeStrategyName();
mergeable = mergeabilityCache.get(
ObjectId.fromString(ps.getRevision().get()),
@@ -851,7 +901,7 @@ public class ChangeData {
}
editsByUser = new HashSet<>();
Change.Id id = change.getId();
try (Repository repo = repoManager.openRepository(project)) {
try (Repository repo = repoManager.openRepository(project())) {
for (String ref
: repo.getRefDatabase().getRefs(RefNames.REFS_USERS).keySet()) {
if (Change.Id.fromEditRefPart(ref).equals(id)) {