Search in sources :

Example 1 with BlockStrategy

use of com.github.rholder.retry.BlockStrategy in project gerrit by GerritCodeReview.

the class ExternalIdIT method retryOnLockFailure.

@Test
public void retryOnLockFailure() throws Exception {
    Retryer<RefsMetaExternalIdsUpdate> retryer = ExternalIdsUpdate.retryerBuilder().withBlockStrategy(new BlockStrategy() {

        @Override
        public void block(long sleepTime) {
        // Don't sleep in tests.
        }
    }).build();
    ExternalId.Key fooId = ExternalId.Key.create("foo", "foo");
    ExternalId.Key barId = ExternalId.Key.create("bar", "bar");
    final AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
    ExternalIdsUpdate update = new ExternalIdsUpdate(repoManager, allUsers, metricMaker, externalIds, new DisabledExternalIdCache(), serverIdent.get(), serverIdent.get(), () -> {
        if (!doneBgUpdate.getAndSet(true)) {
            try {
                extIdsUpdate.create().insert(ExternalId.create(barId, admin.id));
            } catch (IOException | ConfigInvalidException | OrmException e) {
            // Ignore, the successful insertion of the external ID is asserted later
            }
        }
    }, retryer);
    assertThat(doneBgUpdate.get()).isFalse();
    update.insert(ExternalId.create(fooId, admin.id));
    assertThat(doneBgUpdate.get()).isTrue();
    assertThat(externalIds.get(fooId)).isNotNull();
    assertThat(externalIds.get(barId)).isNotNull();
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ConfigInvalidException(org.eclipse.jgit.errors.ConfigInvalidException) RefsMetaExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate) OrmException(com.google.gwtorm.server.OrmException) ExternalId(com.google.gerrit.server.account.externalids.ExternalId) ExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate) RefsMetaExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate) IOException(java.io.IOException) BlockStrategy(com.github.rholder.retry.BlockStrategy) DisabledExternalIdCache(com.google.gerrit.server.account.externalids.DisabledExternalIdCache) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest) Test(org.junit.Test)

Example 2 with BlockStrategy

use of com.github.rholder.retry.BlockStrategy in project gerrit by GerritCodeReview.

the class RepoSequenceTest method idCanBeRetrievedFromOtherThreadWhileWaitingToRetry.

