Remove auto-rebuilding of changes
Rebuilding change NoteDb data from ReviewDb is no longer possible since ReviewDb is gone. Hence remove all logic for auto rebuilding changes. ChangeRebuilder is now unused but removing the NoteDb rebuilding machinery will is better done in a separate follow-up change. Remove all of ChangeRebuilderIT; a number of these tests will fail due to auto-rebuilding being gone. It's not worth the effort to prune it down to the passing tests, since the rest of the rebuilder code is getting deleted next. Change-Id: Ic577d69f5826094a2ca22f4efcc5ff591193e0fe Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -33,7 +33,6 @@ import com.google.gerrit.server.index.IndexExecutor;
|
||||
import com.google.gerrit.server.index.IndexUtils;
|
||||
import com.google.gerrit.server.logging.TraceContext;
|
||||
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.plugincontext.PluginSetContext;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
@@ -87,8 +86,6 @@ public class ChangeIndexer {
|
||||
@Nullable private final ChangeIndexCollection indexes;
|
||||
@Nullable private final ChangeIndex index;
|
||||
private final SchemaFactory<ReviewDb> schemaFactory;
|
||||
private final NotesMigration notesMigration;
|
||||
private final ChangeNotes.Factory changeNotesFactory;
|
||||
private final ChangeData.Factory changeDataFactory;
|
||||
private final ThreadLocalRequestContext context;
|
||||
private final ListeningExecutorService batchExecutor;
|
||||
@@ -102,7 +99,6 @@ public class ChangeIndexer {
|
||||
@GerritServerConfig Config cfg,
|
||||
SchemaFactory<ReviewDb> schemaFactory,
|
||||
NotesMigration notesMigration,
|
||||
ChangeNotes.Factory changeNotesFactory,
|
||||
ChangeData.Factory changeDataFactory,
|
||||
ThreadLocalRequestContext context,
|
||||
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
||||
@@ -112,8 +108,6 @@ public class ChangeIndexer {
|
||||
@Assisted ChangeIndex index) {
|
||||
this.executor = executor;
|
||||
this.schemaFactory = schemaFactory;
|
||||
this.notesMigration = notesMigration;
|
||||
this.changeNotesFactory = changeNotesFactory;
|
||||
this.changeDataFactory = changeDataFactory;
|
||||
this.context = context;
|
||||
this.indexedListeners = indexedListeners;
|
||||
@@ -129,7 +123,6 @@ public class ChangeIndexer {
|
||||
SchemaFactory<ReviewDb> schemaFactory,
|
||||
@GerritServerConfig Config cfg,
|
||||
NotesMigration notesMigration,
|
||||
ChangeNotes.Factory changeNotesFactory,
|
||||
ChangeData.Factory changeDataFactory,
|
||||
ThreadLocalRequestContext context,
|
||||
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
||||
@@ -139,8 +132,6 @@ public class ChangeIndexer {
|
||||
@Assisted ChangeIndexCollection indexes) {
|
||||
this.executor = executor;
|
||||
this.schemaFactory = schemaFactory;
|
||||
this.notesMigration = notesMigration;
|
||||
this.changeNotesFactory = changeNotesFactory;
|
||||
this.changeDataFactory = changeDataFactory;
|
||||
this.context = context;
|
||||
this.indexedListeners = indexedListeners;
|
||||
@@ -239,8 +230,9 @@ public class ChangeIndexer {
|
||||
* @param db review database.
|
||||
* @param change change to index.
|
||||
*/
|
||||
// TODO(dborowitz): Remove OrmException
|
||||
public void index(ReviewDb db, Change change) throws IOException, OrmException {
|
||||
index(newChangeData(db, change));
|
||||
index(changeDataFactory.create(db, change));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,9 +242,10 @@ public class ChangeIndexer {
|
||||
* @param project the project to which the change belongs.
|
||||
* @param changeId ID of the change to index.
|
||||
*/
|
||||
// TODO(dborowitz): Remove OrmException
|
||||
public void index(ReviewDb db, Project.NameKey project, Change.Id changeId)
|
||||
throws IOException, OrmException {
|
||||
index(newChangeData(db, project, changeId));
|
||||
index(changeDataFactory.create(db, project, changeId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,7 +376,7 @@ public class ChangeIndexer {
|
||||
|
||||
@Override
|
||||
public Void callImpl(Provider<ReviewDb> db) throws Exception {
|
||||
ChangeData cd = newChangeData(db.get(), project, id);
|
||||
ChangeData cd = changeDataFactory.create(db.get(), project, id);
|
||||
index(cd);
|
||||
return null;
|
||||
}
|
||||
@@ -429,7 +422,7 @@ public class ChangeIndexer {
|
||||
public Boolean callImpl(Provider<ReviewDb> db) throws Exception {
|
||||
try {
|
||||
if (stalenessChecker.isStale(id)) {
|
||||
indexImpl(newChangeData(db.get(), project, id));
|
||||
indexImpl(changeDataFactory.create(db.get(), project, id));
|
||||
return true;
|
||||
}
|
||||
} catch (NoSuchChangeException nsce) {
|
||||
@@ -460,26 +453,4 @@ public class ChangeIndexer {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid auto-rebuilding when reindexing if reading is disabled. This just
|
||||
// increases contention on the meta ref from a background indexing thread
|
||||
// with little benefit. The next actual write to the entity may still incur a
|
||||
// less-contentious rebuild.
|
||||
private ChangeData newChangeData(ReviewDb db, Change change) throws OrmException {
|
||||
if (!notesMigration.readChanges()) {
|
||||
ChangeNotes notes = changeNotesFactory.createWithAutoRebuildingDisabled(change, null);
|
||||
return changeDataFactory.create(db, notes);
|
||||
}
|
||||
return changeDataFactory.create(db, change);
|
||||
}
|
||||
|
||||
private ChangeData newChangeData(ReviewDb db, Project.NameKey project, Change.Id changeId)
|
||||
throws OrmException {
|
||||
if (!notesMigration.readChanges()) {
|
||||
ChangeNotes notes =
|
||||
changeNotesFactory.createWithAutoRebuildingDisabled(db, project, changeId);
|
||||
return changeDataFactory.create(db, notes);
|
||||
}
|
||||
return changeDataFactory.create(db, project, changeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -27,8 +28,6 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.notedb.ChangeNotesCommit.ChangeNotesRevWalk;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
@@ -55,9 +54,6 @@ public abstract class AbstractChangeNotes<T> {
|
||||
|
||||
// Providers required to avoid dependency cycles.
|
||||
|
||||
// ChangeRebuilder -> ChangeNotes.Factory -> Args
|
||||
final Provider<ChangeRebuilder> rebuilder;
|
||||
|
||||
// ChangeNoteCache -> Args
|
||||
final Provider<ChangeNotesCache> cache;
|
||||
|
||||
@@ -70,7 +66,6 @@ public abstract class AbstractChangeNotes<T> {
|
||||
LegacyChangeNoteRead legacyChangeNoteRead,
|
||||
NoteDbMetrics metrics,
|
||||
Provider<ReviewDb> db,
|
||||
Provider<ChangeRebuilder> rebuilder,
|
||||
Provider<ChangeNotesCache> cache) {
|
||||
this.repoManager = repoManager;
|
||||
this.migration = migration;
|
||||
@@ -79,7 +74,6 @@ public abstract class AbstractChangeNotes<T> {
|
||||
this.changeNoteJson = changeNoteJson;
|
||||
this.metrics = metrics;
|
||||
this.db = db;
|
||||
this.rebuilder = rebuilder;
|
||||
this.cache = cache;
|
||||
}
|
||||
}
|
||||
@@ -114,22 +108,14 @@ public abstract class AbstractChangeNotes<T> {
|
||||
}
|
||||
|
||||
protected final Args args;
|
||||
protected final PrimaryStorage primaryStorage;
|
||||
protected final boolean autoRebuild;
|
||||
private final Change.Id changeId;
|
||||
|
||||
private ObjectId revision;
|
||||
private boolean loaded;
|
||||
|
||||
AbstractChangeNotes(
|
||||
Args args, Change.Id changeId, @Nullable PrimaryStorage primaryStorage, boolean autoRebuild) {
|
||||
AbstractChangeNotes(Args args, Change.Id changeId) {
|
||||
this.args = requireNonNull(args);
|
||||
this.changeId = requireNonNull(changeId);
|
||||
this.primaryStorage = primaryStorage;
|
||||
this.autoRebuild =
|
||||
primaryStorage == PrimaryStorage.REVIEW_DB
|
||||
&& !args.migration.disableChangeReviewDb()
|
||||
&& autoRebuild;
|
||||
}
|
||||
|
||||
public Change.Id getChangeId() {
|
||||
@@ -146,18 +132,7 @@ public abstract class AbstractChangeNotes<T> {
|
||||
return self();
|
||||
}
|
||||
|
||||
boolean read = args.migration.readChanges();
|
||||
if (!read && primaryStorage == PrimaryStorage.NOTE_DB) {
|
||||
throw new OrmException("NoteDb is required to read change " + changeId);
|
||||
}
|
||||
boolean readOrWrite = read || args.migration.rawWriteChangesSetting();
|
||||
if (!readOrWrite) {
|
||||
// Don't even open the repo if we neither write to nor read from NoteDb. It's possible that
|
||||
// there is some garbage in the noteDbState field and/or the repo, but at this point NoteDb is
|
||||
// completely off so it's none of our business.
|
||||
loadDefaults();
|
||||
return self();
|
||||
}
|
||||
checkState(args.migration.readChanges(), "NoteDb is required to read changes");
|
||||
if (args.migration.failOnLoadForTest()) {
|
||||
throw new OrmException("Reading from NoteDb is disabled");
|
||||
}
|
||||
@@ -166,12 +141,8 @@ public abstract class AbstractChangeNotes<T> {
|
||||
// Call openHandle even if reading is disabled, to trigger
|
||||
// auto-rebuilding before this object may get passed to a ChangeUpdate.
|
||||
LoadHandle handle = openHandle(repo)) {
|
||||
if (read) {
|
||||
revision = handle.id();
|
||||
onLoad(handle);
|
||||
} else {
|
||||
loadDefaults();
|
||||
}
|
||||
loaded = true;
|
||||
} catch (ConfigInvalidException | IOException e) {
|
||||
throw new OrmException(e);
|
||||
@@ -202,7 +173,7 @@ public abstract class AbstractChangeNotes<T> {
|
||||
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), id);
|
||||
}
|
||||
|
||||
public T reload() throws NoSuchChangeException, OrmException {
|
||||
public T reload() throws OrmException {
|
||||
loaded = false;
|
||||
return load();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package com.google.gerrit.server.notedb;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -39,7 +38,6 @@ import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.metrics.Timer1;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
@@ -57,9 +55,7 @@ import com.google.gerrit.server.ReviewerByEmailSet;
|
||||
import com.google.gerrit.server.ReviewerSet;
|
||||
import com.google.gerrit.server.ReviewerStatusUpdate;
|
||||
import com.google.gerrit.server.git.RefCache;
|
||||
import com.google.gerrit.server.git.RepoRefCache;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
@@ -77,7 +73,6 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
@@ -186,12 +181,6 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
return new ChangeNotes(args, loadChangeFromDb(db, project, changeId)).load();
|
||||
}
|
||||
|
||||
public ChangeNotes createWithAutoRebuildingDisabled(
|
||||
ReviewDb db, Project.NameKey project, Change.Id changeId) throws OrmException {
|
||||
return new ChangeNotes(args, loadChangeFromDb(db, project, changeId), true, false, null)
|
||||
.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create change notes for a change that was loaded from index. This method should only be used
|
||||
* when database access is harmful and potentially stale data from the index is acceptable.
|
||||
@@ -205,12 +194,11 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
|
||||
public ChangeNotes createForBatchUpdate(Change change, boolean shouldExist)
|
||||
throws OrmException {
|
||||
return new ChangeNotes(args, change, shouldExist, false, null).load();
|
||||
return new ChangeNotes(args, change, shouldExist, null).load();
|
||||
}
|
||||
|
||||
public ChangeNotes createWithAutoRebuildingDisabled(Change change, RefCache refs)
|
||||
throws OrmException {
|
||||
return new ChangeNotes(args, change, true, false, refs).load();
|
||||
public ChangeNotes create(Change change, RefCache refs) throws OrmException {
|
||||
return new ChangeNotes(args, change, true, refs).load();
|
||||
}
|
||||
|
||||
// TODO(ekempin): Remove when database backend is deleted
|
||||
@@ -459,7 +447,6 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
// notes easier.
|
||||
RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
||||
|
||||
private NoteDbUpdateManager.Result rebuildResult;
|
||||
private DraftCommentNotes draftCommentNotes;
|
||||
private RobotCommentNotes robotCommentNotes;
|
||||
|
||||
@@ -471,12 +458,11 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
|
||||
@VisibleForTesting
|
||||
public ChangeNotes(Args args, Change change) {
|
||||
this(args, change, true, true, null);
|
||||
this(args, change, true, null);
|
||||
}
|
||||
|
||||
private ChangeNotes(
|
||||
Args args, Change change, boolean shouldExist, boolean autoRebuild, @Nullable RefCache refs) {
|
||||
super(args, change.getId(), PrimaryStorage.of(change), autoRebuild);
|
||||
private ChangeNotes(Args args, Change change, boolean shouldExist, @Nullable RefCache refs) {
|
||||
super(args, change.getId());
|
||||
this.change = new Change(change);
|
||||
this.shouldExist = shouldExist;
|
||||
this.refs = refs;
|
||||
@@ -609,8 +595,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
*/
|
||||
private void loadDraftComments(Account.Id author, @Nullable Ref ref) throws OrmException {
|
||||
if (draftCommentNotes == null || !author.equals(draftCommentNotes.getAuthor()) || ref != null) {
|
||||
draftCommentNotes =
|
||||
new DraftCommentNotes(args, change, author, autoRebuild, rebuildResult, ref);
|
||||
draftCommentNotes = new DraftCommentNotes(args, getChangeId(), author, ref);
|
||||
draftCommentNotes.load();
|
||||
}
|
||||
}
|
||||
@@ -665,8 +650,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad(LoadHandle handle)
|
||||
throws NoSuchChangeException, IOException, ConfigInvalidException {
|
||||
protected void onLoad(LoadHandle handle) throws NoSuchChangeException, IOException {
|
||||
ObjectId rev = handle.id();
|
||||
if (rev == null) {
|
||||
if (args.migration.readChanges()
|
||||
@@ -699,89 +683,4 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
||||
protected ObjectId readRef(Repository repo) throws IOException {
|
||||
return refs != null ? refs.get(getRefName()).orElse(null) : super.readRef(repo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoadHandle openHandle(Repository repo) throws NoSuchChangeException, IOException {
|
||||
if (autoRebuild) {
|
||||
NoteDbChangeState state = NoteDbChangeState.parse(change);
|
||||
if (args.migration.disableChangeReviewDb()) {
|
||||
checkState(
|
||||
state != null,
|
||||
"shouldn't have null NoteDbChangeState when ReviewDb disabled: %s",
|
||||
change);
|
||||
}
|
||||
ObjectId id = readRef(repo);
|
||||
if (id == null) {
|
||||
// Meta ref doesn't exist in NoteDb.
|
||||
|
||||
if (state == null) {
|
||||
// Either ReviewDb change is being newly created, or it exists in ReviewDb but has not yet
|
||||
// been rebuilt for the first time, e.g. because we just turned on write-only mode. In
|
||||
// both cases, we don't want to auto-rebuild, just proceed with an empty ChangeNotes.
|
||||
return super.openHandle(repo, id);
|
||||
} else if (shouldExist && state.getPrimaryStorage() == PrimaryStorage.NOTE_DB) {
|
||||
throw new NoSuchChangeException(getChangeId());
|
||||
}
|
||||
|
||||
// ReviewDb claims NoteDb state exists, but meta ref isn't present: fall through and
|
||||
// auto-rebuild if necessary.
|
||||
}
|
||||
RefCache refs = this.refs != null ? this.refs : new RepoRefCache(repo);
|
||||
if (!NoteDbChangeState.isChangeUpToDate(state, refs, getChangeId())) {
|
||||
return rebuildAndOpen(repo, id);
|
||||
}
|
||||
}
|
||||
return super.openHandle(repo);
|
||||
}
|
||||
|
||||
private LoadHandle rebuildAndOpen(Repository repo, ObjectId oldId) throws IOException {
|
||||
Timer1.Context timer = args.metrics.autoRebuildLatency.start(CHANGES);
|
||||
try {
|
||||
Change.Id cid = getChangeId();
|
||||
ReviewDb db = args.db.get();
|
||||
ChangeRebuilder rebuilder = args.rebuilder.get();
|
||||
NoteDbUpdateManager.Result r;
|
||||
try (NoteDbUpdateManager manager = rebuilder.stage(db, cid)) {
|
||||
if (manager == null) {
|
||||
return super.openHandle(repo, oldId); // May be null in tests.
|
||||
}
|
||||
manager.setRefLogMessage("Auto-rebuilding change");
|
||||
r = manager.stageAndApplyDelta(change);
|
||||
try {
|
||||
rebuilder.execute(db, cid, manager);
|
||||
repo.scanForRepoChanges();
|
||||
} catch (OrmException | IOException e) {
|
||||
// Rebuilding failed. Most likely cause is contention on one or more
|
||||
// change refs; there are other types of errors that can happen during
|
||||
// rebuilding, but generally speaking they should happen during stage(),
|
||||
// not execute(). Assume that some other worker is going to successfully
|
||||
// store the rebuilt state, which is deterministic given an input
|
||||
// ChangeBundle.
|
||||
//
|
||||
// Parse notes from the staged result so we can return something useful
|
||||
// to the caller instead of throwing.
|
||||
logger.atFine().log("Rebuilding change %s failed: %s", getChangeId(), e.getMessage());
|
||||
args.metrics.autoRebuildFailureCount.increment(CHANGES);
|
||||
rebuildResult = requireNonNull(r);
|
||||
requireNonNull(r.newState());
|
||||
requireNonNull(r.staged());
|
||||
requireNonNull(r.staged().changeObjects());
|
||||
return LoadHandle.create(
|
||||
ChangeNotesCommit.newStagedRevWalk(repo, r.staged().changeObjects()),
|
||||
r.newState().getChangeMetaId());
|
||||
}
|
||||
}
|
||||
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), r.newState().getChangeMetaId());
|
||||
} catch (NoSuchChangeException e) {
|
||||
return super.openHandle(repo, oldId);
|
||||
} catch (OrmException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
logger.atFine().log(
|
||||
"Rebuilt change %s in project %s in %s ms",
|
||||
getChangeId(),
|
||||
getProjectName(),
|
||||
TimeUnit.MILLISECONDS.convert(timer.stop(), TimeUnit.NANOSECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.gerrit.reviewdb.client.RefNames.refsDraftComments;
|
||||
import static com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -25,24 +24,15 @@ import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.metrics.Timer1;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Comment;
|
||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RevId;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.git.RepoRefCache;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.gerrit.server.notedb.NoteDbUpdateManager.StagedResult;
|
||||
import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder;
|
||||
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 java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectReader;
|
||||
@@ -50,53 +40,29 @@ import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.notes.NoteMap;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
|
||||
/** View of the draft comments for a single {@link Change} based on the log of its drafts branch. */
|
||||
public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
public interface Factory {
|
||||
DraftCommentNotes create(Change change, Account.Id accountId);
|
||||
|
||||
DraftCommentNotes createWithAutoRebuildingDisabled(Change.Id changeId, Account.Id accountId);
|
||||
DraftCommentNotes create(Change.Id changeId, Account.Id accountId);
|
||||
}
|
||||
|
||||
private final Change change;
|
||||
private final Account.Id author;
|
||||
private final NoteDbUpdateManager.Result rebuildResult;
|
||||
private final Ref ref;
|
||||
|
||||
private ImmutableListMultimap<RevId, Comment> comments;
|
||||
private RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
||||
|
||||
@AssistedInject
|
||||
DraftCommentNotes(Args args, @Assisted Change change, @Assisted Account.Id author) {
|
||||
this(args, change, author, true, null, null);
|
||||
}
|
||||
|
||||
@AssistedInject
|
||||
DraftCommentNotes(Args args, @Assisted Change.Id changeId, @Assisted Account.Id author) {
|
||||
// PrimaryStorage is unknown; this should only called by
|
||||
// PatchLineCommentsUtil#draftByAuthor, which can live with this.
|
||||
super(args, changeId, null, false);
|
||||
this.change = null;
|
||||
this.author = author;
|
||||
this.rebuildResult = null;
|
||||
this.ref = null;
|
||||
this(args, changeId, author, null);
|
||||
}
|
||||
|
||||
DraftCommentNotes(
|
||||
Args args,
|
||||
Change change,
|
||||
Account.Id author,
|
||||
boolean autoRebuild,
|
||||
@Nullable NoteDbUpdateManager.Result rebuildResult,
|
||||
@Nullable Ref ref) {
|
||||
super(args, change.getId(), PrimaryStorage.of(change), autoRebuild);
|
||||
this.change = change;
|
||||
this.author = author;
|
||||
this.rebuildResult = rebuildResult;
|
||||
DraftCommentNotes(Args args, Change.Id changeId, Account.Id author, @Nullable Ref ref) {
|
||||
super(args, changeId);
|
||||
this.author = requireNonNull(author);
|
||||
this.ref = ref;
|
||||
if (ref != null) {
|
||||
checkArgument(
|
||||
@@ -181,79 +147,6 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
||||
return args.allUsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoadHandle openHandle(Repository repo) throws NoSuchChangeException, IOException {
|
||||
if (rebuildResult != null) {
|
||||
StagedResult sr = requireNonNull(rebuildResult.staged());
|
||||
return LoadHandle.create(
|
||||
ChangeNotesCommit.newStagedRevWalk(repo, sr.allUsersObjects()),
|
||||
findNewId(sr.allUsersCommands(), getRefName()));
|
||||
} else if (change != null && autoRebuild) {
|
||||
NoteDbChangeState state = NoteDbChangeState.parse(change);
|
||||
// Only check if this particular user's drafts are up to date, to avoid
|
||||
// reading unnecessary refs.
|
||||
if (!NoteDbChangeState.areDraftsUpToDate(
|
||||
state, new RepoRefCache(repo), getChangeId(), author)) {
|
||||
return rebuildAndOpen(repo);
|
||||
}
|
||||
}
|
||||
return super.openHandle(repo);
|
||||
}
|
||||
|
||||
private static ObjectId findNewId(Iterable<ReceiveCommand> cmds, String refName) {
|
||||
for (ReceiveCommand cmd : cmds) {
|
||||
if (cmd.getRefName().equals(refName)) {
|
||||
return cmd.getNewId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LoadHandle rebuildAndOpen(Repository repo) throws NoSuchChangeException, IOException {
|
||||
Timer1.Context timer = args.metrics.autoRebuildLatency.start(CHANGES);
|
||||
try {
|
||||
Change.Id cid = getChangeId();
|
||||
ReviewDb db = args.db.get();
|
||||
ChangeRebuilder rebuilder = args.rebuilder.get();
|
||||
NoteDbUpdateManager.Result r;
|
||||
try (NoteDbUpdateManager manager = rebuilder.stage(db, cid)) {
|
||||
if (manager == null) {
|
||||
return super.openHandle(repo); // May be null in tests.
|
||||
}
|
||||
r = manager.stageAndApplyDelta(change);
|
||||
try {
|
||||
rebuilder.execute(db, cid, manager);
|
||||
repo.scanForRepoChanges();
|
||||
} catch (OrmException | IOException e) {
|
||||
// See ChangeNotes#rebuildAndOpen.
|
||||
logger.atFine().log(
|
||||
"Rebuilding change %s via drafts failed: %s", getChangeId(), e.getMessage());
|
||||
args.metrics.autoRebuildFailureCount.increment(CHANGES);
|
||||
requireNonNull(r.staged());
|
||||
return LoadHandle.create(
|
||||
ChangeNotesCommit.newStagedRevWalk(repo, r.staged().allUsersObjects()), draftsId(r));
|
||||
}
|
||||
}
|
||||
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), draftsId(r));
|
||||
} catch (NoSuchChangeException e) {
|
||||
return super.openHandle(repo);
|
||||
} catch (OrmException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
logger.atFine().log(
|
||||
"Rebuilt change %s in %s in %s ms via drafts",
|
||||
getChangeId(),
|
||||
change != null ? "project " + change.getProject() : "unknown project",
|
||||
TimeUnit.MILLISECONDS.convert(timer.stop(), TimeUnit.NANOSECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectId draftsId(NoteDbUpdateManager.Result r) {
|
||||
requireNonNull(r);
|
||||
requireNonNull(r.newState());
|
||||
return r.newState().getDraftIds().get(author);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
NoteMap getNoteMap() {
|
||||
return revisionNoteMap != null ? revisionNoteMap.noteMap : null;
|
||||
|
||||
@@ -24,7 +24,6 @@ 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.reviewdb.client.RobotComment;
|
||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import java.io.IOException;
|
||||
@@ -49,7 +48,7 @@ public class RobotCommentNotes extends AbstractChangeNotes<RobotCommentNotes> {
|
||||
|
||||
@Inject
|
||||
RobotCommentNotes(Args args, @Assisted Change change) {
|
||||
super(args, change.getId(), PrimaryStorage.of(change), false);
|
||||
super(args, change.getId());
|
||||
this.change = change;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2605,7 +2605,7 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
}
|
||||
|
||||
// Looking at drafts directly shows the zombie comment.
|
||||
DraftCommentNotes draftNotes = draftNotesFactory.create(c, otherUserId);
|
||||
DraftCommentNotes draftNotes = draftNotesFactory.create(c.getId(), otherUserId);
|
||||
assertThat(draftNotes.load().getComments().get(rev1)).containsExactly(comment1, comment2);
|
||||
|
||||
// Zombie comment is filtered out of drafts via ChangeNotes.
|
||||
|
||||
Reference in New Issue
Block a user