/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved. * */ package repmgrtests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import org.junit.Test; import org.junit.Before; import com.sleepycat.db.Environment; import com.sleepycat.db.EnvironmentConfig; import com.sleepycat.db.EventHandlerAdapter; import com.sleepycat.db.ReplicationConfig; import com.sleepycat.db.ReplicationManagerSiteConfig; import com.sleepycat.db.ReplicationManagerStartPolicy; import com.sleepycat.db.ReplicationStats; import com.sleepycat.db.ReplicationTimeoutType; import com.sleepycat.db.StatsConfig; import com.sleepycat.db.VerboseConfig; /** * Tests for repmgr's handling of elections, and the "strict 2-site" * config flag. */ public class TestStrictElect { private int[] testPorts; private int masterPort; private int clientPort; private int client2Port; @Before public void setUp() throws Exception { testPorts = Util.findAvailablePorts(3); masterPort = testPorts[0]; clientPort = testPorts[1]; client2Port = testPorts[2]; } /** * Verifies that by default in a 2-site group, client takes over * when master seems to have failed. */ @Test public void liberal() throws Exception { EnvironmentConfig ec = makeBasicConfig(); ReplicationManagerSiteConfig local = new ReplicationManagerSiteConfig("localhost", masterPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); File masterDir = Util.mkdir("master"); Environment master = new Environment(masterDir, ec); master.setReplicationConfig(ReplicationConfig.STRICT_2SITE, true); master.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_MASTER); ec = makeBasicConfig(); local = new ReplicationManagerSiteConfig("localhost", clientPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); ReplicationManagerSiteConfig remote = new ReplicationManagerSiteConfig("localhost", masterPort); remote.setBootstrapHelper(true); ec.addReplicationManagerSite(remote); MyEventHandler mon = new MyEventHandler(); ec.setEventHandler(mon); File clientDir = Util.mkdir("client"); Environment client = new Environment(clientDir, ec); client.setReplicationConfig(ReplicationConfig.STRICT_2SITE, true); client.setReplicationTimeout(ReplicationTimeoutType.ELECTION_RETRY, 500000); client.setReplicationTimeout(ReplicationTimeoutType.ELECTION_TIMEOUT, 500000); client.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); mon.await(); // check stats, at this point there should be 0 elections ReplicationStats stats = client.getReplicationStats(StatsConfig.DEFAULT); assertTrue(stats.getElections() == 0); master.close(); // wait a little while // there should be a couple of failed elections, and we should // not be master Thread.sleep(5000); stats = client.getReplicationStats(StatsConfig.DEFAULT); assertTrue(stats.getElections() > 2); assertTrue(stats.getEnvId() != stats.getMaster()); client.close(); } /** * Verifies that when the "strict" setting is on, failures * of a master leaves the group with no master: the client does * not take over. */ @Test public void strict() throws Exception { EnvironmentConfig ec = makeBasicConfig(); ReplicationManagerSiteConfig local = new ReplicationManagerSiteConfig("localhost", masterPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); File masterDir = Util.mkdir("master"); Environment master = new Environment(masterDir, ec); master.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_MASTER); ec = makeBasicConfig(); local = new ReplicationManagerSiteConfig("localhost", clientPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); ReplicationManagerSiteConfig remote = new ReplicationManagerSiteConfig("localhost", masterPort); remote.setBootstrapHelper(true); ec.addReplicationManagerSite(remote); MyEventHandler mon = new MyEventHandler(); ec.setEventHandler(mon); File clientDir = Util.mkdir("client"); Environment client = new Environment(clientDir, ec); client.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); mon.await(); // check stats, at this point there should be 0 elections ReplicationStats stats = client.getReplicationStats(StatsConfig.DEFAULT); assertTrue(stats.getElections() == 0); master.close(); Thread.sleep(3000); stats = client.getReplicationStats(StatsConfig.DEFAULT); assertEquals(1, stats.getElections()); assertEquals(ReplicationStats.REP_CLIENT, stats.getStatus()); client.close(); } /** * Verifies that the usual strict majority rule is observed in a * group with more than two sites, regardless of the config setting. */ @Test public void threeSite() throws Exception { EnvironmentConfig ec = makeBasicConfig(); ReplicationManagerSiteConfig local = new ReplicationManagerSiteConfig("localhost", masterPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); File masterDir = Util.mkdir("master"); Environment master = new Environment(masterDir, ec); master.setReplicationConfig(ReplicationConfig.STRICT_2SITE, true); master.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_MASTER); ec = makeBasicConfig(); local = new ReplicationManagerSiteConfig("localhost", clientPort); local.setLocalSite(true); ec.addReplicationManagerSite(local); ReplicationManagerSiteConfig remote = new ReplicationManagerSiteConfig("localhost", masterPort); remote.setBootstrapHelper(true); ec.addReplicationManagerSite(remote); MyEventHandler mon = new MyEventHandler(); ec.setEventHandler(mon); File clientDir = Util.mkdir("client"); Environment client = new Environment(clientDir, ec); client.setReplicationConfig(ReplicationConfig.STRICT_2SITE, true); client.setReplicationTimeout(ReplicationTimeoutType.ELECTION_RETRY, 500000); client.setReplicationTimeout(ReplicationTimeoutType.ELECTION_TIMEOUT, 500000); client.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); mon.await(); // Create, start, and sync the 3rd site, just to establish its // existence (so that the rest of the group recognizes that // the group size is 3); then shut it down so that the later // election will fail for insufficient sites. // ec = makeBasicConfig(); local = new ReplicationManagerSiteConfig("localhost", client2Port); local.setLocalSite(true); ec.addReplicationManagerSite(local); remote = new ReplicationManagerSiteConfig("localhost", masterPort); remote.setBootstrapHelper(true); ec.addReplicationManagerSite(remote); mon = new MyEventHandler(); ec.setEventHandler(mon); clientDir = Util.mkdir("client2"); Environment client2 = new Environment(clientDir, ec); client2.setReplicationConfig(ReplicationConfig.STRICT_2SITE, true); client2.setReplicationTimeout(ReplicationTimeoutType.ELECTION_RETRY, 500000); client2.setReplicationTimeout(ReplicationTimeoutType.ELECTION_TIMEOUT, 500000); client2.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); mon.await(); client2.close(); // check stats, at this point there should be 0 elections ReplicationStats stats = client.getReplicationStats(StatsConfig.DEFAULT); assertTrue(stats.getElections() == 0); master.close(); // wait a little while // there should be a couple of failed elections, and we should // not be master Thread.sleep(5000); stats = client.getReplicationStats(StatsConfig.DEFAULT); assertTrue(stats.getElections() > 2); assertTrue(stats.getEnvId() != stats.getMaster()); client.close(); } private EnvironmentConfig makeBasicConfig() throws Exception { EnvironmentConfig ec = new EnvironmentConfig(); ec.setAllowCreate(true); ec.setInitializeCache(true); ec.setInitializeLocking(true); ec.setInitializeLogging(true); ec.setInitializeReplication(true); ec.setTransactional(true); ec.setThreaded(true); if (Boolean.getBoolean("VERB_REPLICATION")) ec.setVerbose(VerboseConfig.REPLICATION, true); return (ec); } class MyEventHandler extends EventHandlerAdapter { private boolean done = false; private boolean panic = false; @Override synchronized public void handleRepStartupDoneEvent() { done = true; notifyAll(); } @Override synchronized public void handlePanicEvent() { done = true; panic = true; notifyAll(); } synchronized void await() throws Exception { while (!done) { wait(); } if (panic) throw new Exception("aborted by panic in DB"); } } }