Define a floor for NoteDb sequence generation
Make sure that new entities created with NoteDb sequences
are never below the floor value defined in ReviewDb when performing
a NoteDb migration.
Prevents any possible conflicts with existing change sequences
on ReviewDb once NoteDb is set as main active review store.
Bug: Issue 8861
Change-Id: Ica4529771fae6487b01708fb22193cf16ce73f82
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
index b8fb4c3..388c240 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/OnlineNoteDbMigrationIT.java
@@ -335,7 +335,7 @@
@Test
public void enableSequencesNoGap() throws Exception {
- testEnableSequences(0, 2, "12");
+ testEnableSequences(0, 3, "13");
}
@Test
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
index 777624a..11266f9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
@@ -91,6 +91,7 @@
private final Project.NameKey projectName;
private final String refName;
private final Seed seed;
+ private final int floor;
private final int batchSize;
private final Runnable afterReadRef;
private final Retryer<RefUpdate.Result> retryer;
@@ -118,7 +119,28 @@
seed,
batchSize,
Runnables.doNothing(),
- RETRYER);
+ RETRYER,
+ 0);
+ }
+
+ public RepoSequence(
+ GitRepositoryManager repoManager,
+ GitReferenceUpdated gitRefUpdated,
+ Project.NameKey projectName,
+ String name,
+ Seed seed,
+ int batchSize,
+ int floor) {
+ this(
+ repoManager,
+ gitRefUpdated,
+ projectName,
+ name,
+ seed,
+ batchSize,
+ Runnables.doNothing(),
+ RETRYER,
+ floor);
}
@VisibleForTesting
@@ -131,6 +153,19 @@
int batchSize,
Runnable afterReadRef,
Retryer<RefUpdate.Result> retryer) {
+ this(repoManager, gitRefUpdated, projectName, name, seed, batchSize, afterReadRef, retryer, 0);
+ }
+
+ RepoSequence(
+ GitRepositoryManager repoManager,
+ GitReferenceUpdated gitRefUpdated,
+ Project.NameKey projectName,
+ String name,
+ Seed seed,
+ int batchSize,
+ Runnable afterReadRef,
+ Retryer<RefUpdate.Result> retryer,
+ int floor) {
this.repoManager = checkNotNull(repoManager, "repoManager");
this.gitRefUpdated = checkNotNull(gitRefUpdated, "gitRefUpdated");
this.projectName = checkNotNull(projectName, "projectName");
@@ -144,6 +179,7 @@
this.refName = RefNames.REFS_SEQUENCES + name;
this.seed = checkNotNull(seed, "seed");
+ this.floor = floor;
checkArgument(batchSize > 0, "expected batchSize > 0, got: %s", batchSize);
this.batchSize = batchSize;
@@ -251,15 +287,17 @@
@Override
public RefUpdate.Result call() throws Exception {
Ref ref = repo.exactRef(refName);
+ int nextCandidate;
afterReadRef.run();
ObjectId oldId;
if (ref == null) {
oldId = ObjectId.zeroId();
- next = seed.get();
+ nextCandidate = seed.get();
} else {
oldId = ref.getObjectId();
- next = parse(oldId);
+ nextCandidate = parse(oldId);
}
+ next = Math.max(floor, nextCandidate);
return store(repo, rw, oldId, next + count);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
index df415ce..6db9e76 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/rebuild/NoteDbMigrator.java
@@ -560,6 +560,8 @@
throws OrmException, IOException {
try (ReviewDb db = schemaFactory.open()) {
@SuppressWarnings("deprecation")
+ final int nextChangeId = db.nextChangeId();
+
RepoSequence seq =
new RepoSequence(
repoManager,
@@ -569,8 +571,9 @@
// If sequenceGap is 0, this writes into the sequence ref the same ID that is returned
// by the call to seq.next() below. If we actually used this as a change ID, that
// would be a problem, but we just discard it, so this is safe.
- () -> db.nextChangeId() + sequenceGap - 1,
- 1);
+ () -> nextChangeId + sequenceGap - 1,
+ 1,
+ nextChangeId);
seq.next();
}
return saveState(prev, READ_WRITE_WITH_SEQUENCE_REVIEW_DB_PRIMARY);