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
This commit is contained in:
Luca Milanesio
2018-04-27 00:40:49 +01:00
parent 192dfd7bc6
commit 027e219e3d
3 changed files with 47 additions and 6 deletions

View File

@@ -335,7 +335,7 @@ public class OnlineNoteDbMigrationIT extends AbstractDaemonTest {
@Test
public void enableSequencesNoGap() throws Exception {
testEnableSequences(0, 2, "12");
testEnableSequences(0, 3, "13");
}
@Test

View File

@@ -91,6 +91,7 @@ public class RepoSequence {
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 @@ public class RepoSequence {
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 @@ public class RepoSequence {
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 @@ public class RepoSequence {
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 @@ public class RepoSequence {
@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);
}

View File

@@ -560,6 +560,8 @@ public class NoteDbMigrator implements AutoCloseable {
throws OrmException, IOException {
try (ReviewDb db = schemaFactory.open()) {
@SuppressWarnings("deprecation")
final int nextChangeId = db.nextChangeId();
RepoSequence seq =
new RepoSequence(
repoManager,
@@ -569,8 +571,9 @@ public class NoteDbMigrator implements AutoCloseable {
// 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);