package org.infinispan.statetransfer; import static org.testng.Assert.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import java.util.Arrays; import java.util.List; import javax.management.Attribute; import javax.management.MBeanServer; import javax.management.ObjectName; import org.infinispan.Cache; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.distribution.ch.ConsistentHash; import org.infinispan.jmx.PerThreadMBeanServerLookup; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.remoting.transport.Address; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterMethod; import org.infinispan.topology.ClusterTopologyManager; import org.testng.annotations.Test; /** * @author Dan Berindei * @author Tristan Tarrant */ @Test(groups = "functional", testName = "statetransfer.PerCacheRebalancePolicyJmxTest") @CleanupAfterMethod public class PerCacheRebalancePolicyJmxTest extends MultipleCacheManagersTest { private static final String REBALANCING_ENABLED = "rebalancingEnabled"; public void testJoinAndLeaveWithRebalanceSuspended() throws Exception { doTest(false); } public void testJoinAndLeaveWithRebalanceSuspendedAwaitingInitialTransfer() throws Exception { doTest(true); } @Override protected void createCacheManagers() throws Throwable { //no-op } private ConfigurationBuilder getConfigurationBuilder(boolean awaitInitialTransfer) { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.clustering().cacheMode(CacheMode.DIST_SYNC) .stateTransfer().awaitInitialTransfer(awaitInitialTransfer); return cb; } private GlobalConfigurationBuilder getGlobalConfigurationBuilder(String rackId) { GlobalConfigurationBuilder gcb = GlobalConfigurationBuilder.defaultClusteredBuilder(); gcb.globalJmxStatistics() .enable() .mBeanServerLookup(new PerThreadMBeanServerLookup()) .transport().rackId(rackId); return gcb; } private void addNode(GlobalConfigurationBuilder gcb, ConfigurationBuilder builder) { EmbeddedCacheManager cacheManager = addClusterEnabledCacheManager(gcb, builder); cacheManager.defineConfiguration("a", builder.build()); cacheManager.defineConfiguration("b", builder.build()); } private void doTest(boolean awaitInitialTransfer) throws Exception { ConfigurationBuilder builder = getConfigurationBuilder(awaitInitialTransfer); addNode(getGlobalConfigurationBuilder("r1"), builder); addNode(getGlobalConfigurationBuilder("r1"), builder); waitForClusterToForm("a", "b"); MBeanServer mBeanServer = PerThreadMBeanServerLookup.getThreadMBeanServer(); String domain0 = manager(1).getCacheManagerConfiguration().globalJmxStatistics().domain(); ObjectName ltmName0 = TestingUtil.getCacheManagerObjectName(domain0, "DefaultCacheManager", "LocalTopologyManager"); String domain1 = manager(1).getCacheManagerConfiguration().globalJmxStatistics().domain(); ObjectName ltmName1 = TestingUtil.getCacheManagerObjectName(domain1, "DefaultCacheManager", "LocalTopologyManager"); ObjectName jmxCacheA = TestingUtil.getCacheObjectName(domain0, "a(dist_sync)"); ObjectName jmxCacheB = TestingUtil.getCacheObjectName(domain0, "b(dist_sync)"); // Check initial state StateTransferManager stm0a = TestingUtil.extractComponent(cache(0, "a"), StateTransferManager.class); assertEquals(Arrays.asList(address(0), address(1)), stm0a.getCacheTopology().getCurrentCH().getMembers()); assertNull(stm0a.getCacheTopology().getPendingCH()); StateTransferManager stm0b = TestingUtil.extractComponent(cache(0, "b"), StateTransferManager.class); assertEquals(Arrays.asList(address(0), address(1)), stm0b.getCacheTopology().getCurrentCH().getMembers()); assertNull(stm0b.getCacheTopology().getPendingCH()); assertTrue(mBeanServer.isRegistered(ltmName0)); assertTrue((Boolean) mBeanServer.getAttribute(ltmName0, REBALANCING_ENABLED)); // Suspend global rebalancing mBeanServer.setAttribute(ltmName0, new Attribute(REBALANCING_ENABLED, false)); assertFalse((Boolean) mBeanServer.getAttribute(ltmName0, REBALANCING_ENABLED)); // Add 2 nodes log.debugf("Starting 2 new nodes"); addNode(getGlobalConfigurationBuilder("r2"), builder); addNode(getGlobalConfigurationBuilder("r2"), builder); // Ensure the caches are started on all nodes TestingUtil.blockUntilViewsReceived(3000, getCaches("a")); TestingUtil.blockUntilViewsReceived(3000, getCaches("b")); // Check that rebalance is suspended on the new nodes ClusterTopologyManager ctm2 = TestingUtil.extractGlobalComponent(manager(2), ClusterTopologyManager.class); assertFalse(ctm2.isRebalancingEnabled()); ClusterTopologyManager ctm3 = TestingUtil.extractGlobalComponent(manager(3), ClusterTopologyManager.class); assertFalse(ctm3.isRebalancingEnabled()); // Check that no rebalance happened after 1 second Thread.sleep(1000); assertFalse((Boolean) mBeanServer.getAttribute(ltmName1, REBALANCING_ENABLED)); assertNull(stm0a.getCacheTopology().getPendingCH()); assertEquals(Arrays.asList(address(0), address(1)), stm0a.getCacheTopology().getCurrentCH().getMembers()); // Disable rebalancing for cache b mBeanServer.setAttribute(jmxCacheB, new Attribute(REBALANCING_ENABLED, false)); // Re-enable global rebalancing log.debugf("Rebalancing with nodes %s %s %s %s", address(0), address(1), address(2), address(3)); mBeanServer.setAttribute(ltmName0, new Attribute(REBALANCING_ENABLED, true)); assertTrue((Boolean) mBeanServer.getAttribute(ltmName0, REBALANCING_ENABLED)); checkRehashed(stm0a, getCaches("a"), Arrays.asList(address(0), address(1), address(2), address(3))); // Check that cache "b" still has rebalancing disabled assertFalse((Boolean)mBeanServer.getAttribute(jmxCacheB, REBALANCING_ENABLED)); assertEquals(Arrays.asList(address(0), address(1)), stm0b.getCacheTopology().getCurrentCH().getMembers()); // Enable rebalancing for cache b mBeanServer.setAttribute(jmxCacheB, new Attribute(REBALANCING_ENABLED, true)); // Check that cache "b" now has 4 nodes, and the CH is balanced checkRehashed(stm0b, getCaches("b"), Arrays.asList(address(0), address(1), address(2), address(3))); } private void checkRehashed(StateTransferManager stm, List<Cache<Object,Object>> caches, List<Address> addresses) { TestingUtil.waitForNoRebalance(caches); assertNull(stm.getCacheTopology().getPendingCH()); ConsistentHash ch = stm.getCacheTopology().getCurrentCH(); assertEquals(addresses, ch.getMembers()); for (int i = 0; i < ch.getNumSegments(); i++) { assertEquals(2, ch.locateOwnersForSegment(i).size()); } } }