package org.infinispan.distribution; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.infinispan.Cache; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.manager.CacheContainer; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.test.AbstractInfinispanTest; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.test.fwk.TestResourceTracker; import org.infinispan.util.concurrent.CompletableFutures; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; /** * Tests concurrent startup of replicated and distributed caches * * @author Mircea.Markus@jboss.com * @since 4.1 */ @Test(testName = "distribution.ConcurrentStartWithReplTest", groups = "functional") public class ConcurrentStartWithReplTest extends AbstractInfinispanTest { private ConfigurationBuilder replCfg, distCfg; @BeforeTest public void setUp() { replCfg = MultipleCacheManagersTest.getDefaultClusteredCacheConfig(CacheMode.REPL_SYNC, false); replCfg.clustering().stateTransfer().fetchInMemoryState(true); distCfg = MultipleCacheManagersTest.getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, false); distCfg.clustering().stateTransfer().fetchInMemoryState(true); } @Test(timeOut = 60000) public void testSequence1() throws ExecutionException, InterruptedException { TestResourceTracker.testThreadStarted(this); /* Sequence 1: C1 (repl) (becomes coord) C2 (dist) C1 (repl) C2 (dist) in the same thread. */ doTest(true, false); } @Test(timeOut = 60000) public void testSequence2() throws ExecutionException, InterruptedException { TestResourceTracker.testThreadStarted(this); /* Sequence 2: C1 (repl) (becomes coord) C2 (repl) C2 (dist) C1 (dist) in the same thread. */ doTest(false, false); } @Test(timeOut = 60000) public void testSequence3() throws ExecutionException, InterruptedException { TestResourceTracker.testThreadStarted(this); /* Sequence 3: C1 (repl) (becomes coord) C2 (repl) C1 (dist) (async thread) C2 (dist) (async thread) in the same thread, except the last two which are in separate threads */ doTest(true, true); } @Test(timeOut = 60000) public void testSequence4() throws ExecutionException, InterruptedException { TestResourceTracker.testThreadStarted(this); /* Sequence 4: C1 (repl) (becomes coord) C2 (repl) C2 (dist) (async thread) C1 (dist) (async thread) in the same thread, except the last two which are in separate threads */ doTest(false, true); } private void doTest(boolean inOrder, boolean nonBlockingStartupForDist) throws ExecutionException, InterruptedException { EmbeddedCacheManager cm1 = TestCacheManagerFactory.createClusteredCacheManager(new ConfigurationBuilder()); EmbeddedCacheManager cm2 = TestCacheManagerFactory.createClusteredCacheManager(new ConfigurationBuilder()); try { cm1.defineConfiguration("r", replCfg.build()); cm1.defineConfiguration("d", distCfg.build()); cm2.defineConfiguration("r", replCfg.build()); cm2.defineConfiguration("d", distCfg.build()); // first start the repl caches Cache<String, String> c1r = startCache(cm1, "r", false).get(); c1r.put("key", "value"); Cache<String, String> c2r = startCache(cm2, "r", false).get(); TestingUtil.blockUntilViewsReceived(10000, c1r, c2r); TestingUtil.waitForNoRebalance(c1r, c2r); assert "value".equals(c2r.get("key")); // now the dist ones Future<Cache<String, String>> c1df = startCache(inOrder ? cm1 : cm2, "d", nonBlockingStartupForDist); Future<Cache<String, String>> c2df = startCache(inOrder ? cm2 : cm1, "d", nonBlockingStartupForDist); Cache<String, String> c1d = c1df.get(); Cache<String, String> c2d = c2df.get(); c1d.put("key", "value"); assert "value".equals(c2d.get("key")); } finally { TestingUtil.killCacheManagers(cm1, cm2); } } private Future<Cache<String, String>> startCache(final CacheContainer cm, final String cacheName, boolean nonBlockingStartup) { final Callable<Cache<String, String>> cacheCreator = () -> cm.getCache(cacheName); if (nonBlockingStartup) { return fork(cacheCreator); } else { try { Cache<String, String> cache = cacheCreator.call(); return CompletableFuture.completedFuture(cache); } catch (Exception e) { return CompletableFutures.completedExceptionFuture(e); } } } }