Search in sources :

Example 1 with DataOperationOrderer

use of org.infinispan.util.concurrent.DataOperationOrderer in project infinispan by infinispan.

the class EvictionWithConcurrentOperationsTest method testEvictionDuring.

/**
 * Tests that an entry was written to container, but before it releases its orderer it is evicted
 */
void testEvictionDuring(String key, Callable<Object> callable, Consumer<Object> valueConsumer, Consumer<Object> finalResultConsumer, boolean blockOnCompletion) throws TimeoutException, InterruptedException, ExecutionException {
    // We use this checkpoint to hold the orderer lock during the write - which means the eviction will have to handle
    // it appropriately
    CheckPoint operationCheckPoint = new CheckPoint("operation");
    operationCheckPoint.triggerForever(blockOnCompletion ? Mocks.AFTER_RELEASE : Mocks.BEFORE_RELEASE);
    DataOperationOrderer original;
    if (blockOnCompletion) {
        // Blocks just before releasing the orderer
        original = Mocks.blockingMock(operationCheckPoint, DataOperationOrderer.class, cache, (stub, m) -> stub.when(m).completeOperation(eq(key), any(), any()));
    } else {
        // Blocks just after acquiring orderer
        original = Mocks.blockingMock(operationCheckPoint, DataOperationOrderer.class, cache, (stub, m) -> stub.when(m).orderOn(eq(key), any()));
    }
    // Put the key which will wait on releasing the orderer at the end
    Future<Object> operationFuture = fork(callable);
    // Confirm everything is complete except releasing orderer
    operationCheckPoint.awaitStrict(Mocks.BEFORE_INVOCATION, 10, TimeUnit.SECONDS);
    // Replace the original so the eviction doesn't get blocked by the other check point
    TestingUtil.replaceComponent(cache, DataOperationOrderer.class, original, true);
    // We use this checkpoint to wait until the eviction is in process (that is that it has the caffeine lock
    // and has to wait until the prior orderer above completes
    CheckPoint evictionCheckPoint = new CheckPoint("eviction");
    evictionCheckPoint.triggerForever(Mocks.BEFORE_RELEASE);
    Mocks.blockingMock(evictionCheckPoint, DataOperationOrderer.class, cache, (stub, m) -> stub.when(m).orderOn(eq(key), any()));
    // Put another key, which will evict our original key
    Future<Object> evictFuture = fork(() -> cache.put("other-key", "other-value"));
    // Now wait for the eviction to retrieve the orderer - but don't let it continue
    evictionCheckPoint.awaitStrict(Mocks.AFTER_INVOCATION, 10, TimeUnit.SECONDS);
    // Let the put complete
    operationCheckPoint.trigger(blockOnCompletion ? Mocks.BEFORE_RELEASE : Mocks.AFTER_RELEASE);
    // be preventing the actual operation from completing - thus we free the eviction sooner
    if (!blockOnCompletion) {
        evictionCheckPoint.triggerForever(Mocks.AFTER_RELEASE);
    }
    // And ensure the operation complete
    valueConsumer.accept(operationFuture.get(10, TimeUnit.SECONDS));
    // Finally let the eviction to complete if it wasn't above
    evictionCheckPoint.triggerForever(Mocks.AFTER_RELEASE);
    evictFuture.get(10, TimeUnit.SECONDS);
    finalResultConsumer.accept(cache.get(key));
}
Also used : CompletionStages.join(org.infinispan.util.concurrent.CompletionStages.join) Arrays(java.util.Arrays) EntryWrappingInterceptor(org.infinispan.interceptors.impl.EntryWrappingInterceptor) CheckPoint(org.infinispan.test.fwk.CheckPoint) GetCacheEntryCommand(org.infinispan.commands.read.GetCacheEntryCommand) ConfigurationBuilder(org.infinispan.configuration.cache.ConfigurationBuilder) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) TimeoutException(java.util.concurrent.TimeoutException) Test(org.testng.annotations.Test) Cache(org.infinispan.Cache) AssertJUnit.assertTrue(org.testng.AssertJUnit.assertTrue) Future(java.util.concurrent.Future) InvocationContext(org.infinispan.context.InvocationContext) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AssertJUnit.assertNull(org.testng.AssertJUnit.assertNull) TestingUtil(org.infinispan.test.TestingUtil) DDAsyncInterceptor(org.infinispan.interceptors.DDAsyncInterceptor) ProtoField(org.infinispan.protostream.annotations.ProtoField) Listener(org.infinispan.notifications.Listener) DataOperationOrderer(org.infinispan.util.concurrent.DataOperationOrderer) CompletionStage(java.util.concurrent.CompletionStage) Flag(org.infinispan.context.Flag) CommonsTestingUtil(org.infinispan.commons.test.CommonsTestingUtil) PutKeyValueCommand(org.infinispan.commands.write.PutKeyValueCommand) AsyncInterceptorChain(org.infinispan.interceptors.AsyncInterceptorChain) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) SingleCacheManagerTest(org.infinispan.test.SingleCacheManagerTest) InternalCacheEntry(org.infinispan.container.entries.InternalCacheEntry) AssertJUnit(org.testng.AssertJUnit) PersistenceManager(org.infinispan.persistence.manager.PersistenceManager) CacheEntriesEvictedEvent(org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent) Mocks(org.infinispan.test.Mocks) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Callable(java.util.concurrent.Callable) ProtoFactory(org.infinispan.protostream.annotations.ProtoFactory) EmbeddedCacheManager(org.infinispan.manager.EmbeddedCacheManager) AutoProtoSchemaBuilder(org.infinispan.protostream.annotations.AutoProtoSchemaBuilder) SerializationContextInitializer(org.infinispan.protostream.SerializationContextInitializer) MarshallableEntry(org.infinispan.persistence.spi.MarshallableEntry) CacheEntriesEvicted(org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted) AsyncInterceptor(org.infinispan.interceptors.AsyncInterceptor) AfterClass(org.testng.annotations.AfterClass) GetKeyValueCommand(org.infinispan.commands.read.GetKeyValueCommand) DataContainer(org.infinispan.container.DataContainer) Util(org.infinispan.commons.util.Util) GlobalConfigurationBuilder(org.infinispan.configuration.global.GlobalConfigurationBuilder) AssertJUnit.fail(org.testng.AssertJUnit.fail) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) DummyInMemoryStoreConfigurationBuilder(org.infinispan.persistence.dummy.DummyInMemoryStoreConfigurationBuilder) TestCacheManagerFactory(org.infinispan.test.fwk.TestCacheManagerFactory) AssertJUnit.assertNotNull(org.testng.AssertJUnit.assertNotNull) WaitNonBlockingStore(org.infinispan.persistence.support.WaitNonBlockingStore) VisitableCommand(org.infinispan.commands.VisitableCommand) AssertJUnit.assertEquals(org.testng.AssertJUnit.assertEquals) CheckPoint(org.infinispan.test.fwk.CheckPoint) DataOperationOrderer(org.infinispan.util.concurrent.DataOperationOrderer)

