package org.infinispan.server.test.jmx.suppress.statetransfer; import static org.infinispan.server.test.util.ITestUtils.SERVER1_MGMT_PORT; import static org.infinispan.server.test.util.ITestUtils.SERVER2_MGMT_PORT; import static org.infinispan.server.test.util.ITestUtils.SERVER3_MGMT_PORT; import static org.infinispan.server.test.util.ITestUtils.eventually; import static org.infinispan.server.test.util.ITestUtils.getAttribute; import static org.infinispan.server.test.util.ITestUtils.setAttribute; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.infinispan.arquillian.core.InfinispanResource; import org.infinispan.arquillian.core.RemoteInfinispanServer; import org.infinispan.arquillian.core.RunningServer; import org.infinispan.arquillian.core.WithRunningServer; import org.infinispan.arquillian.utils.MBeanServerConnectionProvider; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCacheManager; import org.infinispan.server.infinispan.spi.InfinispanSubsystem; import org.infinispan.server.test.client.memcached.MemcachedClient; import org.infinispan.server.test.util.ITestUtils; import org.jboss.arquillian.container.test.api.ContainerController; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Abstact class for testing state transfer suppress functionality * * @author <a href="mailto:amanukya@redhat.com">Anna Manukyan</a> * @author <a href="mailto:vchepeli@redhat.com">Vitalii Chepeliuk</a> */ @RunWith(Arquillian.class) public class StateTransferSuppressIT { private static final Logger log = Logger.getLogger(StateTransferSuppressIT.class); /* container names */ protected static final String CONTAINER1 = "suppress-state-transfer-1"; protected static final String CONTAINER2 = "suppress-state-transfer-2"; protected static final String CONTAINER3 = "suppress-state-transfer-3"; private static final int NUMBER_ENTRIES = 1000; private static final String CACHE_MANAGER_NAME = "clustered"; private static final String MEMCACHED_CACHE_NAME = "memcachedCache"; private static final String HOTROD_CACHE_NAME = "default"; /* cache MBeans */ final String HOTROD_DIST_CACHE_PREFIX = "jboss." + InfinispanSubsystem.SUBSYSTEM_NAME + ":type=Cache,name=\"" + HOTROD_CACHE_NAME + "(dist_sync)\",manager=\"" + getCacheManagerName() + "\",component="; final String MEMCACHED_DIST_CACHE_PREFIX = "jboss." + InfinispanSubsystem.SUBSYSTEM_NAME + ":type=Cache,name=\"" + MEMCACHED_CACHE_NAME + "(dist_sync)\",manager=\"" + getCacheManagerName() + "\",component="; final String HOTROD_RPC_MANAGER_MBEAN = HOTROD_DIST_CACHE_PREFIX + "RpcManager"; final String MEMCACHED_RPC_MANAGER_MBEAN = MEMCACHED_DIST_CACHE_PREFIX + "RpcManager"; /* JMX attribute names */ final String REBALANCE_ENABLED_ATTR_NAME = "RebalancingEnabled"; final String COMMITTED_VIEW_AS_STRING_ATTR_NAME = "CommittedViewAsString"; final String PENDING_VIEW_AS_STRING_ATTR_NAME = "PendingViewAsString"; /* JMX result views */ private final String OWNERS_2_MEMBERS_NODE1_NODE2 = "[node0, node1]"; private final String OWNERS_2_MEMBERS_NODE2_NODE3 = "[node1, node2]"; private final String OWNERS_2_MEMBERS_NODE1_NODE2_NODE3 = "[node0, node1, node2]"; /* server module MBeans */ private final String LOCAL_TOPOLOGY_MANAGER = "jboss." + InfinispanSubsystem.SUBSYSTEM_NAME + ":type=CacheManager,name=\"" + getCacheManagerName() + "\",component=LocalTopologyManager"; @InfinispanResource(CONTAINER1) RemoteInfinispanServer server1; @InfinispanResource(CONTAINER2) RemoteInfinispanServer server2; @InfinispanResource(CONTAINER3) RemoteInfinispanServer server3; @ArquillianResource ContainerController controller; protected final List<MBeanServerConnectionProvider> providers = new ArrayList<MBeanServerConnectionProvider>(); private RemoteCacheManager rcm1; private RemoteCacheManager rcm2; private RemoteCache cache1; private RemoteCache cache2; private MemcachedClient mc; @Before public void setUp() throws Exception { // clear list of providers before test providers.clear(); providers.add(new MBeanServerConnectionProvider(server1.getHotrodEndpoint().getInetAddress().getHostName(), SERVER1_MGMT_PORT)); providers.add(new MBeanServerConnectionProvider(server1.getHotrodEndpoint().getInetAddress().getHostName(), SERVER2_MGMT_PORT)); providers.add(new MBeanServerConnectionProvider(server1.getHotrodEndpoint().getInetAddress().getHostName(), SERVER3_MGMT_PORT)); // hotrod rcm1 = ITestUtils.createCacheManager(server1); rcm2 = ITestUtils.createCacheManager(server2); cache1 = rcm1.getCache(HOTROD_CACHE_NAME); cache2 = rcm2.getCache(HOTROD_CACHE_NAME); // memcached try { mc = new MemcachedClient("UTF-8", server1.getMemcachedEndpoint().getInetAddress() .getHostName(), server1.getMemcachedEndpoint().getPort(), server1.getMemcachedEndpoint().getPort()); } catch (Exception ex) { log.warn("prepare() method throws exception", ex); } } @After public void tearDown() throws Exception { if (null != rcm1) rcm1.stop(); if (null != rcm2) rcm2.stop(); } protected MBeanServerConnectionProvider provider(int index) { return providers.get(index); } private String getCacheManagerName() { return CACHE_MANAGER_NAME; } private long numEntries(RemoteInfinispanServer server, String cacheName) { return server.getCacheManager(getCacheManagerName()).getCache(cacheName).getNumberOfEntries(); } @Test @WithRunningServer({@RunningServer(name = CONTAINER1), @RunningServer(name = CONTAINER2)}) public void testRebalanceWithFirstNodeStop() throws Exception { try { verifyRebalanceWith3rdNode(); //Disabling rebalance. setAttribute(provider(0), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, false); controller.stop(CONTAINER1); checkRpcManagerStatistics(new String[]{"null", OWNERS_2_MEMBERS_NODE2_NODE3}, OWNERS_2_MEMBERS_NODE2_NODE3, provider(1), provider(2)); checkRebalanceStatus(false, provider(1), provider(2)); assertTrue(numEntries(server2, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server3, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server2, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server3, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); //Enabling rebalance setAttribute(provider(1), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, true); checkRebalanceStatus(true, provider(1), provider(2)); checkRpcManagerStatistics(new String[]{"null", OWNERS_2_MEMBERS_NODE2_NODE3}, OWNERS_2_MEMBERS_NODE2_NODE3, provider(1), provider(2)); assertTrue(numEntries(server2, HOTROD_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server3, HOTROD_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server2, MEMCACHED_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server3, MEMCACHED_CACHE_NAME) == NUMBER_ENTRIES); } finally { controller.stop(CONTAINER3); } } @Test @WithRunningServer({@RunningServer(name = CONTAINER1), @RunningServer(name = CONTAINER2)}) public void testRebalanceWithJoinedNodeStop() throws Exception { verifyRebalanceWith3rdNode(); //Disabling rebalance. setAttribute(provider(0), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, false); controller.stop(CONTAINER3); checkRpcManagerStatistics(new String[]{"null", OWNERS_2_MEMBERS_NODE1_NODE2}, OWNERS_2_MEMBERS_NODE1_NODE2, provider(0), provider(1)); checkRebalanceStatus(false, provider(0), provider(1)); assertTrue(numEntries(server1, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server2, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server1, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server2, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); //Enabling rebalance setAttribute(provider(1), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, true); checkRebalanceStatus(true, provider(0), provider(1)); checkRpcManagerStatistics(new String[]{"null", OWNERS_2_MEMBERS_NODE1_NODE2}, OWNERS_2_MEMBERS_NODE1_NODE2, provider(0), provider(1)); assertTrue(numEntries(server1, HOTROD_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server2, HOTROD_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server1, MEMCACHED_CACHE_NAME) == NUMBER_ENTRIES); assertTrue(numEntries(server2, MEMCACHED_CACHE_NAME) == NUMBER_ENTRIES); } private void verifyRebalanceWith3rdNode() throws Exception { //Disabling Rebalance for verifying the join of the 3rd node. setAttribute(provider(0), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, false); //putting data into cache before adding new node putDataIntoCache(NUMBER_ENTRIES); //Verifying that the rebalance is disabled. checkRebalanceStatus(false, provider(0), provider(1)); checkRpcManagerStatistics(new String[]{"null"}, OWNERS_2_MEMBERS_NODE1_NODE2, provider(0), provider(1)); controller.start(CONTAINER3); checkRebalanceStatus(false, provider(2)); checkRpcManagerStatistics(new String[]{"null"}, OWNERS_2_MEMBERS_NODE1_NODE2, provider(0), provider(1), provider(2)); assertTrue("The hotrod cache on server(2) should be empty.", numEntries(server3, HOTROD_CACHE_NAME) == 0); assertTrue("The memcached cache on server(2) should be empty.", numEntries(server3, MEMCACHED_CACHE_NAME) == 0); //Enabling the Rebalance and verifying that the consistent rehash takes place. setAttribute(provider(0), LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME, true); checkRebalanceStatus(true, provider(0), provider(1), provider(2)); checkRpcManagerStatistics(new String[]{"null", OWNERS_2_MEMBERS_NODE1_NODE2_NODE3}, null, provider(0), provider(1), provider(2)); //Waiting for rehash take place. checkRpcManagerStatistics(new String[]{"null"}, OWNERS_2_MEMBERS_NODE1_NODE2_NODE3, provider(0), provider(1), provider(2)); assertTrue(numEntries(server1, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server2, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server3, HOTROD_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server1, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server2, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); assertTrue(numEntries(server3, MEMCACHED_CACHE_NAME) < NUMBER_ENTRIES); } private void checkRebalanceStatus(final boolean expectedStatus, MBeanServerConnectionProvider... providers) throws Exception { for (final MBeanServerConnectionProvider provider : providers) { eventually(new ITestUtils.Condition() { @Override public boolean isSatisfied() throws Exception { return expectedStatus == Boolean.parseBoolean(getAttribute(provider, LOCAL_TOPOLOGY_MANAGER, REBALANCE_ENABLED_ATTR_NAME)); } }, 10000); } } private void checkRpcManagerStatistics(String[] expectedPendingViews, final String expectedCommitedView, MBeanServerConnectionProvider... providers) throws Exception { // on windows, everything is slow and the view might not be yet updated, so we sleep a little for (final MBeanServerConnectionProvider provider : providers) { if (expectedCommitedView != null) { eventually(new ITestUtils.Condition() { @Override public boolean isSatisfied() throws Exception { String hotrodCommittedViewAsString = String.valueOf(getAttribute(provider, HOTROD_RPC_MANAGER_MBEAN, COMMITTED_VIEW_AS_STRING_ATTR_NAME)); String memcachedCommittedViewAsString = String.valueOf(getAttribute(provider, MEMCACHED_RPC_MANAGER_MBEAN, COMMITTED_VIEW_AS_STRING_ATTR_NAME)); return expectedCommitedView.equals(hotrodCommittedViewAsString) && expectedCommitedView.equals(memcachedCommittedViewAsString); } }, 10000); } String hotrodPendingViewAsString = String.valueOf(getAttribute(provider, HOTROD_RPC_MANAGER_MBEAN, PENDING_VIEW_AS_STRING_ATTR_NAME)); String memcachedPendingViewAsString = String.valueOf(getAttribute(provider, MEMCACHED_RPC_MANAGER_MBEAN, PENDING_VIEW_AS_STRING_ATTR_NAME)); boolean hotrodPassed = false; boolean memcachedPassed = false; for (String expectedPendingView : expectedPendingViews) { if (expectedPendingView.equals(hotrodPendingViewAsString)) { hotrodPassed = true; } if (expectedPendingView.equals(memcachedPendingViewAsString)) { memcachedPassed = true; } } assertTrue("The pending view doesn't match to any of expected ones, but is " + hotrodPendingViewAsString + ".", hotrodPassed); assertTrue("The pending view doesn't match to any of expected ones, but is " + memcachedPendingViewAsString + ".", memcachedPassed); } } private void putDataIntoCache(int count) { // hotrod for (int i = 0; i < count; i++) { cache1.put("key" + i, "value" + i); } assertTrue("The size of both caches should be equal.", cache1.size() == cache2.size()); assertEquals(count, cache1.size()); assertEquals(count, cache2.size()); // memcached try { for (int i = 0; i < count; i++) { mc.set("key" + i, "value" + i); } long num1 = numEntries(server1, MEMCACHED_CACHE_NAME); long num2 = numEntries(server2, MEMCACHED_CACHE_NAME); assertEquals("The size of both caches should be equal.", num1, num2); assertEquals(count, num1); assertEquals(count, num2); } catch (Exception ex) { log.error("putDataIntoCache() throws exception", ex); } } }