Remove config option to read account sequence numbers from ReviewDb
Accounts have been migrated to NoteDb, hence also the account sequence should be moved to NoteDb. Change-Id: I7da683e61b6ef0368efaec17b1f4562cf6a050ac Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -3285,17 +3285,6 @@ NoteDb is the next generation of Gerrit storage backend, currently powering
|
|||||||
`googlesource.com`. It is not (yet) recommended for general use, but if you want
|
`googlesource.com`. It is not (yet) recommended for general use, but if you want
|
||||||
to learn more, see the link:dev-note-db.html[developer documentation].
|
to learn more, see the link:dev-note-db.html[developer documentation].
|
||||||
|
|
||||||
[[notedb.accounts.readSequenceFromNoteDb]]notedb.accounts.readSequenceFromNoteDb::
|
|
||||||
+
|
|
||||||
Whether the account sequence should be read from NoteDb.
|
|
||||||
+
|
|
||||||
Once set to `true` this parameter cannot be set back to `false` because
|
|
||||||
the account sequence in ReviewDb will no longer be updated when account
|
|
||||||
IDs are retrieved from NoteDb, and hence the account sequence in
|
|
||||||
ReviewDb will be outdated.
|
|
||||||
+
|
|
||||||
By default `false`.
|
|
||||||
|
|
||||||
[[notedb.accounts.sequenceBatchSize]]notedb.accounts.sequenceBatchSize::
|
[[notedb.accounts.sequenceBatchSize]]notedb.accounts.sequenceBatchSize::
|
||||||
+
|
+
|
||||||
The current account sequence number is stored as UTF-8 text in a blob
|
The current account sequence number is stored as UTF-8 text in a blob
|
||||||
@@ -3307,9 +3296,6 @@ hand out numbers from that range in memory until they run out. This
|
|||||||
configuration parameter controls the size of the account ID batch that
|
configuration parameter controls the size of the account ID batch that
|
||||||
each process retrieves at once.
|
each process retrieves at once.
|
||||||
+
|
+
|
||||||
Only relevant if link:#notedb.accounts.readSequenceFromNoteDb[
|
|
||||||
notedb.accounts.readSequenceFromNoteDb] is set to `true`.
|
|
||||||
+
|
|
||||||
By default, 1.
|
By default, 1.
|
||||||
|
|
||||||
[[oauth]]
|
[[oauth]]
|
||||||
|
@@ -32,11 +32,8 @@ import com.google.gerrit.server.account.VersionedAuthorizedKeys;
|
|||||||
import com.google.gerrit.server.account.externalids.ExternalId;
|
import com.google.gerrit.server.account.externalids.ExternalId;
|
||||||
import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
|
import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
|
||||||
import com.google.gerrit.server.ssh.SshKeyCache;
|
import com.google.gerrit.server.ssh.SshKeyCache;
|
||||||
import com.google.gerrit.server.util.ManualRequestContext;
|
|
||||||
import com.google.gerrit.server.util.OneOffRequestContext;
|
|
||||||
import com.google.gwtorm.server.SchemaFactory;
|
import com.google.gwtorm.server.SchemaFactory;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import com.jcraft.jsch.JSch;
|
import com.jcraft.jsch.JSch;
|
||||||
import com.jcraft.jsch.JSchException;
|
import com.jcraft.jsch.JSchException;
|
||||||
@@ -54,8 +51,7 @@ public class AccountCreator {
|
|||||||
private final Map<String, TestAccount> accounts;
|
private final Map<String, TestAccount> accounts;
|
||||||
|
|
||||||
private final SchemaFactory<ReviewDb> reviewDbProvider;
|
private final SchemaFactory<ReviewDb> reviewDbProvider;
|
||||||
private final OneOffRequestContext oneOffRequestContext;
|
private final Sequences sequences;
|
||||||
private final Provider<Sequences> sequencesProvider;
|
|
||||||
private final AccountsUpdate.Server accountsUpdate;
|
private final AccountsUpdate.Server accountsUpdate;
|
||||||
private final VersionedAuthorizedKeys.Accessor authorizedKeys;
|
private final VersionedAuthorizedKeys.Accessor authorizedKeys;
|
||||||
private final GroupCache groupCache;
|
private final GroupCache groupCache;
|
||||||
@@ -68,8 +64,7 @@ public class AccountCreator {
|
|||||||
@Inject
|
@Inject
|
||||||
AccountCreator(
|
AccountCreator(
|
||||||
SchemaFactory<ReviewDb> schema,
|
SchemaFactory<ReviewDb> schema,
|
||||||
OneOffRequestContext oneOffRequestContext,
|
Sequences sequences,
|
||||||
Provider<Sequences> sequencesProvider,
|
|
||||||
AccountsUpdate.Server accountsUpdate,
|
AccountsUpdate.Server accountsUpdate,
|
||||||
VersionedAuthorizedKeys.Accessor authorizedKeys,
|
VersionedAuthorizedKeys.Accessor authorizedKeys,
|
||||||
GroupCache groupCache,
|
GroupCache groupCache,
|
||||||
@@ -80,8 +75,7 @@ public class AccountCreator {
|
|||||||
@SshEnabled boolean sshEnabled) {
|
@SshEnabled boolean sshEnabled) {
|
||||||
accounts = new HashMap<>();
|
accounts = new HashMap<>();
|
||||||
reviewDbProvider = schema;
|
reviewDbProvider = schema;
|
||||||
this.oneOffRequestContext = oneOffRequestContext;
|
this.sequences = sequences;
|
||||||
this.sequencesProvider = sequencesProvider;
|
|
||||||
this.accountsUpdate = accountsUpdate;
|
this.accountsUpdate = accountsUpdate;
|
||||||
this.authorizedKeys = authorizedKeys;
|
this.authorizedKeys = authorizedKeys;
|
||||||
this.groupCache = groupCache;
|
this.groupCache = groupCache;
|
||||||
@@ -103,9 +97,8 @@ public class AccountCreator {
|
|||||||
if (account != null) {
|
if (account != null) {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
try (ReviewDb db = reviewDbProvider.open();
|
try (ReviewDb db = reviewDbProvider.open()) {
|
||||||
ManualRequestContext ctx = oneOffRequestContext.open()) {
|
Account.Id id = new Account.Id(sequences.nextAccountId());
|
||||||
Account.Id id = new Account.Id(sequencesProvider.get().nextAccountId());
|
|
||||||
|
|
||||||
List<ExternalId> extIds = new ArrayList<>(2);
|
List<ExternalId> extIds = new ArrayList<>(2);
|
||||||
String httpPass = null;
|
String httpPass = null;
|
||||||
|
@@ -54,7 +54,6 @@ public class Sequences {
|
|||||||
|
|
||||||
private final Provider<ReviewDb> db;
|
private final Provider<ReviewDb> db;
|
||||||
private final NotesMigration migration;
|
private final NotesMigration migration;
|
||||||
private final boolean readAccountSeqFromNoteDb;
|
|
||||||
private final RepoSequence accountSeq;
|
private final RepoSequence accountSeq;
|
||||||
private final RepoSequence changeSeq;
|
private final RepoSequence changeSeq;
|
||||||
private final Timer2<SequenceType, Boolean> nextIdLatency;
|
private final Timer2<SequenceType, Boolean> nextIdLatency;
|
||||||
@@ -71,18 +70,14 @@ public class Sequences {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.migration = migration;
|
this.migration = migration;
|
||||||
|
|
||||||
readAccountSeqFromNoteDb =
|
|
||||||
cfg.getBoolean("noteDb", "accounts", "readSequenceFromNoteDb", false);
|
|
||||||
|
|
||||||
// It's intentional to not use any configured gap for the account sequence unlike we do for the
|
|
||||||
// change sequence. For the account sequence we have a different migration strategy that
|
|
||||||
// doesn't require any gap.
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
RepoSequence.Seed accountSeed = () -> db.get().nextAccountId();
|
|
||||||
|
|
||||||
int accountBatchSize = cfg.getInt("noteDb", "accounts", "sequenceBatchSize", 1);
|
int accountBatchSize = cfg.getInt("noteDb", "accounts", "sequenceBatchSize", 1);
|
||||||
accountSeq =
|
accountSeq =
|
||||||
new RepoSequence(repoManager, allUsers, NAME_ACCOUNTS, accountSeed, accountBatchSize);
|
new RepoSequence(
|
||||||
|
repoManager,
|
||||||
|
allUsers,
|
||||||
|
NAME_ACCOUNTS,
|
||||||
|
() -> ReviewDb.FIRST_ACCOUNT_ID,
|
||||||
|
accountBatchSize);
|
||||||
|
|
||||||
int gap = getChangeSequenceGap(cfg);
|
int gap = getChangeSequenceGap(cfg);
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@@ -102,15 +97,9 @@ public class Sequences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int nextAccountId() throws OrmException {
|
public int nextAccountId() throws OrmException {
|
||||||
if (readAccountSeqFromNoteDb) {
|
try (Timer2.Context timer = nextIdLatency.start(SequenceType.ACCOUNTS, false)) {
|
||||||
try (Timer2.Context timer = nextIdLatency.start(SequenceType.ACCOUNTS, false)) {
|
return accountSeq.next();
|
||||||
return accountSeq.next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int accountId = nextAccountId(db.get());
|
|
||||||
accountSeq.increaseTo(accountId + 1); // NoteDb stores next available account ID.
|
|
||||||
return accountId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int nextChangeId() throws OrmException {
|
public int nextChangeId() throws OrmException {
|
||||||
|
@@ -34,8 +34,6 @@ import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
|
|||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.query.account.InternalAccountQuery;
|
import com.google.gerrit.server.query.account.InternalAccountQuery;
|
||||||
import com.google.gerrit.server.util.ManualRequestContext;
|
|
||||||
import com.google.gerrit.server.util.OneOffRequestContext;
|
|
||||||
import com.google.gwtorm.server.OrmException;
|
import com.google.gwtorm.server.OrmException;
|
||||||
import com.google.gwtorm.server.SchemaFactory;
|
import com.google.gwtorm.server.SchemaFactory;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -60,8 +58,7 @@ public class AccountManager {
|
|||||||
private static final Logger log = LoggerFactory.getLogger(AccountManager.class);
|
private static final Logger log = LoggerFactory.getLogger(AccountManager.class);
|
||||||
|
|
||||||
private final SchemaFactory<ReviewDb> schema;
|
private final SchemaFactory<ReviewDb> schema;
|
||||||
private final OneOffRequestContext oneOffRequestContext;
|
private final Sequences sequences;
|
||||||
private final Provider<Sequences> sequencesProvider;
|
|
||||||
private final Accounts accounts;
|
private final Accounts accounts;
|
||||||
private final AccountsUpdate.Server accountsUpdateFactory;
|
private final AccountsUpdate.Server accountsUpdateFactory;
|
||||||
private final AccountCache byIdCache;
|
private final AccountCache byIdCache;
|
||||||
@@ -79,8 +76,7 @@ public class AccountManager {
|
|||||||
@Inject
|
@Inject
|
||||||
AccountManager(
|
AccountManager(
|
||||||
SchemaFactory<ReviewDb> schema,
|
SchemaFactory<ReviewDb> schema,
|
||||||
OneOffRequestContext oneOffRequestContext,
|
Sequences sequences,
|
||||||
Provider<Sequences> sequencesProvider,
|
|
||||||
@GerritServerConfig Config cfg,
|
@GerritServerConfig Config cfg,
|
||||||
Accounts accounts,
|
Accounts accounts,
|
||||||
AccountsUpdate.Server accountsUpdateFactory,
|
AccountsUpdate.Server accountsUpdateFactory,
|
||||||
@@ -95,8 +91,7 @@ public class AccountManager {
|
|||||||
ExternalIds externalIds,
|
ExternalIds externalIds,
|
||||||
ExternalIdsUpdate.Server externalIdsUpdateFactory) {
|
ExternalIdsUpdate.Server externalIdsUpdateFactory) {
|
||||||
this.schema = schema;
|
this.schema = schema;
|
||||||
this.oneOffRequestContext = oneOffRequestContext;
|
this.sequences = sequences;
|
||||||
this.sequencesProvider = sequencesProvider;
|
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
this.accountsUpdateFactory = accountsUpdateFactory;
|
this.accountsUpdateFactory = accountsUpdateFactory;
|
||||||
this.byIdCache = byIdCache;
|
this.byIdCache = byIdCache;
|
||||||
@@ -214,10 +209,7 @@ public class AccountManager {
|
|||||||
|
|
||||||
private AuthResult create(ReviewDb db, AuthRequest who)
|
private AuthResult create(ReviewDb db, AuthRequest who)
|
||||||
throws OrmException, AccountException, IOException, ConfigInvalidException {
|
throws OrmException, AccountException, IOException, ConfigInvalidException {
|
||||||
Account.Id newId;
|
Account.Id newId = new Account.Id(sequences.nextAccountId());
|
||||||
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
|
|
||||||
newId = new Account.Id(sequencesProvider.get().nextAccountId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternalId extId =
|
ExternalId extId =
|
||||||
ExternalId.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
|
ExternalId.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
|
||||||
|
@@ -194,27 +194,6 @@ public class RepoSequence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increaseTo(int val) throws OrmException {
|
|
||||||
counterLock.lock();
|
|
||||||
try {
|
|
||||||
try (Repository repo = repoManager.openRepository(projectName);
|
|
||||||
RevWalk rw = new RevWalk(repo)) {
|
|
||||||
TryIncreaseTo attempt = new TryIncreaseTo(repo, rw, val);
|
|
||||||
checkResult(retryer.call(attempt));
|
|
||||||
counter = limit;
|
|
||||||
} catch (ExecutionException | RetryException e) {
|
|
||||||
if (e.getCause() != null) {
|
|
||||||
Throwables.throwIfInstanceOf(e.getCause(), OrmException.class);
|
|
||||||
}
|
|
||||||
throw new OrmException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new OrmException(e);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
counterLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void acquire(int count) throws OrmException {
|
private void acquire(int count) throws OrmException {
|
||||||
try (Repository repo = repoManager.openRepository(projectName);
|
try (Repository repo = repoManager.openRepository(projectName);
|
||||||
RevWalk rw = new RevWalk(repo)) {
|
RevWalk rw = new RevWalk(repo)) {
|
||||||
@@ -234,9 +213,7 @@ public class RepoSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkResult(RefUpdate.Result result) throws OrmException {
|
private void checkResult(RefUpdate.Result result) throws OrmException {
|
||||||
if (result != RefUpdate.Result.NEW
|
if (result != RefUpdate.Result.NEW && result != RefUpdate.Result.FORCED) {
|
||||||
&& result != RefUpdate.Result.FORCED
|
|
||||||
&& result != RefUpdate.Result.NO_CHANGE) {
|
|
||||||
throw new OrmException("failed to update " + refName + ": " + result);
|
throw new OrmException("failed to update " + refName + ": " + result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,57 +241,27 @@ public class RepoSequence {
|
|||||||
next = seed.get();
|
next = seed.get();
|
||||||
} else {
|
} else {
|
||||||
oldId = ref.getObjectId();
|
oldId = ref.getObjectId();
|
||||||
next = parse(rw, oldId);
|
next = parse(oldId);
|
||||||
}
|
}
|
||||||
return store(repo, rw, oldId, next + count);
|
return store(repo, rw, oldId, next + count);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class TryIncreaseTo implements Callable<RefUpdate.Result> {
|
private int parse(ObjectId id) throws IOException, OrmException {
|
||||||
private final Repository repo;
|
ObjectLoader ol = rw.getObjectReader().open(id, OBJ_BLOB);
|
||||||
private final RevWalk rw;
|
if (ol.getType() != OBJ_BLOB) {
|
||||||
private final int value;
|
// In theory this should be thrown by open but not all implementations
|
||||||
|
// may do it properly (certainly InMemoryRepository doesn't).
|
||||||
private TryIncreaseTo(Repository repo, RevWalk rw, int value) {
|
throw new IncorrectObjectTypeException(id, OBJ_BLOB);
|
||||||
this.repo = repo;
|
|
||||||
this.rw = rw;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RefUpdate.Result call() throws Exception {
|
|
||||||
Ref ref = repo.exactRef(refName);
|
|
||||||
afterReadRef.run();
|
|
||||||
ObjectId oldId;
|
|
||||||
if (ref == null) {
|
|
||||||
oldId = ObjectId.zeroId();
|
|
||||||
} else {
|
|
||||||
oldId = ref.getObjectId();
|
|
||||||
int next = parse(rw, oldId);
|
|
||||||
if (next >= value) {
|
|
||||||
// a concurrent write updated the ref already to this or a higher value
|
|
||||||
return RefUpdate.Result.NO_CHANGE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return store(repo, rw, oldId, value);
|
String str = CharMatcher.whitespace().trimFrom(new String(ol.getCachedBytes(), UTF_8));
|
||||||
|
Integer val = Ints.tryParse(str);
|
||||||
|
if (val == null) {
|
||||||
|
throw new OrmException("invalid value in " + refName + " blob at " + id.name());
|
||||||
|
}
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parse(RevWalk rw, ObjectId id) throws IOException, OrmException {
|
|
||||||
ObjectLoader ol = rw.getObjectReader().open(id, OBJ_BLOB);
|
|
||||||
if (ol.getType() != OBJ_BLOB) {
|
|
||||||
// In theory this should be thrown by open but not all implementations
|
|
||||||
// may do it properly (certainly InMemoryRepository doesn't).
|
|
||||||
throw new IncorrectObjectTypeException(id, OBJ_BLOB);
|
|
||||||
}
|
|
||||||
String str = CharMatcher.whitespace().trimFrom(new String(ol.getCachedBytes(), UTF_8));
|
|
||||||
Integer val = Ints.tryParse(str);
|
|
||||||
if (val == null) {
|
|
||||||
throw new OrmException("invalid value in " + refName + " blob at " + id.name());
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RefUpdate.Result store(Repository repo, RevWalk rw, @Nullable ObjectId oldId, int val)
|
private RefUpdate.Result store(Repository repo, RevWalk rw, @Nullable ObjectId oldId, int val)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
ObjectId newId;
|
ObjectId newId;
|
||||||
|
@@ -253,95 +253,6 @@ public class RepoSequenceTest {
|
|||||||
assertThat(s2.acquireCount).isEqualTo(1);
|
assertThat(s2.acquireCount).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void increaseTo() throws Exception {
|
|
||||||
// Seed existing ref value.
|
|
||||||
writeBlob("id", "1");
|
|
||||||
|
|
||||||
RepoSequence s = newSequence("id", 1, 10);
|
|
||||||
|
|
||||||
s.increaseTo(2);
|
|
||||||
assertThat(s.next()).isEqualTo(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void increaseToLowerValueIsIgnored() throws Exception {
|
|
||||||
// Seed existing ref value.
|
|
||||||
writeBlob("id", "2");
|
|
||||||
|
|
||||||
RepoSequence s = newSequence("id", 1, 10);
|
|
||||||
|
|
||||||
s.increaseTo(1);
|
|
||||||
assertThat(s.next()).isEqualTo(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void increaseToRetryOnLockFailureV1() throws Exception {
|
|
||||||
// Seed existing ref value.
|
|
||||||
writeBlob("id", "1");
|
|
||||||
|
|
||||||
AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
|
|
||||||
Runnable bgUpdate =
|
|
||||||
() -> {
|
|
||||||
if (!doneBgUpdate.getAndSet(true)) {
|
|
||||||
writeBlob("id", "2");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
RepoSequence s = newSequence("id", 1, 10, bgUpdate, RETRYER);
|
|
||||||
assertThat(doneBgUpdate.get()).isFalse();
|
|
||||||
|
|
||||||
// Increase the value to 3. The background thread increases the value to 2, which makes the
|
|
||||||
// increase to value 3 fail once with LockFailure. The increase to 3 is then retried and is
|
|
||||||
// expected to succeed.
|
|
||||||
s.increaseTo(3);
|
|
||||||
assertThat(s.next()).isEqualTo(3);
|
|
||||||
|
|
||||||
assertThat(doneBgUpdate.get()).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void increaseToRetryOnLockFailureV2() throws Exception {
|
|
||||||
// Seed existing ref value.
|
|
||||||
writeBlob("id", "1");
|
|
||||||
|
|
||||||
AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
|
|
||||||
Runnable bgUpdate =
|
|
||||||
() -> {
|
|
||||||
if (!doneBgUpdate.getAndSet(true)) {
|
|
||||||
writeBlob("id", "3");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
RepoSequence s = newSequence("id", 1, 10, bgUpdate, RETRYER);
|
|
||||||
assertThat(doneBgUpdate.get()).isFalse();
|
|
||||||
|
|
||||||
// Increase the value to 2. The background thread increases the value to 3, which makes the
|
|
||||||
// increase to value 2 fail with LockFailure. The increase to 2 is then not retried because the
|
|
||||||
// current value is already higher and it should be preserved.
|
|
||||||
s.increaseTo(2);
|
|
||||||
assertThat(s.next()).isEqualTo(3);
|
|
||||||
|
|
||||||
assertThat(doneBgUpdate.get()).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void increaseToFailAfterRetryerGivesUp() throws Exception {
|
|
||||||
AtomicInteger bgCounter = new AtomicInteger(1234);
|
|
||||||
RepoSequence s =
|
|
||||||
newSequence(
|
|
||||||
"id",
|
|
||||||
1,
|
|
||||||
10,
|
|
||||||
() -> writeBlob("id", Integer.toString(bgCounter.getAndAdd(1000))),
|
|
||||||
RetryerBuilder.<RefUpdate.Result>newBuilder()
|
|
||||||
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
|
|
||||||
.build());
|
|
||||||
exception.expect(OrmException.class);
|
|
||||||
exception.expectMessage("failed to update refs/sequences/id: LOCK_FAILURE");
|
|
||||||
s.increaseTo(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RepoSequence newSequence(String name, int start, int batchSize) {
|
private RepoSequence newSequence(String name, int start, int batchSize) {
|
||||||
return newSequence(name, start, batchSize, Runnables.doNothing(), RETRYER);
|
return newSequence(name, start, batchSize, Runnables.doNothing(), RETRYER);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user