package com.hazelcast.examples.splitbrain; import com.hazelcast.config.CacheConfig; import com.hazelcast.config.Config; import com.hazelcast.config.XmlConfigBuilder; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.LifecycleEvent; import com.hazelcast.core.LifecycleListener; import com.hazelcast.core.MemberAttributeEvent; import com.hazelcast.core.MembershipEvent; import com.hazelcast.core.MembershipListener; import com.hazelcast.instance.Node; import com.hazelcast.util.ExceptionUtil; import java.io.FileNotFoundException; import java.util.concurrent.CountDownLatch; import static com.hazelcast.examples.helper.CommonUtils.assertClusterSizeEventually; import static com.hazelcast.examples.helper.CommonUtils.assertOpenEventually; import static com.hazelcast.examples.helper.CommonUtils.generateRandomString; import static com.hazelcast.examples.helper.HazelcastUtils.getNode; /** * Base class for jcache split-brain samples. */ public abstract class AbstractCacheSplitBrainSample { protected static final String BASE_CACHE_NAME = "my-cache"; protected static Config newProgrammaticConfig() { Config config = new Config(); config.setProperty("hazelcast.merge.first.run.delay.seconds", "5"); config.setProperty("hazelcast.merge.next.run.delay.seconds", "3"); config.getGroupConfig().setName(generateRandomString(10)); return config; } protected static Config newDeclarativeConfig() { try { Config config = new XmlConfigBuilder("jcache/src/main/resources/hazelcast-splitbrain.xml").build(); config.setProperty("hazelcast.merge.first.run.delay.seconds", "5"); config.setProperty("hazelcast.merge.next.run.delay.seconds", "3"); config.getGroupConfig().setName(generateRandomString(10)); return config; } catch (FileNotFoundException e) { throw ExceptionUtil.rethrow(e); } } protected static CacheConfig newCacheConfig(String cacheName, String mergePolicy) { CacheConfig cacheConfig = new CacheConfig(); cacheConfig.setName(cacheName); cacheConfig.setMergePolicy(mergePolicy); return cacheConfig; } private static final class SampleLifeCycleListener implements LifecycleListener { private final CountDownLatch latch; private SampleLifeCycleListener(int countdown) { latch = new CountDownLatch(countdown); } @Override public void stateChanged(LifecycleEvent event) { if (event.getState() == LifecycleEvent.LifecycleState.MERGED) { latch.countDown(); } } } private static final class SampleMemberShipListener implements MembershipListener { private final CountDownLatch latch; private SampleMemberShipListener(int countdown) { latch = new CountDownLatch(countdown); } @Override public void memberAdded(MembershipEvent membershipEvent) { } @Override public void memberRemoved(MembershipEvent membershipEvent) { latch.countDown(); } @Override public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) { } } protected static CountDownLatch simulateSplitBrain(HazelcastInstance h1, HazelcastInstance h2) { SampleMemberShipListener memberShipListener = new SampleMemberShipListener(1); h2.getCluster().addMembershipListener(memberShipListener); SampleLifeCycleListener lifeCycleListener = new SampleLifeCycleListener(1); h2.getLifecycleService().addLifecycleListener(lifeCycleListener); closeConnectionBetween(h1, h2); assertOpenEventually(memberShipListener.latch); assertClusterSizeEventually(1, h1); assertClusterSizeEventually(1, h2); return lifeCycleListener.latch; } private static void closeConnectionBetween(HazelcastInstance h1, HazelcastInstance h2) { if (h1 == null || h2 == null) { return; } Node n1 = getNode(h1); Node n2 = getNode(h2); if (n1 != null && n2 != null) { n1.clusterService.suspectMember(n2.getLocalMember(), null, true); n2.clusterService.suspectMember(n1.getLocalMember(), null, true); } } }