diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java index 3f0db7733d..4917e65122 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java @@ -46,12 +46,12 @@ import com.google.gerrit.server.index.change.ChangeField; import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage; import com.google.gerrit.server.notedb.NoteDbChangeState.RefState; import com.google.gerrit.server.notedb.rebuild.ChangeRebuilder; -import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.update.BatchUpdate; import com.google.gerrit.server.update.BatchUpdateOp; import com.google.gerrit.server.update.ChangeContext; +import com.google.gerrit.server.update.RetryHelper; import com.google.gerrit.server.update.UpdateException; import com.google.gwtorm.server.AtomicUpdate; import com.google.gwtorm.server.OrmException; @@ -81,15 +81,27 @@ import org.slf4j.LoggerFactory; public class PrimaryStorageMigrator { private static final Logger log = LoggerFactory.getLogger(PrimaryStorageMigrator.class); + /** + * Exception thrown during migration if the change has no {@code noteDbState} field at the + * beginning of the migration. + */ + public static class NoNoteDbStateException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private NoNoteDbStateException(Change.Id id) { + super("change " + id + " has no note_db_state; rebuild it first"); + } + } + private final AllUsersName allUsers; - private final BatchUpdate.Factory batchUpdateFactory; - private final ChangeControl.GenericFactory changeControlFactory; + private final ChangeNotes.Factory changeNotesFactory; private final ChangeRebuilder rebuilder; private final ChangeUpdate.Factory updateFactory; private final GitRepositoryManager repoManager; private final InternalUser.Factory internalUserFactory; private final Provider<InternalChangeQuery> queryProvider; private final Provider<ReviewDb> db; + private final RetryHelper retryHelper; private final long skewMs; private final long timeoutMs; @@ -102,11 +114,11 @@ public class PrimaryStorageMigrator { GitRepositoryManager repoManager, AllUsersName allUsers, ChangeRebuilder rebuilder, - ChangeControl.GenericFactory changeControlFactory, + ChangeNotes.Factory changeNotesFactory, Provider<InternalChangeQuery> queryProvider, ChangeUpdate.Factory updateFactory, InternalUser.Factory internalUserFactory, - BatchUpdate.Factory batchUpdateFactory) { + RetryHelper retryHelper) { this( cfg, db, @@ -114,11 +126,11 @@ public class PrimaryStorageMigrator { allUsers, rebuilder, null, - changeControlFactory, + changeNotesFactory, queryProvider, updateFactory, internalUserFactory, - batchUpdateFactory); + retryHelper); } @VisibleForTesting @@ -129,21 +141,21 @@ public class PrimaryStorageMigrator { AllUsersName allUsers, ChangeRebuilder rebuilder, @Nullable Retryer<NoteDbChangeState> testEnsureRebuiltRetryer, - ChangeControl.GenericFactory changeControlFactory, + ChangeNotes.Factory changeNotesFactory, Provider<InternalChangeQuery> queryProvider, ChangeUpdate.Factory updateFactory, InternalUser.Factory internalUserFactory, - BatchUpdate.Factory batchUpdateFactory) { + RetryHelper retryHelper) { this.db = db; this.repoManager = repoManager; this.allUsers = allUsers; this.rebuilder = rebuilder; this.testEnsureRebuiltRetryer = testEnsureRebuiltRetryer; - this.changeControlFactory = changeControlFactory; + this.changeNotesFactory = changeNotesFactory; this.queryProvider = queryProvider; this.updateFactory = updateFactory; this.internalUserFactory = internalUserFactory; - this.batchUpdateFactory = batchUpdateFactory; + this.retryHelper = retryHelper; skewMs = NoteDbChangeState.getReadOnlySkew(cfg); String s = "notedb"; @@ -266,7 +278,7 @@ public class PrimaryStorageMigrator { // the primary storage to NoteDb. setPrimaryStorageNoteDb(id, rebuiltState); - log.info("Migrated change {} to NoteDb primary in {}ms", id, sw.elapsed(MILLISECONDS)); + log.debug("Migrated change {} to NoteDb primary in {}ms", id, sw.elapsed(MILLISECONDS)); } private Change setReadOnlyInReviewDb(Change.Id id) throws OrmException { @@ -281,9 +293,11 @@ public class PrimaryStorageMigrator { NoteDbChangeState state = NoteDbChangeState.parse(change); if (state == null) { // Could rebuild the change here, but that's more complexity, and this - // really shouldn't happen. - throw new OrmRuntimeException( - "change " + id + " has no note_db_state; rebuild it first"); + // normally shouldn't happen. + // + // Known cases where this happens are described in and handled by + // NoteDbMigrator#canSkipPrimaryStorageMigration. + throw new NoNoteDbStateException(id); } // If the change is already read-only, then the lease is held by another // (likely failed) migrator thread. Fail early, as we can't take over @@ -400,7 +414,7 @@ public class PrimaryStorageMigrator { rebuilder.rebuildReviewDb(db(), project, id); setPrimaryStorageReviewDb(id, newMetaId); releaseReadOnlyLeaseInNoteDb(project, id); - log.info("Migrated change {} to ReviewDb primary in {}ms", id, sw.elapsed(MILLISECONDS)); + log.debug("Migrated change {} to ReviewDb primary in {}ms", id, sw.elapsed(MILLISECONDS)); } private ObjectId setReadOnlyInNoteDb(Project.NameKey project, Change.Id id) @@ -409,7 +423,7 @@ public class PrimaryStorageMigrator { Timestamp until = new Timestamp(now.getTime() + timeoutMs); ChangeUpdate update = updateFactory.create( - changeControlFactory.controlFor(db.get(), project, id, internalUserFactory.create())); + changeNotesFactory.createChecked(db.get(), project, id), internalUserFactory.create()); update.setReadOnlyUntil(until); return update.commit(); } @@ -451,19 +465,27 @@ public class PrimaryStorageMigrator { private void releaseReadOnlyLeaseInNoteDb(Project.NameKey project, Change.Id id) throws OrmException { // Use a BatchUpdate since ReviewDb is primary at this point, so it needs to reflect the update. - try (BatchUpdate bu = - batchUpdateFactory.create( - db.get(), project, internalUserFactory.create(), TimeUtil.nowTs())) { - bu.addOp( - id, - new BatchUpdateOp() { - @Override - public boolean updateChange(ChangeContext ctx) { - ctx.getUpdate(ctx.getChange().currentPatchSetId()).setReadOnlyUntil(new Timestamp(0)); - return true; + // (In practice retrying won't happen, since we aren't using fused updates at this point.) + try { + retryHelper.execute( + updateFactory -> { + try (BatchUpdate bu = + updateFactory.create( + db.get(), project, internalUserFactory.create(), TimeUtil.nowTs())) { + bu.addOp( + id, + new BatchUpdateOp() { + @Override + public boolean updateChange(ChangeContext ctx) { + ctx.getUpdate(ctx.getChange().currentPatchSetId()) + .setReadOnlyUntil(new Timestamp(0)); + return true; + } + }); + bu.execute(); + return null; } }); - bu.execute(); } catch (RestApiException | UpdateException e) { throw new OrmException(e); } |