Example 2 with DataOperationOrderer

use of org.infinispan.util.concurrent.DataOperationOrderer in project infinispan by infinispan.

the class EvictionWithPassivationAndConcurrentOperationsTest method testWriteDuringEviction.

// This test differs from testEvictionDuringWrite in that it simulates an eviction and acquires the
// caffeine lock, but is unable to acquire the orderer as it is already taken by a write operation. In this case
// the eviction has removed the entry and the write puts it back - however the passivation should be skipped
public void testWriteDuringEviction() throws Exception {
    String key = "evicted-key";
    String initialValue = "value";
    cache.put(key, initialValue);
    // Use delayFuture1 to stop eviction from acquiring the orderer
    // It blocks eviction from acquiring orderer - but has entry lock
    DataOperationOrderer orderer = extractComponent(cache, DataOperationOrderer.class);
    CompletableFuture<DataOperationOrderer.Operation> delayFuture1 = acquireOrderer(orderer, key, null);
    log.tracef("delayFuture1=%s", delayFuture1.toString());
    // This will be stuck evicting the key until it can get the orderer
    Future<Object> putFuture = fork(() -> cache.put("other-key", "other-value"));
    eventually(() -> orderer.getCurrentStage(key) != delayFuture1);
    CompletionStage<DataOperationOrderer.Operation> putOtherKeyPassivationStage = orderer.getCurrentStage(key);
    String newValue = "value-2";
    Future<Object> evictedKeyPutFuture = fork(() -> cache.put(key, newValue));
    // Should be blocked waiting on Caffeine lock - but has the orderer
    TestingUtil.assertNotDone(evictedKeyPutFuture);
    assertFalse(putOtherKeyPassivationStage.toCompletableFuture().isDone());
    // Let the eviction finish, which will let the put happen
    orderer.completeOperation(key, delayFuture1, DataOperationOrderer.Operation.READ);
    putFuture.get(10, SECONDS);
    assertEquals(initialValue, evictedKeyPutFuture.get(10, SECONDS));
    assertInMemory(key, newValue);
    PassivationPersistenceManager ppm = (PassivationPersistenceManager) extractComponent(cache, PersistenceManager.class);
    eventuallyEquals(0, ppm::pendingPassivations);
    assertEquals(2L, extractComponent(cache, PassivationManager.class).getPassivations());
}
Also used : PassivationPersistenceManager(org.infinispan.persistence.manager.PassivationPersistenceManager) PersistenceManager(org.infinispan.persistence.manager.PersistenceManager) PassivationPersistenceManager(org.infinispan.persistence.manager.PassivationPersistenceManager) DataOperationOrderer(org.infinispan.util.concurrent.DataOperationOrderer)

Example 3 with DataOperationOrderer

use of org.infinispan.util.concurrent.DataOperationOrderer in project infinispan by infinispan.

the class EvictionWithPassivationAndConcurrentOperationsTest method testEvictionDuringWriteWithConcurrentRead.

