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 @Test
public void enableSequencesNoGap() throws Exception { public void enableSequencesNoGap() throws Exception {
testEnableSequences(0, 2, "12"); testEnableSequences(0, 3, "13");
} }
@Test @Test

View File

@@ -91,6 +91,7 @@ public class RepoSequence {
private final Project.NameKey projectName; private final Project.NameKey projectName;
private final String refName; private final String refName;
private final Seed seed; private final Seed seed;
private final int floor;
private final int batchSize; private final int batchSize;
private final Runnable afterReadRef; private final Runnable afterReadRef;
private final Retryer<RefUpdate.Result> retryer; private final Retryer<RefUpdate.Result> retryer;
@@ -118,7 +119,28 @@ public class RepoSequence {
seed, seed,
batchSize, batchSize,
Runnables.doNothing(), 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 @VisibleForTesting
@@ -131,6 +153,19 @@ public class RepoSequence {
int batchSize, int batchSize,
Runnable afterReadRef, Runnable afterReadRef,
Retryer<RefUpdate.Result> retryer) { 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.repoManager = checkNotNull(repoManager, "repoManager");
this.gitRefUpdated = checkNotNull(gitRefUpdated, "gitRefUpdated"); this.gitRefUpdated = checkNotNull(gitRefUpdated, "gitRefUpdated");
this.projectName = checkNotNull(projectName, "projectName"); this.projectName = checkNotNull(projectName, "projectName");
@@ -144,6 +179,7 @@ public class RepoSequence {
this.refName = RefNames.REFS_SEQUENCES + name; this.refName = RefNames.REFS_SEQUENCES + name;
this.seed = checkNotNull(seed, "seed"); this.seed = checkNotNull(seed, "seed");
this.floor = floor;
checkArgument(batchSize > 0, "expected batchSize > 0, got: %s", batchSize); checkArgument(batchSize > 0, "expected batchSize > 0, got: %s", batchSize);
this.batchSize = batchSize; this.batchSize = batchSize;
@@ -251,15 +287,17 @@ public class RepoSequence {
@Override @Override
public RefUpdate.Result call() throws Exception { public RefUpdate.Result call() throws Exception {
Ref ref = repo.exactRef(refName); Ref ref = repo.exactRef(refName);
int nextCandidate;
afterReadRef.run(); afterReadRef.run();
ObjectId oldId; ObjectId oldId;
if (ref == null) { if (ref == null) {
oldId = ObjectId.zeroId(); oldId = ObjectId.zeroId();
next = seed.get(); nextCandidate = seed.get();
} else { } else {
oldId = ref.getObjectId(); oldId = ref.getObjectId();
next = parse(oldId); nextCandidate = parse(oldId);
} }
next = Math.max(floor, nextCandidate);
return store(repo, rw, oldId, next + count); return store(repo, rw, oldId, next + count);
} }

View File

@@ -560,6 +560,8 @@ public class NoteDbMigrator implements AutoCloseable {
throws OrmException, IOException { throws OrmException, IOException {
try (ReviewDb db = schemaFactory.open()) { try (ReviewDb db = schemaFactory.open()) {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
final int nextChangeId = db.nextChangeId();
RepoSequence seq = RepoSequence seq =
new RepoSequence( new RepoSequence(
repoManager, 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 // 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 // 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. // would be a problem, but we just discard it, so this is safe.
() -> db.nextChangeId() + sequenceGap - 1, () -> nextChangeId + sequenceGap - 1,
1); 1,
nextChangeId);
seq.next(); seq.next();
} }
return saveState(prev, READ_WRITE_WITH_SEQUENCE_REVIEW_DB_PRIMARY); return saveState(prev, READ_WRITE_WITH_SEQUENCE_REVIEW_DB_PRIMARY);