package org.infinispan.statetransfer; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNull; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.infinispan.Cache; import org.infinispan.commands.write.InvalidateCommand; import org.infinispan.commons.CacheConfigurationException; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.container.entries.InternalCacheEntry; import org.infinispan.context.InvocationContext; import org.infinispan.interceptors.BaseCustomAsyncInterceptor; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.persistence.dummy.DummyInMemoryStoreConfigurationBuilder; import org.infinispan.test.Exceptions; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterMethod; import org.testng.annotations.Test; /** * Test if state transfer happens properly on a non-tx invalidation cache. * * @since 7.0 */ @Test(groups = "functional", testName = "statetransfer.NonTxStateTransferInvalidationTest") @CleanupAfterMethod public class NonTxStateTransferInvalidationTest extends MultipleCacheManagersTest { public static final int NUM_KEYS = 10; private ConfigurationBuilder dccc; @Override protected void createCacheManagers() throws Throwable { dccc = getDefaultClusteredCacheConfig(CacheMode.INVALIDATION_SYNC, false, true); createCluster(dccc, 2); waitForClusterToForm(); } public void testStateTransferDisabled() throws Exception { // Insert initial data in the cache Set<Object> keys = new HashSet<Object>(); for (int i = 0; i < NUM_KEYS; i++) { Object key = "key" + i; keys.add(key); cache(0).put(key, key); } log.trace("State transfer happens here"); // add a third node addClusterEnabledCacheManager(dccc); waitForClusterToForm(); log.trace("Checking the values from caches..."); for (Object key : keys) { log.tracef("Checking key: %s", key); // check them directly in data container InternalCacheEntry d0 = advancedCache(0).getDataContainer().get(key); InternalCacheEntry d1 = advancedCache(1).getDataContainer().get(key); InternalCacheEntry d2 = advancedCache(2).getDataContainer().get(key); assertEquals(key, d0.getValue()); assertNull(d1); assertNull(d2); } } public void testConfigValidation() { ConfigurationBuilder builder1 = new ConfigurationBuilder(); builder1.clustering().cacheMode(CacheMode.INVALIDATION_ASYNC).stateTransfer(); builder1.validate(); ConfigurationBuilder builder2 = new ConfigurationBuilder(); builder2.clustering().cacheMode(CacheMode.INVALIDATION_ASYNC).stateTransfer().fetchInMemoryState(true); Exceptions.expectException(CacheConfigurationException.class, builder2::validate); ConfigurationBuilder builder3 = new ConfigurationBuilder(); builder3.clustering().cacheMode(CacheMode.INVALIDATION_ASYNC).persistence() .addStore(DummyInMemoryStoreConfigurationBuilder.class); builder3.validate(); ConfigurationBuilder builder4 = new ConfigurationBuilder(); builder4.clustering().cacheMode(CacheMode.INVALIDATION_ASYNC).persistence() .addStore(DummyInMemoryStoreConfigurationBuilder.class).fetchPersistentState(true); Exceptions.expectException(CacheConfigurationException.class, builder4::validate); } public void testInvalidationDuringStateTransfer() throws Exception { EmbeddedCacheManager node1 = manager(0); Cache<String, Object> node1Cache = node1.getCache(); EmbeddedCacheManager node2 = manager(1); Cache<String, Object> node2Cache = node2.getCache(); CountDownLatch latch = new CountDownLatch(1); node2Cache.getAdvancedCache().getAsyncInterceptorChain().addInterceptor(new BaseCustomAsyncInterceptor() { @Override public Object visitInvalidateCommand(InvocationContext ctx, InvalidateCommand command) throws Throwable { latch.await(10, TimeUnit.SECONDS); return super.visitInvalidateCommand(ctx, command); } }, 0); String key = "key"; Future<?> future = fork(() -> { node1Cache.putForExternalRead(key, new Object()); node1Cache.remove(key); }); EmbeddedCacheManager node3 = addClusterEnabledCacheManager(dccc); Cache<Object, Object> node3Cache = node3.getCache(); TestingUtil.waitForNoRebalance(caches()); log.info("Node 3 started"); latch.countDown(); future.get(30, TimeUnit.SECONDS); assertNull(node1Cache.get(key)); assertNull(node2Cache.get(key)); assertNull(node3Cache.get(key)); } }