@Test
public void idCanBeRetrievedFromOtherThreadWhileWaitingToRetry() throws Exception {
    // Seed existing ref value.
    writeBlob("id", "1");
    // Let the first update of the sequence fail with LOCK_FAILURE, so that the update is retried.
    CountDownLatch lockFailure = new CountDownLatch(1);
    CountDownLatch parallelSuccessfulSequenceGeneration = new CountDownLatch(1);
    AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
    Runnable bgUpdate = () -> {
        if (!doneBgUpdate.getAndSet(true)) {
            writeBlob("id", "1234");
        }
    };
    BlockStrategy blockStrategy = t -> {
        // Keep blocking until we verified that another thread can retrieve a sequence number
        // while we are blocking here.
        lockFailure.countDown();
        parallelSuccessfulSequenceGeneration.await();
    };
    // Use batch size = 1 to make each call go to NoteDb.
    RepoSequence s = newSequence("id", 1, 1, bgUpdate, RepoSequence.retryerBuilder().withBlockStrategy(blockStrategy).build());
    assertThat(doneBgUpdate.get()).isFalse();
    // Start a thread to get a sequence number. This thread needs to update the sequence in NoteDb,
    // but due to the background update (see bgUpdate) the first attempt to update NoteDb fails
    // with LOCK_FAILURE. RepoSequence uses a retryer to retry the NoteDb update on LOCK_FAILURE,
    // but our block strategy ensures that this retry only happens after isBlocking was set to
    // false.
    Future<?> future = Executors.newFixedThreadPool(1).submit(() -> {
        // The background update sets the next available sequence number to 1234. Then the
        // test thread retrieves one sequence number, so that the next available sequence
        // number for this thread is 1235.
        expect.that(s.next()).isEqualTo(1235);
    });
    // Wait until the LOCK_FAILURE has happened and the block strategy was entered.
    lockFailure.await();
    // Verify that the background update was done now.
    assertThat(doneBgUpdate.get()).isTrue();
    // Verify that we can retrieve a sequence number while the other thread is blocked. If the
    // s.next() call hangs it means that the RepoSequence.counterLock was not released before the
    // background thread started to block for retry. In this case the test would time out.
    assertThat(s.next()).isEqualTo(1234);
    // Stop blocking the retry of the background thread (and verify that it was still blocked).
    parallelSuccessfulSequenceGeneration.countDown();
    // Wait until the background thread is done.
    future.get();
    // Two successful acquire calls (because batch size == 1).
    assertThat(s.acquireCount).isEqualTo(2);
}
Also used : ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) OBJ_BLOB(org.eclipse.jgit.lib.Constants.OBJ_BLOB) IncorrectObjectTypeException(org.eclipse.jgit.errors.IncorrectObjectTypeException) Retryer(com.github.rholder.retry.Retryer) RetryerBuilder(com.github.rholder.retry.RetryerBuilder) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) BlockStrategy(com.github.rholder.retry.BlockStrategy) RevWalk(org.eclipse.jgit.revwalk.RevWalk) Future(java.util.concurrent.Future) ImmutableList(com.google.common.collect.ImmutableList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Runnables(com.google.common.util.concurrent.Runnables) RefNames(com.google.gerrit.entities.RefNames) Before(org.junit.Before) Expect(com.google.common.truth.Expect) TestRepository(org.eclipse.jgit.junit.TestRepository) Truth.assertWithMessage(com.google.common.truth.Truth.assertWithMessage) UTF_8(java.nio.charset.StandardCharsets.UTF_8) StorageException(com.google.gerrit.exceptions.StorageException) RefUpdate(org.eclipse.jgit.lib.RefUpdate) IOException(java.io.IOException) Test(org.junit.Test) Truth.assertThat(com.google.common.truth.Truth.assertThat) Executors(java.util.concurrent.Executors) ObjectId(org.eclipse.jgit.lib.ObjectId) CountDownLatch(java.util.concurrent.CountDownLatch) Rule(org.junit.Rule) StopStrategies(com.github.rholder.retry.StopStrategies) Project(com.google.gerrit.entities.Project) InMemoryRepositoryManager(com.google.gerrit.testing.InMemoryRepositoryManager) GerritJUnit.assertThrows(com.google.gerrit.testing.GerritJUnit.assertThrows) GitReferenceUpdated(com.google.gerrit.server.extensions.events.GitReferenceUpdated) Repository(org.eclipse.jgit.lib.Repository) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CountDownLatch(java.util.concurrent.CountDownLatch) BlockStrategy(com.github.rholder.retry.BlockStrategy) Test(org.junit.Test)

Aggregations

BlockStrategy (com.github.rholder.retry.BlockStrategy)2 IOException (java.io.IOException)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 Test (org.junit.Test)2 Retryer (com.github.rholder.retry.Retryer)1 RetryerBuilder (com.github.rholder.retry.RetryerBuilder)1 StopStrategies (com.github.rholder.retry.StopStrategies)1 ImmutableList (com.google.common.collect.ImmutableList)1 Expect (com.google.common.truth.Expect)1 Truth.assertThat (com.google.common.truth.Truth.assertThat)1 Truth.assertWithMessage (com.google.common.truth.Truth.assertWithMessage)1 Runnables (com.google.common.util.concurrent.Runnables)1 AbstractDaemonTest (com.google.gerrit.acceptance.AbstractDaemonTest)1 Project (com.google.gerrit.entities.Project)1 RefNames (com.google.gerrit.entities.RefNames)1 StorageException (com.google.gerrit.exceptions.StorageException)1 DisabledExternalIdCache (com.google.gerrit.server.account.externalids.DisabledExternalIdCache)1 ExternalId (com.google.gerrit.server.account.externalids.ExternalId)1 ExternalIdsUpdate (com.google.gerrit.server.account.externalids.ExternalIdsUpdate)1 RefsMetaExternalIdsUpdate (com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate)1