Automatically rebuild out-of-date NoteDb drafts

Uses the same mechanism as when rebuilding changes, except checking
the state of the relevant drafts ref in All-Users.

The one place we couldn't do this easily is in
PatchLineCommentsUtil#draftsByAuthor, since it doesn't have a Change
object available for each change, and we don't want to go overboard in
reading the notes. Just bail and skip rebuilding in that particular
case, marking it as deprecated so it doesn't pick up any new users.

Change-Id: Iaeccc9e665eb6ee2ffa4583f5add8d0ba9968d70
This commit is contained in:
Dave Borowitz
2016-03-29 12:32:42 -04:00
parent a30ce68ee1
commit 029d256839
6 changed files with 129 additions and 32 deletions

View File

@@ -24,14 +24,18 @@ import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import java.io.IOException;
@@ -41,20 +45,34 @@ import java.io.IOException;
*/
public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
public interface Factory {
DraftCommentNotes create(Change.Id changeId, Account.Id accountId);
DraftCommentNotes create(Change change, Account.Id accountId);
DraftCommentNotes createWithAutoRebuildingDisabled(
Change.Id changeId, Account.Id accountId);
}
private final Change change;
private final Account.Id author;
private ImmutableListMultimap<RevId, PatchLineComment> comments;
private RevisionNoteMap revisionNoteMap;
@AssistedInject
DraftCommentNotes(
Args args,
@Assisted Change change,
@Assisted Account.Id author) {
super(args, change.getId());
this.change = change;
this.author = author;
}
@AssistedInject
DraftCommentNotes(
Args args,
@Assisted Change.Id changeId,
@Assisted Account.Id author) {
super(args, changeId);
this.change = null;
this.author = author;
}
@@ -118,6 +136,36 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
return args.allUsers;
}
@Override
protected LoadHandle openHandle(Repository repo) throws IOException {
if (change != null) {
NoteDbChangeState state = NoteDbChangeState.parse(change);
// Only check if this particular user's drafts are up to date, to avoid
// reading unnecessary refs.
if (state == null || !state.areDraftsUpToDate(repo, author)) {
return rebuildAndOpen(repo);
}
}
return super.openHandle(repo);
}
private LoadHandle rebuildAndOpen(Repository repo) throws IOException {
try {
NoteDbChangeState newState =
args.rebuilder.get().rebuild(args.db.get(), getChangeId());
if (newState == null) {
return super.openHandle(repo); // May be null in tests.
}
ObjectId draftsId = newState.getDraftIds().get(author);
repo.scanForRepoChanges();
return LoadHandle.create(new RevWalk(repo), draftsId);
} catch (NoSuchChangeException e) {
return super.openHandle(repo);
} catch (OrmException | ConfigInvalidException e) {
throw new IOException(e);
}
}
@VisibleForTesting
NoteMap getNoteMap() {
return revisionNoteMap != null ? revisionNoteMap.noteMap : null;