/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*/
package com.sleepycat.db.test;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Vector;
import com.sleepycat.db.*;
public class RepmgrElectionTest extends EventHandlerAdapter
{
static String address = "localhost";
static int basePort = 4242;
static String baseDirName = "";
File homedir;
EnvironmentConfig envConfig;
Environment dbenv;
int masterIndex = -1;
int maxLoopWait = 30;
@BeforeClass public static void ClassInit() {
TestUtils.loadConfig(null);
baseDirName = TestUtils.BASETEST_DBDIR + "/TESTDIR";
}
@AfterClass public static void ClassShutdown() {
}
@Before public void PerTestInit()
throws Exception {
}
@After public void PerTestShutdown()
throws Exception {
for(int j = 0; j < NUM_WORKER_SITES; j++) {
TestUtils.removeDir(baseDirName + j);
}
}
private static boolean lastSiteStarted = false;
private static int NUM_WORKER_SITES = 5;
@Test public void startConductor()
{
Vector<RepmgrElectionTest> workers =
new Vector<RepmgrElectionTest>(NUM_WORKER_SITES);
// Start all worker sites.
for (int i = 0; i < NUM_WORKER_SITES; i++) {
RepmgrElectionTest worker;
worker = new RepmgrElectionTest(i, i == 0 ? -1 : 0);
worker.run();
workers.add(worker);
}
// Ensure that the first site is master.
ReplicationStats rs = null;
try {
rs = workers.elementAt(0).dbenv.getReplicationStats(StatsConfig.DEFAULT);
} catch (DatabaseException dbe) {
fail("Unexpected database exception came from get replication stats." + dbe);
}
assertTrue(rs.getEnvId() == rs.getMaster());
// Stop the master
try {
workers.elementAt(0).dbenv.close();
workers.elementAt(0).dbenv = null;
workers.elementAt(0).envConfig = null;
} catch(DatabaseException dbe) {
fail("Unexpected database exception came during shutdown." + dbe);
}
// Ensure the election is completed.
try {
java.lang.Thread.sleep(5000);
} catch (InterruptedException ie) {} // Do nothing if interrupted.
// Ensure that the site with priority = 75 is selected as new master.
try {
rs = workers.elementAt(1).dbenv.getReplicationStats(StatsConfig.DEFAULT);
} catch (DatabaseException dbe) {
fail("Unexpected database exception came from get replication stats." + dbe);
}
assertTrue(rs.getEnvId() == rs.getMaster());
// Re-start original master using the new master as bootstrap helper.
RepmgrElectionTest rejoin = new RepmgrElectionTest(0, 1);
rejoin.run();
workers.remove(0);
workers.insertElementAt(rejoin, 0);
// Close all the sites and remove their environment contents.
for (int i = 0; i < NUM_WORKER_SITES; i++) {
try {
if (workers.elementAt(i).dbenv != null) {
workers.elementAt(i).dbenv.close();
workers.elementAt(i).dbenv = null;
workers.elementAt(i).envConfig = null;
}
} catch(DatabaseException dbe) {
fail("Unexpected database exception came during shutdown." + dbe);
}
}
}
/*
* Worker site implementation
*/
private final static int priorities[] = {100, 75, 50, 50, 25};
private int siteIndex;
public RepmgrElectionTest() {
// needed to comply with JUnit, since there is also another constructor.
}
RepmgrElectionTest(int siteIndex, int masterIndex) {
this.siteIndex = siteIndex;
this.masterIndex = masterIndex;
}
public void run() {
String homedirName = baseDirName + siteIndex;
TestUtils.removeDir(homedirName);
try {
homedir = new File(homedirName);
homedir.mkdir();
} catch (Exception e) {
TestUtils.DEBUGOUT(2, "Warning: initialization had a problem creating a clean directory.\n" + e);
}
try {
homedir = new File(homedirName);
} catch (NullPointerException npe) {
// can't really happen :)
}
TestUtils.DEBUGOUT(1, "Creating worker: " + siteIndex);
envConfig = new EnvironmentConfig();
envConfig.setErrorStream(TestUtils.getErrorStream());
envConfig.setErrorPrefix("RepmgrElectionTest test("+siteIndex+")");
envConfig.setAllowCreate(true);
envConfig.setRunRecovery(true);
envConfig.setThreaded(true);
envConfig.setInitializeLocking(true);
envConfig.setInitializeLogging(true);
envConfig.setInitializeCache(true);
envConfig.setTransactional(true);
envConfig.setTxnNoSync(true);
envConfig.setInitializeReplication(true);
envConfig.setVerboseReplication(false);
ReplicationManagerSiteConfig localConfig = new ReplicationManagerSiteConfig(address, basePort + siteIndex);
localConfig.setLocalSite(true);
envConfig.addReplicationManagerSite(localConfig);
envConfig.setReplicationPriority(priorities[siteIndex]);
envConfig.setEventHandler(this);
envConfig.setReplicationManagerAckPolicy(ReplicationManagerAckPolicy.ALL);
if (masterIndex >= 0) {
// If we already have the master, then set it as the bootstrap helper,
// otherwise, set local site as new master.
ReplicationManagerSiteConfig remoteConfig =
new ReplicationManagerSiteConfig(address, basePort + masterIndex);
remoteConfig.setBootstrapHelper(true);
envConfig.addReplicationManagerSite(remoteConfig);
}
try {
dbenv = new Environment(homedir, envConfig);
} catch(FileNotFoundException e) {
fail("Unexpected FNFE in standard environment creation." + e);
} catch(DatabaseException dbe) {
fail("Unexpected database exception came from environment create." + dbe);
}
try {
// If we do not have master, then set local site as new master.
if(masterIndex == -1)
dbenv.replicationManagerStart(3, ReplicationManagerStartPolicy.REP_MASTER);
else
dbenv.replicationManagerStart(3, ReplicationManagerStartPolicy.REP_CLIENT);
} catch(DatabaseException dbe) {
fail("Unexpected database exception came from replicationManagerStart." + dbe);
}
TestUtils.DEBUGOUT(1, "Started replication site: " + siteIndex);
lastSiteStarted = true;
try {
java.lang.Thread.sleep(1000 * (1+ siteIndex));
} catch (InterruptedException ie) {}
if(masterIndex != -1) {
// Wait for "Start-up done" for each client, then add next client.
ReplicationStats rs = null;
int i = 0;
do {
try {
java.lang.Thread.sleep(2000);
} catch (InterruptedException e) {}
try {
rs = dbenv.getReplicationStats(StatsConfig.DEFAULT);
} catch (DatabaseException dbe) {
dbe.printStackTrace();
fail("Unexpected database exception came from getReplicationStats." + dbe);
}
} while (!rs.getStartupComplete() && i++ < maxLoopWait);
assertTrue(rs.getStartupComplete());
}
}
/*
* End worker site implementation
*/
public void handleRepMasterEvent() {
TestUtils.DEBUGOUT(1, "Got a REP_MASTER message");
TestUtils.DEBUGOUT(1, "My priority: " + priorities[siteIndex]);
}
public void handleRepClientEvent() {
TestUtils.DEBUGOUT(1, "Got a REP_CLIENT message");
}
public void handleRepNewMasterEvent() {
TestUtils.DEBUGOUT(1, "Got a REP_NEW_MASTER message");
TestUtils.DEBUGOUT(1, "My priority: " + priorities[siteIndex]);
}
}