NoteDb: Auto-rebuild when either reads or writes are enabled

We plan to switch from write-only to read-write in a running server
after doing a batch rebuild. For that to work, we need to assume that
changes that are being written consistently will stay up-to-date in
NoteDb.

Previously, auto-rebuilding only happened when reads were enabled;
after this change, it will happen when either reads or writes are
enabled.

Change-Id: I265ef862df84d81e6917400309193e0681dd56db
This commit is contained in:
Dave Borowitz
2016-05-05 16:56:58 -04:00
parent 31cee3af70
commit ce13052c53
3 changed files with 31 additions and 17 deletions

View File

@@ -97,14 +97,16 @@ public abstract class AbstractChangeNotes<T> {
} }
protected final Args args; protected final Args args;
protected final boolean autoRebuild;
private final Change.Id changeId; private final Change.Id changeId;
private ObjectId revision; private ObjectId revision;
private boolean loaded; private boolean loaded;
AbstractChangeNotes(Args args, Change.Id changeId) { AbstractChangeNotes(Args args, Change.Id changeId, boolean autoRebuild) {
this.args = checkNotNull(args); this.args = checkNotNull(args);
this.changeId = checkNotNull(changeId); this.changeId = checkNotNull(changeId);
this.autoRebuild = autoRebuild;
} }
public Change.Id getChangeId() { public Change.Id getChangeId() {
@@ -120,7 +122,9 @@ public abstract class AbstractChangeNotes<T> {
if (loaded) { if (loaded) {
return self(); return self();
} }
if (!args.migration.readChanges()) { boolean read = args.migration.readChanges();
boolean readOrWrite = read || args.migration.writeChanges();
if (!readOrWrite || !autoRebuild) {
loadDefaults(); loadDefaults();
return self(); return self();
} }
@@ -129,9 +133,15 @@ public abstract class AbstractChangeNotes<T> {
} }
try (Timer1.Context timer = args.metrics.readLatency.start(CHANGES); try (Timer1.Context timer = args.metrics.readLatency.start(CHANGES);
Repository repo = args.repoManager.openRepository(getProjectName()); Repository repo = args.repoManager.openRepository(getProjectName());
// Call openHandle even if reading is disabled, to trigger
// auto-rebuilding before this object may get passed to a ChangeUpdate.
LoadHandle handle = openHandle(repo)) { LoadHandle handle = openHandle(repo)) {
revision = handle.id(); if (read) {
onLoad(handle); revision = handle.id();
onLoad(handle);
} else {
loadDefaults();
}
loaded = true; loaded = true;
} catch (ConfigInvalidException | IOException e) { } catch (ConfigInvalidException | IOException e) {
throw new OrmException(e); throw new OrmException(e);
@@ -145,7 +155,11 @@ public abstract class AbstractChangeNotes<T> {
} }
protected LoadHandle openHandle(Repository repo) throws IOException { protected LoadHandle openHandle(Repository repo) throws IOException {
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), readRef(repo)); return openHandle(repo, readRef(repo));
}
protected LoadHandle openHandle(Repository repo, ObjectId id) {
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), id);
} }
public T reload() throws OrmException { public T reload() throws OrmException {

View File

@@ -377,7 +377,6 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
private final Project.NameKey project; private final Project.NameKey project;
private final Change change; private final Change change;
private final boolean autoRebuild;
private final RefCache refs; private final RefCache refs;
private ImmutableSortedMap<PatchSet.Id, PatchSet> patchSets; private ImmutableSortedMap<PatchSet.Id, PatchSet> patchSets;
@@ -403,10 +402,9 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
private ChangeNotes(Args args, Project.NameKey project, Change change, private ChangeNotes(Args args, Project.NameKey project, Change change,
boolean autoRebuild, @Nullable RefCache refs) { boolean autoRebuild, @Nullable RefCache refs) {
super(args, change.getId()); super(args, change.getId(), autoRebuild);
this.project = project; this.project = project;
this.change = new Change(change); this.change = new Change(change);
this.autoRebuild = autoRebuild;
this.refs = refs; this.refs = refs;
} }
@@ -626,26 +624,31 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
protected LoadHandle openHandle(Repository repo) throws IOException { protected LoadHandle openHandle(Repository repo) throws IOException {
if (autoRebuild) { if (autoRebuild) {
NoteDbChangeState state = NoteDbChangeState.parse(change); NoteDbChangeState state = NoteDbChangeState.parse(change);
ObjectId id = readRef(repo);
if (state == null && id == null) {
return super.openHandle(repo, id);
}
RefCache refs = this.refs != null ? this.refs : new RepoRefCache(repo); RefCache refs = this.refs != null ? this.refs : new RepoRefCache(repo);
if (!NoteDbChangeState.isChangeUpToDate(state, refs, getChangeId())) { if (!NoteDbChangeState.isChangeUpToDate(state, refs, getChangeId())) {
return rebuildAndOpen(repo); return rebuildAndOpen(repo, id);
} }
} }
return super.openHandle(repo); return super.openHandle(repo);
} }
private LoadHandle rebuildAndOpen(Repository repo) throws IOException { private LoadHandle rebuildAndOpen(Repository repo, ObjectId oldId)
throws IOException {
try { try {
NoteDbChangeState newState = NoteDbChangeState newState =
args.rebuilder.get().rebuild(args.db.get(), getChangeId()); args.rebuilder.get().rebuild(args.db.get(), getChangeId());
if (newState == null) { if (newState == null) {
return super.openHandle(repo); // May be null in tests. return super.openHandle(repo, oldId); // May be null in tests.
} }
repo.scanForRepoChanges(); repo.scanForRepoChanges();
return LoadHandle.create( return LoadHandle.create(
ChangeNotesCommit.newRevWalk(repo), newState.getChangeMetaId()); ChangeNotesCommit.newRevWalk(repo), newState.getChangeMetaId());
} catch (NoSuchChangeException e) { } catch (NoSuchChangeException e) {
return super.openHandle(repo); return super.openHandle(repo, oldId);
} catch (OrmException | ConfigInvalidException e) { } catch (OrmException | ConfigInvalidException e) {
throw new IOException(e); throw new IOException(e);
} }

View File

@@ -52,7 +52,6 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
private final Change change; private final Change change;
private final Account.Id author; private final Account.Id author;
private final boolean autoRebuild;
private ImmutableListMultimap<RevId, PatchLineComment> comments; private ImmutableListMultimap<RevId, PatchLineComment> comments;
private RevisionNoteMap revisionNoteMap; private RevisionNoteMap revisionNoteMap;
@@ -70,10 +69,9 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
Args args, Args args,
@Assisted Change.Id changeId, @Assisted Change.Id changeId,
@Assisted Account.Id author) { @Assisted Account.Id author) {
super(args, changeId); super(args, changeId, true);
this.change = null; this.change = null;
this.author = author; this.author = author;
this.autoRebuild = true;
} }
DraftCommentNotes( DraftCommentNotes(
@@ -81,10 +79,9 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
Change change, Change change,
Account.Id author, Account.Id author,
boolean autoRebuild) { boolean autoRebuild) {
super(args, change.getId()); super(args, change.getId(), autoRebuild);
this.change = change; this.change = change;
this.author = author; this.author = author;
this.autoRebuild = autoRebuild;
} }
RevisionNoteMap getRevisionNoteMap() { RevisionNoteMap getRevisionNoteMap() {