during our tests with JE HA (one master node and one replica node) we encountered that InsufficientReplicasException is not thrown by JE, although ReplicaAckPolicy.ALL is used and the replica node is not running. Here is a test program, that illustrates this.
Is my understanding of InsufficientReplicasException not correct or is there another problem?
We are testing with JE 6.2.7.
import java.io.File;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Durability;
import com.sleepycat.je.Durability.ReplicaAckPolicy;
import com.sleepycat.je.Durability.SyncPolicy;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.TransactionConfig;
import com.sleepycat.je.rep.InsufficientReplicasException;
import com.sleepycat.je.rep.NodeType;
import com.sleepycat.je.rep.ReplicatedEnvironment;
import com.sleepycat.je.rep.ReplicationConfig;
@SuppressWarnings("nls")
public class ReplicationTest {
private static final Durability SYNC_ALL = new Durability(SyncPolicy.SYNC, SyncPolicy.SYNC, ReplicaAckPolicy.ALL);
private static long mbToBytes(final long mb) {
return mb * 1024 * 1024;
}
private static EnvironmentConfig createEnvConfig() {
final EnvironmentConfig ec = new EnvironmentConfig();
ec.setAllowCreate(true);
ec.setTransactional(true);
return ec;
}
private static ReplicatedEnvironment createEnvironment(final File dir, final boolean isMaster, final String nodeName, final String portName) {
final EnvironmentConfig ec = createEnvConfig();
ec.setCacheSize(mbToBytes(100));
final String nodeHostPort = "localhost:" + portName;
final ReplicationConfig repConfig = new ReplicationConfig();
repConfig.setGroupName("test-group");
repConfig.setNodeName(nodeName);
repConfig.setNodeHostPort(nodeHostPort);
repConfig.setHelperHosts("localhost:20000");
repConfig.setDesignatedPrimary(isMaster);
repConfig.setConfigParam(ReplicationConfig.REPLAY_FREE_DISK_PERCENT, "0"); //$NON-NLS-1$
repConfig.setConfigParam(ReplicationConfig.REPLAY_COST_PERCENT, "0"); //$NON-NLS-1$
if (!isMaster) {
repConfig.setConfigParam(ReplicationConfig.TXN_ROLLBACK_LIMIT, "0"); //$NON-NLS-1$
repConfig.setNodeType(NodeType.ELECTABLE);
}
return new ReplicatedEnvironment(dir, repConfig, ec);
}
private static DatabaseConfig getDBConfig() {
final DatabaseConfig docsConf = new DatabaseConfig();
docsConf.setAllowCreate(true);
docsConf.setDeferredWrite(false);
docsConf.setSortedDuplicates(false);
docsConf.setTransactional(true);
return docsConf;
}
public static void main(final String[] args) {
final File masterDbDir = new File(args[0]);
final File replicaDbDir = new File(args[1]);
resetDir(masterDbDir);
resetDir(replicaDbDir);
testInsufficientReplicasExceptionNotThrown(masterDbDir, replicaDbDir);
}
private static void resetDir(final File dir) {
dir.delete();
dir.mkdir();
}
private static void testInsufficientReplicasExceptionNotThrown(final File masterDbDir, final File replicaDbDir) {
System.out.println("init nodes ...");
final ReplicatedEnvironment master = createEnvironment(masterDbDir, true, "node1", "20000");
final ReplicatedEnvironment replica = createEnvironment(replicaDbDir, false, "node2", "30000");
final Database testDb = master.openDatabase(null, "testDb", getDBConfig());
writeRecord(master, testDb, 1);
//close the replica node
System.out.println("closing replica node...");
replica.close();
//now InsufficientReplicasException should be thrown in beginTransaction because of ReplicaAckPolicy.ALL
try {
writeRecord(master, testDb, 2);
System.out.println("***** InsufficientReplicasException has not been thrown!!!");
} catch (final InsufficientReplicasException ex) {
System.out.println("InsufficientReplicasException has been thrown as expected");
ex.printStackTrace(System.out);
}
System.out.println("closing master node...");
testDb.close();
master.close();
}
private static void writeRecord(final ReplicatedEnvironment master, final Database testDb, final int key) {
final Transaction tx1 = master.beginTransaction(null, new TransactionConfig().setDurability(SYNC_ALL));
testDb.put(tx1, new DatabaseEntry(new byte[]{(byte) key}), new DatabaseEntry(new byte[0]));
tx1.commit();
}
}