Return more structured result from ChangeRebuilder

Refactors ChangeRebuilder and NoteDbUpdateManager to return a new type
encapsulating both the new NoteDbChangeState (which is intentionally
not part of the original staged result) and the underlying staged
result with its possibly-not-yet-written NoteDb data.

Change-Id: I2ff014e9fe01910a2b77b1f5417f1f11dc84b610
This commit is contained in:
Dave Borowitz
2016-06-16 11:38:46 -04:00
parent 5d4830d449
commit 1635b5d6a4
10 changed files with 51 additions and 40 deletions

View File

@@ -44,7 +44,6 @@ import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate; import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.notedb.InsertedObject; import com.google.gerrit.server.notedb.InsertedObject;
import com.google.gerrit.server.notedb.NoteDbChangeState;
import com.google.gerrit.server.notedb.NoteDbUpdateManager; import com.google.gerrit.server.notedb.NoteDbUpdateManager;
import com.google.gerrit.server.notedb.NotesMigration; import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
@@ -874,7 +873,7 @@ public class BatchUpdate implements AutoCloseable {
updateManager.deleteChange(ctx.getChange().getId()); updateManager.deleteChange(ctx.getChange().getId());
} }
try { try {
NoteDbChangeState.applyDelta(ctx.getChange(), updateManager.stage()); updateManager.stageAndApplyDelta(ctx.getChange());
} catch (OrmConcurrencyException ex) { } catch (OrmConcurrencyException ex) {
// Refused to apply update because NoteDb was out of sync. Go ahead with // Refused to apply update because NoteDb was out of sync. Go ahead with
// this ReviewDb update; it's still out of sync, but this is no worse // this ReviewDb update; it's still out of sync, but this is no worse

View File

@@ -53,6 +53,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ReviewerSet; import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.git.RefCache; import com.google.gerrit.server.git.RefCache;
import com.google.gerrit.server.git.RepoRefCache; import com.google.gerrit.server.git.RepoRefCache;
import com.google.gerrit.server.notedb.NoteDbUpdateManager.Result;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
@@ -595,7 +596,9 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
try { try {
NoteDbChangeState newState; NoteDbChangeState newState;
try { try {
newState = args.rebuilder.get().rebuild(args.db.get(), getChangeId()); NoteDbUpdateManager.Result r =
args.rebuilder.get().rebuild(args.db.get(), getChangeId());
newState = r != null ? r.newState() : null;
repo.scanForRepoChanges(); repo.scanForRepoChanges();
} catch (IOException e) { } catch (IOException e) {
newState = recheckUpToDate(repo, e); newState = recheckUpToDate(repo, e);

View File

@@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.notedb.NoteDbUpdateManager.Result;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
@@ -37,11 +38,11 @@ public abstract class ChangeRebuilder {
this.schemaFactory = schemaFactory; this.schemaFactory = schemaFactory;
} }
public final ListenableFuture<NoteDbChangeState> rebuildAsync( public final ListenableFuture<Result> rebuildAsync(
final Change.Id id, ListeningExecutorService executor) { final Change.Id id, ListeningExecutorService executor) {
return executor.submit(new Callable<NoteDbChangeState>() { return executor.submit(new Callable<Result>() {
@Override @Override
public NoteDbChangeState call() throws Exception { public Result call() throws Exception {
try (ReviewDb db = schemaFactory.open()) { try (ReviewDb db = schemaFactory.open()) {
return rebuild(db, id); return rebuild(db, id);
} }
@@ -49,11 +50,11 @@ public abstract class ChangeRebuilder {
}); });
} }
public abstract NoteDbChangeState rebuild(ReviewDb db, Change.Id changeId) public abstract Result rebuild(ReviewDb db, Change.Id changeId)
throws NoSuchChangeException, IOException, OrmException, throws NoSuchChangeException, IOException, OrmException,
ConfigInvalidException; ConfigInvalidException;
public abstract NoteDbChangeState rebuild(NoteDbUpdateManager manager, public abstract Result rebuild(NoteDbUpdateManager manager,
ChangeBundle bundle) throws NoSuchChangeException, IOException, ChangeBundle bundle) throws NoSuchChangeException, IOException,
OrmException, ConfigInvalidException; OrmException, ConfigInvalidException;

View File

@@ -57,6 +57,7 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.config.AnonymousCowardName; import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.git.ChainedReceiveCommands; import com.google.gerrit.server.git.ChainedReceiveCommands;
import com.google.gerrit.server.notedb.NoteDbUpdateManager.OpenRepo; import com.google.gerrit.server.notedb.NoteDbUpdateManager.OpenRepo;
import com.google.gerrit.server.notedb.NoteDbUpdateManager.Result;
import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectCache;
@@ -150,7 +151,7 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
} }
@Override @Override
public NoteDbChangeState rebuild(ReviewDb db, Change.Id changeId) public Result rebuild(ReviewDb db, Change.Id changeId)
throws NoSuchChangeException, IOException, OrmException, throws NoSuchChangeException, IOException, OrmException,
ConfigInvalidException { ConfigInvalidException {
db = unwrapDb(db); db = unwrapDb(db);
@@ -164,7 +165,7 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
return execute(db, changeId, manager); return execute(db, changeId, manager);
} }
private NoteDbChangeState execute(ReviewDb db, Change.Id changeId, private Result execute(ReviewDb db, Change.Id changeId,
NoteDbUpdateManager manager) NoteDbUpdateManager manager)
throws NoSuchChangeException, OrmException, IOException { throws NoSuchChangeException, OrmException, IOException {
Change change = db.changes().get(changeId); Change change = db.changes().get(changeId);
@@ -173,8 +174,7 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
} }
final String oldNoteDbState = change.getNoteDbState(); final String oldNoteDbState = change.getNoteDbState();
NoteDbChangeState newState = Result r = manager.stageAndApplyDelta(change);
NoteDbChangeState.applyDelta(change, manager.stage());
final String newNoteDbState = change.getNoteDbState(); final String newNoteDbState = change.getNoteDbState();
try { try {
db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() { db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
@@ -191,7 +191,7 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
} catch (AbortUpdateException e) { } catch (AbortUpdateException e) {
// Drop this rebuild; another thread completed it. // Drop this rebuild; another thread completed it.
} }
return newState; return r;
} }
private static class AbortUpdateException extends OrmRuntimeException { private static class AbortUpdateException extends OrmRuntimeException {
@@ -203,12 +203,12 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
} }
@Override @Override
public NoteDbChangeState rebuild(NoteDbUpdateManager manager, public Result rebuild(NoteDbUpdateManager manager,
ChangeBundle bundle) throws NoSuchChangeException, IOException, ChangeBundle bundle) throws NoSuchChangeException, IOException,
OrmException, ConfigInvalidException { OrmException, ConfigInvalidException {
Change change = new Change(bundle.getChange()); Change change = new Change(bundle.getChange());
buildUpdates(manager, bundle); buildUpdates(manager, bundle);
return NoteDbChangeState.applyDelta(change, manager.stage()); return manager.stageAndApplyDelta(change);
} }
@Override @Override

View File

@@ -221,7 +221,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
NoteDbUpdateManager updateManager = NoteDbUpdateManager updateManager =
updateManagerFactory.create(getProjectName()); updateManagerFactory.create(getProjectName());
updateManager.add(this); updateManager.add(this);
NoteDbChangeState.applyDelta(getChange(), updateManager.stage()); updateManager.stageAndApplyDelta(getChange());
updateManager.execute(); updateManager.execute();
return getResult(); return getResult();
} }

View File

@@ -160,12 +160,12 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
private LoadHandle rebuildAndOpen(Repository repo) throws IOException { private LoadHandle rebuildAndOpen(Repository repo) throws IOException {
try { try {
NoteDbChangeState newState = NoteDbUpdateManager.Result r =
args.rebuilder.get().rebuild(args.db.get(), getChangeId()); args.rebuilder.get().rebuild(args.db.get(), getChangeId());
if (newState == null) { if (r == null) {
return super.openHandle(repo); // May be null in tests. return super.openHandle(repo); // May be null in tests.
} }
ObjectId draftsId = newState.getDraftIds().get(author); ObjectId draftsId = r.newState().getDraftIds().get(author);
repo.scanForRepoChanges(); repo.scanForRepoChanges();
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), draftsId); return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), draftsId);
} catch (NoSuchChangeException e) { } catch (NoSuchChangeException e) {

View File

@@ -100,12 +100,6 @@ public class NoteDbChangeState {
return new NoteDbChangeState(id, changeMetaId, draftIds); return new NoteDbChangeState(id, changeMetaId, draftIds);
} }
public static NoteDbChangeState applyDelta(Change change,
Map<Change.Id, NoteDbUpdateManager.StagedResult> stagedResults) {
NoteDbUpdateManager.StagedResult r = stagedResults.get(change.getId());
return applyDelta(change, r != null ? r.delta() : null);
}
public static NoteDbChangeState applyDelta(Change change, Delta delta) { public static NoteDbChangeState applyDelta(Change change, Delta delta) {
if (delta == null) { if (delta == null) {
return null; return null;

View File

@@ -22,17 +22,13 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Id; import com.google.gerrit.reviewdb.client.Change.Id;
import com.google.gerrit.reviewdb.client.Project.NameKey; import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.notedb.NoteDbUpdateManager.Result;
import com.google.gwtorm.server.OrmException;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.name.Names; import com.google.inject.name.Names;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
public class NoteDbModule extends FactoryModule { public class NoteDbModule extends FactoryModule {
private final Config cfg; private final Config cfg;
private final boolean useTestBindings; private final boolean useTestBindings;
@@ -68,23 +64,20 @@ public class NoteDbModule extends FactoryModule {
} else { } else {
bind(ChangeRebuilder.class).toInstance(new ChangeRebuilder(null) { bind(ChangeRebuilder.class).toInstance(new ChangeRebuilder(null) {
@Override @Override
public NoteDbChangeState rebuild(ReviewDb db, Change.Id changeId) public Result rebuild(ReviewDb db, Change.Id changeId) {
throws OrmException {
return null; return null;
} }
@Override @Override
public NoteDbChangeState rebuild(NoteDbUpdateManager manager, public Result rebuild(NoteDbUpdateManager manager,
ChangeBundle bundle) throws NoSuchChangeException, IOException, ChangeBundle bundle) {
OrmException, ConfigInvalidException {
return null; return null;
} }
@Override @Override
public boolean rebuildProject(ReviewDb db, public boolean rebuildProject(ReviewDb db,
ImmutableMultimap<NameKey, Id> allChanges, NameKey project, ImmutableMultimap<NameKey, Id> allChanges, NameKey project,
Repository allUsersRepo) throws NoSuchChangeException, IOException, Repository allUsersRepo) {
OrmException, ConfigInvalidException {
return false; return false;
} }
}); });

View File

@@ -103,6 +103,18 @@ public class NoteDbUpdateManager {
public abstract ImmutableList<InsertedObject> allUsersObjects(); public abstract ImmutableList<InsertedObject> allUsersObjects();
} }
@AutoValue
public abstract static class Result {
static Result create(NoteDbUpdateManager.StagedResult staged,
NoteDbChangeState newState) {
return new AutoValue_NoteDbUpdateManager_Result(newState, staged);
}
@Nullable public abstract NoteDbChangeState newState();
@Nullable abstract NoteDbUpdateManager.StagedResult staged();
}
static class OpenRepo implements AutoCloseable { static class OpenRepo implements AutoCloseable {
final Repository repo; final Repository repo;
final RevWalk rw; final RevWalk rw;
@@ -332,6 +344,14 @@ public class NoteDbUpdateManager {
} }
} }
public Result stageAndApplyDelta(Change change)
throws OrmException, IOException {
StagedResult sr = stage().get(change.getId());
NoteDbChangeState newState =
NoteDbChangeState.applyDelta(change, sr != null ? sr.delta() : null);
return Result.create(sr, newState);
}
private Table<Change.Id, Account.Id, ObjectId> getDraftIds() { private Table<Change.Id, Account.Id, ObjectId> getDraftIds() {
Table<Change.Id, Account.Id, ObjectId> draftIds = HashBasedTable.create(); Table<Change.Id, Account.Id, ObjectId> draftIds = HashBasedTable.create();
if (allUsersRepo == null) { if (allUsersRepo == null) {

View File

@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableMultimap;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.notedb.NoteDbUpdateManager.Result;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
@@ -50,10 +51,10 @@ public class TestChangeRebuilderWrapper extends ChangeRebuilder {
} }
@Override @Override
public NoteDbChangeState rebuild(ReviewDb db, Change.Id changeId) public Result rebuild(ReviewDb db, Change.Id changeId)
throws NoSuchChangeException, IOException, OrmException, throws NoSuchChangeException, IOException, OrmException,
ConfigInvalidException { ConfigInvalidException {
NoteDbChangeState result = delegate.rebuild(db, changeId); Result result = delegate.rebuild(db, changeId);
if (stealNextUpdate.getAndSet(false)) { if (stealNextUpdate.getAndSet(false)) {
throw new IOException("Update stolen"); throw new IOException("Update stolen");
} }
@@ -61,7 +62,7 @@ public class TestChangeRebuilderWrapper extends ChangeRebuilder {
} }
@Override @Override
public NoteDbChangeState rebuild(NoteDbUpdateManager manager, public Result rebuild(NoteDbUpdateManager manager,
ChangeBundle bundle) throws NoSuchChangeException, IOException, ChangeBundle bundle) throws NoSuchChangeException, IOException,
OrmException, ConfigInvalidException { OrmException, ConfigInvalidException {
// stealNextUpdate doesn't really apply in this case because the IOException // stealNextUpdate doesn't really apply in this case because the IOException