Github user afine commented on a diff in the pull request:
https://github.com/apache/zookeeper/pull/453#discussion_r168887935
--- Diff:
src/java/test/org/apache/zookeeper/server/quorum/QuorumPeerMainTest.java ---
@@ -888,4 +923,103 @@ public void testWithOnlyMinSessionTimeout() throws
Exception {
maxSessionTimeOut, quorumPeer.getMaxSessionTimeout());
}
+ @Test
+ public void testFailedTxnAsPartOfQuorumLoss() throws Exception {
+ // 1. start up server and wait for leader election to finish
+ ClientBase.setupTestEnv();
+ final int SERVER_COUNT = 3;
+ servers = LaunchServers(SERVER_COUNT);
+
+ waitForAll(servers, States.CONNECTED);
+
+ // we need to shutdown and start back up to make sure that the
create session isn't the first transaction since
+ // that is rather innocuous.
+ servers.shutDownAllServers();
+ waitForAll(servers, States.CONNECTING);
+ servers.restartAllServersAndClients(this);
+ waitForAll(servers, States.CONNECTED);
+
+ // 2. kill all followers
+ int leader = servers.findLeader();
+ Map<Long, Proposal> outstanding =
servers.mt[leader].main.quorumPeer.leader.outstandingProposals;
+ // increase the tick time to delay the leader going to looking
+ servers.mt[leader].main.quorumPeer.tickTime = 10000;
+ LOG.warn("LEADER {}", leader);
+
+ for (int i = 0; i < SERVER_COUNT; i++) {
+ if (i != leader) {
+ servers.mt[i].shutdown();
+ }
+ }
+
+ // 3. start up the followers to form a new quorum
+ for (int i = 0; i < SERVER_COUNT; i++) {
+ if (i != leader) {
+ servers.mt[i].start();
+ }
+ }
+
+ // 4. wait one of the follower to be the new leader
+ for (int i = 0; i < SERVER_COUNT; i++) {
+ if (i != leader) {
+ // Recreate a client session since the previous session
was not persisted.
+ servers.restartClient(i, this);
+ waitForOne(servers.zk[i], States.CONNECTED);
+ }
+ }
+
+ // 5. send a create request to old leader and make sure it's
synced to disk,
+ // which means it acked from itself
+ try {
+ servers.zk[leader].create("/zk" + leader, "zk".getBytes(),
Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ Assert.fail("create /zk" + leader + " should have failed");
+ } catch (KeeperException e) {
+ }
+
+ // just make sure that we actually did get it in process at the
+ // leader
+ Assert.assertEquals(1, outstanding.size());
+ Proposal p = outstanding.values().iterator().next();
+ Assert.assertEquals(OpCode.create, p.request.getHdr().getType());
+
+ // make sure it has a chance to write it to disk
+ int sleepTime = 0;
+ Long longLeader = new Long(leader);
+ while (!p.qvAcksetPairs.get(0).getAckset().contains(longLeader)) {
+ if (sleepTime > 2000) {
+ Assert.fail("Transaction not synced to disk within 1
second " + p.qvAcksetPairs.get(0).getAckset()
+ + " expected " + leader);
+ }
+ Thread.sleep(100);
+ sleepTime += 100;
+ }
+
+ // 6. wait for the leader to quit due to not enough followers and
come back up as a part of the new quorum
+ sleepTime = 0;
+ Follower f = servers.mt[leader].main.quorumPeer.follower;
+ while (f == null || !f.isRunning()) {
+ if (sleepTime > 10_000) {
+ Assert.fail("Took too long for old leader to time out " +
servers.mt[leader].main.quorumPeer.getPeerState());
+ }
+ Thread.sleep(100);
+ sleepTime += 100;
+ f = servers.mt[leader].main.quorumPeer.follower;
+ }
+ servers.mt[leader].shutdown();
--- End diff --
why do we need this?
---