public void testEvictionDuringWriteWithConcurrentRead() throws TimeoutException, InterruptedException, ExecutionException {
    String key = "evicted-key";
    String value = "value";
    // Simulate a write orderer operation to acquire the write orderer for evicted-key
    // Holding the orderer blocks prevents another passivation or activation of the same key
    DataOperationOrderer orderer = extractComponent(cache, DataOperationOrderer.class);
    CompletableFuture<DataOperationOrderer.Operation> delayFuture1 = acquireOrderer(orderer, key, null);
    log.tracef("delayFuture1=%s", delayFuture1.toString());
    // Put the key which will wait on releasing the orderer at the end
    Future<Object> putEvictedKeyFuture = fork(() -> cache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD).put(key, value));
    // Confirm the entry has been inserted in the data container so we can evict
    eventually(() -> orderer.getCurrentStage(key) != delayFuture1);
    CompletionStage<DataOperationOrderer.Operation> putEvictedKeyActivationStage = orderer.getCurrentStage(key);
    // Acquire the write orderer for evicted-key again after put(evicted-key) releases it
    CompletableFuture<DataOperationOrderer.Operation> delayFuture2 = acquireOrderer(orderer, key, putEvictedKeyActivationStage);
    log.tracef("delayFuture2=%s", delayFuture2.toString());
    // Let put(evicted-key) acquire the orderer and activate evicted-key
    orderer.completeOperation(key, delayFuture1, DataOperationOrderer.Operation.READ);
    putEvictedKeyFuture.get(10, SECONDS);
    assertTrue(putEvictedKeyActivationStage.toCompletableFuture().isDone());
    // delayFuture2 blocks the eviction of evicted-key, but it does not prevent put(other-key) from finishing
    cache.put("other-key", "other-value");
    CompletionStage<DataOperationOrderer.Operation> putOtherKeyPassivationStage = orderer.getCurrentStage(key);
    assertNotSame(delayFuture2, putOtherKeyPassivationStage);
    // Acquire the write orderer for evicted-key again after put(other-key) releases it
    CompletableFuture<DataOperationOrderer.Operation> delayFuture3 = acquireOrderer(orderer, key, putOtherKeyPassivationStage);
    log.tracef("delayFuture3=%s", delayFuture3.toString());
    // delayFuture2 is still holding evicted-key's orderer
    // Start get(evicted-key); it cannot complete yet, but it does register a new orderer stage
    Future<Object> getFuture = fork(() -> cache.get(key));
    eventually(() -> orderer.getCurrentStage(key) != putOtherKeyPassivationStage);
    CompletionStage<DataOperationOrderer.Operation> getEvictedKeyActivationStage = orderer.getCurrentStage(key);
    assertFalse(getFuture.isDone());
    // Complete delayFuture2 to release the orderer, it will be acquired by put(other-key)
    orderer.completeOperation(key, delayFuture2, putEvictedKeyActivationStage.toCompletableFuture().join());
    // get(evicted-key) can't finish yet because of delayFuture3
    TestingUtil.assertNotDone(getFuture);
    // Let get(evicted-key) acquire the orderer and finish the activation
    orderer.completeOperation(key, delayFuture3, putOtherKeyPassivationStage.toCompletableFuture().join());
    assertEquals(value, getFuture.get(10, SECONDS));
    // Wait for the activation to finish
    eventuallyEquals(null, () -> orderer.getCurrentStage(key));
    assertTrue(getEvictedKeyActivationStage.toCompletableFuture().isDone());
    // #1 evicted-key evicted by other-key from write
    // #2 other-key evicted by evicted-key from the get
    assertEquals(2L, extractComponent(cache, PassivationManager.class).getPassivations());
    // #1 evicted key activated from the get
    assertEquals(1L, extractComponent(cache, ActivationManager.class).getActivationCount());
    assertEquals(0L, extractComponent(cache, ActivationManager.class).getPendingActivationCount());
}
Also used : DataOperationOrderer(org.infinispan.util.concurrent.DataOperationOrderer)

Aggregations

DataOperationOrderer (org.infinispan.util.concurrent.DataOperationOrderer)3 PersistenceManager (org.infinispan.persistence.manager.PersistenceManager)2 Arrays (java.util.Arrays)1 Callable (java.util.concurrent.Callable)1 CompletionStage (java.util.concurrent.CompletionStage)1 ExecutionException (java.util.concurrent.ExecutionException)1 Future (java.util.concurrent.Future)1 TimeUnit (java.util.concurrent.TimeUnit)1 TimeoutException (java.util.concurrent.TimeoutException)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Consumer (java.util.function.Consumer)1 Cache (org.infinispan.Cache)1 VisitableCommand (org.infinispan.commands.VisitableCommand)1 GetCacheEntryCommand (org.infinispan.commands.read.GetCacheEntryCommand)1 GetKeyValueCommand (org.infinispan.commands.read.GetKeyValueCommand)1 PutKeyValueCommand (org.infinispan.commands.write.PutKeyValueCommand)1 CommonsTestingUtil (org.infinispan.commons.test.CommonsTestingUtil)1 Util (org.infinispan.commons.util.Util)1 ConfigurationBuilder (org.infinispan.configuration.cache.ConfigurationBuilder)1