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.index.IndexUtils;
|
||||||
import com.google.gerrit.server.logging.TraceContext;
|
import com.google.gerrit.server.logging.TraceContext;
|
||||||
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
|
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.notedb.NotesMigration;
|
||||||
import com.google.gerrit.server.plugincontext.PluginSetContext;
|
import com.google.gerrit.server.plugincontext.PluginSetContext;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
@@ -87,8 +86,6 @@ public class ChangeIndexer {
|
|||||||
@Nullable private final ChangeIndexCollection indexes;
|
@Nullable private final ChangeIndexCollection indexes;
|
||||||
@Nullable private final ChangeIndex index;
|
@Nullable private final ChangeIndex index;
|
||||||
private final SchemaFactory<ReviewDb> schemaFactory;
|
private final SchemaFactory<ReviewDb> schemaFactory;
|
||||||
private final NotesMigration notesMigration;
|
|
||||||
private final ChangeNotes.Factory changeNotesFactory;
|
|
||||||
private final ChangeData.Factory changeDataFactory;
|
private final ChangeData.Factory changeDataFactory;
|
||||||
private final ThreadLocalRequestContext context;
|
private final ThreadLocalRequestContext context;
|
||||||
private final ListeningExecutorService batchExecutor;
|
private final ListeningExecutorService batchExecutor;
|
||||||
@@ -102,7 +99,6 @@ public class ChangeIndexer {
|
|||||||
@GerritServerConfig Config cfg,
|
@GerritServerConfig Config cfg,
|
||||||
SchemaFactory<ReviewDb> schemaFactory,
|
SchemaFactory<ReviewDb> schemaFactory,
|
||||||
NotesMigration notesMigration,
|
NotesMigration notesMigration,
|
||||||
ChangeNotes.Factory changeNotesFactory,
|
|
||||||
ChangeData.Factory changeDataFactory,
|
ChangeData.Factory changeDataFactory,
|
||||||
ThreadLocalRequestContext context,
|
ThreadLocalRequestContext context,
|
||||||
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
||||||
@@ -112,8 +108,6 @@ public class ChangeIndexer {
|
|||||||
@Assisted ChangeIndex index) {
|
@Assisted ChangeIndex index) {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.schemaFactory = schemaFactory;
|
this.schemaFactory = schemaFactory;
|
||||||
this.notesMigration = notesMigration;
|
|
||||||
this.changeNotesFactory = changeNotesFactory;
|
|
||||||
this.changeDataFactory = changeDataFactory;
|
this.changeDataFactory = changeDataFactory;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.indexedListeners = indexedListeners;
|
this.indexedListeners = indexedListeners;
|
||||||
@@ -129,7 +123,6 @@ public class ChangeIndexer {
|
|||||||
SchemaFactory<ReviewDb> schemaFactory,
|
SchemaFactory<ReviewDb> schemaFactory,
|
||||||
@GerritServerConfig Config cfg,
|
@GerritServerConfig Config cfg,
|
||||||
NotesMigration notesMigration,
|
NotesMigration notesMigration,
|
||||||
ChangeNotes.Factory changeNotesFactory,
|
|
||||||
ChangeData.Factory changeDataFactory,
|
ChangeData.Factory changeDataFactory,
|
||||||
ThreadLocalRequestContext context,
|
ThreadLocalRequestContext context,
|
||||||
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
PluginSetContext<ChangeIndexedListener> indexedListeners,
|
||||||
@@ -139,8 +132,6 @@ public class ChangeIndexer {
|
|||||||
@Assisted ChangeIndexCollection indexes) {
|
@Assisted ChangeIndexCollection indexes) {
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.schemaFactory = schemaFactory;
|
this.schemaFactory = schemaFactory;
|
||||||
this.notesMigration = notesMigration;
|
|
||||||
this.changeNotesFactory = changeNotesFactory;
|
|
||||||
this.changeDataFactory = changeDataFactory;
|
this.changeDataFactory = changeDataFactory;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.indexedListeners = indexedListeners;
|
this.indexedListeners = indexedListeners;
|
||||||
@@ -239,8 +230,9 @@ public class ChangeIndexer {
|
|||||||
* @param db review database.
|
* @param db review database.
|
||||||
* @param change change to index.
|
* @param change change to index.
|
||||||
*/
|
*/
|
||||||
|
// TODO(dborowitz): Remove OrmException
|
||||||
public void index(ReviewDb db, Change change) throws IOException, 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 project the project to which the change belongs.
|
||||||
* @param changeId ID of the change to index.
|
* @param changeId ID of the change to index.
|
||||||
*/
|
*/
|
||||||
|
// TODO(dborowitz): Remove OrmException
|
||||||
public void index(ReviewDb db, Project.NameKey project, Change.Id changeId)
|
public void index(ReviewDb db, Project.NameKey project, Change.Id changeId)
|
||||||
throws IOException, OrmException {
|
throws IOException, OrmException {
|
||||||
index(newChangeData(db, project, changeId));
|
index(changeDataFactory.create(db, project, changeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -383,7 +376,7 @@ public class ChangeIndexer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void callImpl(Provider<ReviewDb> db) throws Exception {
|
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);
|
index(cd);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -429,7 +422,7 @@ public class ChangeIndexer {
|
|||||||
public Boolean callImpl(Provider<ReviewDb> db) throws Exception {
|
public Boolean callImpl(Provider<ReviewDb> db) throws Exception {
|
||||||
try {
|
try {
|
||||||
if (stalenessChecker.isStale(id)) {
|
if (stalenessChecker.isStale(id)) {
|
||||||
indexImpl(newChangeData(db.get(), project, id));
|
indexImpl(changeDataFactory.create(db.get(), project, id));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (NoSuchChangeException nsce) {
|
} catch (NoSuchChangeException nsce) {
|
||||||
@@ -460,26 +453,4 @@ public class ChangeIndexer {
|
|||||||
}
|
}
|
||||||
return false;
|
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;
|
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 com.google.gerrit.server.notedb.NoteDbTable.CHANGES;
|
||||||
import static java.util.Objects.requireNonNull;
|
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.config.AllUsersName;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.notedb.ChangeNotesCommit.ChangeNotesRevWalk;
|
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.gerrit.server.project.NoSuchChangeException;
|
||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -55,9 +54,6 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
|
|
||||||
// Providers required to avoid dependency cycles.
|
// Providers required to avoid dependency cycles.
|
||||||
|
|
||||||
// ChangeRebuilder -> ChangeNotes.Factory -> Args
|
|
||||||
final Provider<ChangeRebuilder> rebuilder;
|
|
||||||
|
|
||||||
// ChangeNoteCache -> Args
|
// ChangeNoteCache -> Args
|
||||||
final Provider<ChangeNotesCache> cache;
|
final Provider<ChangeNotesCache> cache;
|
||||||
|
|
||||||
@@ -70,7 +66,6 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
LegacyChangeNoteRead legacyChangeNoteRead,
|
LegacyChangeNoteRead legacyChangeNoteRead,
|
||||||
NoteDbMetrics metrics,
|
NoteDbMetrics metrics,
|
||||||
Provider<ReviewDb> db,
|
Provider<ReviewDb> db,
|
||||||
Provider<ChangeRebuilder> rebuilder,
|
|
||||||
Provider<ChangeNotesCache> cache) {
|
Provider<ChangeNotesCache> cache) {
|
||||||
this.repoManager = repoManager;
|
this.repoManager = repoManager;
|
||||||
this.migration = migration;
|
this.migration = migration;
|
||||||
@@ -79,7 +74,6 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
this.changeNoteJson = changeNoteJson;
|
this.changeNoteJson = changeNoteJson;
|
||||||
this.metrics = metrics;
|
this.metrics = metrics;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.rebuilder = rebuilder;
|
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,22 +108,14 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final Args args;
|
protected final Args args;
|
||||||
protected final PrimaryStorage primaryStorage;
|
|
||||||
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(
|
AbstractChangeNotes(Args args, Change.Id changeId) {
|
||||||
Args args, Change.Id changeId, @Nullable PrimaryStorage primaryStorage, boolean autoRebuild) {
|
|
||||||
this.args = requireNonNull(args);
|
this.args = requireNonNull(args);
|
||||||
this.changeId = requireNonNull(changeId);
|
this.changeId = requireNonNull(changeId);
|
||||||
this.primaryStorage = primaryStorage;
|
|
||||||
this.autoRebuild =
|
|
||||||
primaryStorage == PrimaryStorage.REVIEW_DB
|
|
||||||
&& !args.migration.disableChangeReviewDb()
|
|
||||||
&& autoRebuild;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Change.Id getChangeId() {
|
public Change.Id getChangeId() {
|
||||||
@@ -146,18 +132,7 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean read = args.migration.readChanges();
|
checkState(args.migration.readChanges(), "NoteDb is required to read changes");
|
||||||
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();
|
|
||||||
}
|
|
||||||
if (args.migration.failOnLoadForTest()) {
|
if (args.migration.failOnLoadForTest()) {
|
||||||
throw new OrmException("Reading from NoteDb is disabled");
|
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
|
// Call openHandle even if reading is disabled, to trigger
|
||||||
// auto-rebuilding before this object may get passed to a ChangeUpdate.
|
// auto-rebuilding before this object may get passed to a ChangeUpdate.
|
||||||
LoadHandle handle = openHandle(repo)) {
|
LoadHandle handle = openHandle(repo)) {
|
||||||
if (read) {
|
revision = handle.id();
|
||||||
revision = handle.id();
|
onLoad(handle);
|
||||||
onLoad(handle);
|
|
||||||
} else {
|
|
||||||
loadDefaults();
|
|
||||||
}
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
} catch (ConfigInvalidException | IOException e) {
|
} catch (ConfigInvalidException | IOException e) {
|
||||||
throw new OrmException(e);
|
throw new OrmException(e);
|
||||||
@@ -202,7 +173,7 @@ public abstract class AbstractChangeNotes<T> {
|
|||||||
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), id);
|
return LoadHandle.create(ChangeNotesCommit.newRevWalk(repo), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T reload() throws NoSuchChangeException, OrmException {
|
public T reload() throws OrmException {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
return load();
|
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.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.google.gerrit.reviewdb.client.RefNames.changeMetaRef;
|
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.Comparator.comparing;
|
||||||
import static java.util.Objects.requireNonNull;
|
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.common.flogger.FluentLogger;
|
||||||
import com.google.gerrit.common.Nullable;
|
import com.google.gerrit.common.Nullable;
|
||||||
import com.google.gerrit.common.data.SubmitRecord;
|
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.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Branch;
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
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.ReviewerSet;
|
||||||
import com.google.gerrit.server.ReviewerStatusUpdate;
|
import com.google.gerrit.server.ReviewerStatusUpdate;
|
||||||
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.notedb.NoteDbChangeState.PrimaryStorage;
|
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.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;
|
||||||
@@ -77,7 +73,6 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
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();
|
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
|
* 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.
|
* 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)
|
public ChangeNotes createForBatchUpdate(Change change, boolean shouldExist)
|
||||||
throws OrmException {
|
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)
|
public ChangeNotes create(Change change, RefCache refs) throws OrmException {
|
||||||
throws OrmException {
|
return new ChangeNotes(args, change, true, refs).load();
|
||||||
return new ChangeNotes(args, change, true, false, refs).load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(ekempin): Remove when database backend is deleted
|
// TODO(ekempin): Remove when database backend is deleted
|
||||||
@@ -459,7 +447,6 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
|||||||
// notes easier.
|
// notes easier.
|
||||||
RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
||||||
|
|
||||||
private NoteDbUpdateManager.Result rebuildResult;
|
|
||||||
private DraftCommentNotes draftCommentNotes;
|
private DraftCommentNotes draftCommentNotes;
|
||||||
private RobotCommentNotes robotCommentNotes;
|
private RobotCommentNotes robotCommentNotes;
|
||||||
|
|
||||||
@@ -471,12 +458,11 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public ChangeNotes(Args args, Change change) {
|
public ChangeNotes(Args args, Change change) {
|
||||||
this(args, change, true, true, null);
|
this(args, change, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChangeNotes(
|
private ChangeNotes(Args args, Change change, boolean shouldExist, @Nullable RefCache refs) {
|
||||||
Args args, Change change, boolean shouldExist, boolean autoRebuild, @Nullable RefCache refs) {
|
super(args, change.getId());
|
||||||
super(args, change.getId(), PrimaryStorage.of(change), autoRebuild);
|
|
||||||
this.change = new Change(change);
|
this.change = new Change(change);
|
||||||
this.shouldExist = shouldExist;
|
this.shouldExist = shouldExist;
|
||||||
this.refs = refs;
|
this.refs = refs;
|
||||||
@@ -609,8 +595,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
|||||||
*/
|
*/
|
||||||
private void loadDraftComments(Account.Id author, @Nullable Ref ref) throws OrmException {
|
private void loadDraftComments(Account.Id author, @Nullable Ref ref) throws OrmException {
|
||||||
if (draftCommentNotes == null || !author.equals(draftCommentNotes.getAuthor()) || ref != null) {
|
if (draftCommentNotes == null || !author.equals(draftCommentNotes.getAuthor()) || ref != null) {
|
||||||
draftCommentNotes =
|
draftCommentNotes = new DraftCommentNotes(args, getChangeId(), author, ref);
|
||||||
new DraftCommentNotes(args, change, author, autoRebuild, rebuildResult, ref);
|
|
||||||
draftCommentNotes.load();
|
draftCommentNotes.load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,8 +650,7 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLoad(LoadHandle handle)
|
protected void onLoad(LoadHandle handle) throws NoSuchChangeException, IOException {
|
||||||
throws NoSuchChangeException, IOException, ConfigInvalidException {
|
|
||||||
ObjectId rev = handle.id();
|
ObjectId rev = handle.id();
|
||||||
if (rev == null) {
|
if (rev == null) {
|
||||||
if (args.migration.readChanges()
|
if (args.migration.readChanges()
|
||||||
@@ -699,89 +683,4 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
|
|||||||
protected ObjectId readRef(Repository repo) throws IOException {
|
protected ObjectId readRef(Repository repo) throws IOException {
|
||||||
return refs != null ? refs.get(getRefName()).orElse(null) : super.readRef(repo);
|
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.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.gerrit.reviewdb.client.RefNames.refsDraftComments;
|
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 static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
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.collect.MultimapBuilder;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.google.gerrit.common.Nullable;
|
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.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.reviewdb.client.Comment;
|
import com.google.gerrit.reviewdb.client.Comment;
|
||||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.reviewdb.client.RevId;
|
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.Assisted;
|
||||||
import com.google.inject.assistedinject.AssistedInject;
|
import com.google.inject.assistedinject.AssistedInject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectReader;
|
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.lib.Repository;
|
||||||
import org.eclipse.jgit.notes.NoteMap;
|
import org.eclipse.jgit.notes.NoteMap;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
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. */
|
/** View of the draft comments for a single {@link Change} based on the log of its drafts branch. */
|
||||||
public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
DraftCommentNotes create(Change change, Account.Id accountId);
|
DraftCommentNotes create(Change.Id changeId, Account.Id accountId);
|
||||||
|
|
||||||
DraftCommentNotes createWithAutoRebuildingDisabled(Change.Id changeId, Account.Id accountId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Change change;
|
|
||||||
private final Account.Id author;
|
private final Account.Id author;
|
||||||
private final NoteDbUpdateManager.Result rebuildResult;
|
|
||||||
private final Ref ref;
|
private final Ref ref;
|
||||||
|
|
||||||
private ImmutableListMultimap<RevId, Comment> comments;
|
private ImmutableListMultimap<RevId, Comment> comments;
|
||||||
private RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
private RevisionNoteMap<ChangeRevisionNote> revisionNoteMap;
|
||||||
|
|
||||||
@AssistedInject
|
|
||||||
DraftCommentNotes(Args args, @Assisted Change change, @Assisted Account.Id author) {
|
|
||||||
this(args, change, author, true, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
DraftCommentNotes(Args args, @Assisted Change.Id changeId, @Assisted Account.Id author) {
|
DraftCommentNotes(Args args, @Assisted Change.Id changeId, @Assisted Account.Id author) {
|
||||||
// PrimaryStorage is unknown; this should only called by
|
this(args, changeId, author, null);
|
||||||
// PatchLineCommentsUtil#draftByAuthor, which can live with this.
|
|
||||||
super(args, changeId, null, false);
|
|
||||||
this.change = null;
|
|
||||||
this.author = author;
|
|
||||||
this.rebuildResult = null;
|
|
||||||
this.ref = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DraftCommentNotes(
|
DraftCommentNotes(Args args, Change.Id changeId, Account.Id author, @Nullable Ref ref) {
|
||||||
Args args,
|
super(args, changeId);
|
||||||
Change change,
|
this.author = requireNonNull(author);
|
||||||
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;
|
|
||||||
this.ref = ref;
|
this.ref = ref;
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
@@ -181,79 +147,6 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
|
|||||||
return args.allUsers;
|
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
|
@VisibleForTesting
|
||||||
NoteMap getNoteMap() {
|
NoteMap getNoteMap() {
|
||||||
return revisionNoteMap != null ? revisionNoteMap.noteMap : null;
|
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.RefNames;
|
||||||
import com.google.gerrit.reviewdb.client.RevId;
|
import com.google.gerrit.reviewdb.client.RevId;
|
||||||
import com.google.gerrit.reviewdb.client.RobotComment;
|
import com.google.gerrit.reviewdb.client.RobotComment;
|
||||||
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -49,7 +48,7 @@ public class RobotCommentNotes extends AbstractChangeNotes<RobotCommentNotes> {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RobotCommentNotes(Args args, @Assisted Change change) {
|
RobotCommentNotes(Args args, @Assisted Change change) {
|
||||||
super(args, change.getId(), PrimaryStorage.of(change), false);
|
super(args, change.getId());
|
||||||
this.change = change;
|
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.
|
// 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);
|
assertThat(draftNotes.load().getComments().get(rev1)).containsExactly(comment1, comment2);
|
||||||
|
|
||||||
// Zombie comment is filtered out of drafts via ChangeNotes.
|
// Zombie comment is filtered out of drafts via ChangeNotes.
|
||||||
|
|||||||
Reference in New Issue
Block a user