/** * Licensed to Ravel, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Ravel, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.goldenorb.zookeeper; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.apache.zookeeper.ZooKeeper; import org.goldenorb.conf.OrbConfiguration; import org.junit.Test; public class OrbFastAllDoneBarrierTest { OrbConfiguration orbConf = new OrbConfiguration(true); String barrierName = "/TestBarrierName"; CountDownLatch startLatch = new CountDownLatch(1); int numOfMembers; /** * Tests the behavior of the barrier if all expected member nodes join in a * timely manner. * * @throws Exception */ @Test public void allMembersJoin() throws Exception { numOfMembers = 3; CountDownLatch everyoneDoneLatch = new CountDownLatch(numOfMembers); orbConf.setOrbZooKeeperQuorum("localhost:21810"); ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum()); OrbFastAllDoneBarrier testBarrier1 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member1", zk); OrbFastAllDoneBarrier testBarrier2 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member2", zk); OrbFastAllDoneBarrier testBarrier3 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member3", zk); BarrierThread bThread1 = new BarrierThread(testBarrier1, startLatch, everyoneDoneLatch, true); BarrierThread bThread2 = new BarrierThread(testBarrier2, startLatch, everyoneDoneLatch, true); BarrierThread bThread3 = new BarrierThread(testBarrier3, startLatch, everyoneDoneLatch, true); bThread1.start(); bThread2.start(); bThread3.start(); startLatch.countDown(); // start all threads everyoneDoneLatch.await(); // wait until all threads are done // the nodes have deleted themselves ont the way out assertTrue(zk.exists(barrierName + "/member1", false) == null); assertTrue(zk.exists(barrierName + "/member2", false) == null); assertTrue(zk.exists(barrierName + "/member3", false) == null); // the nodes say they are all done assertTrue(bThread1.allDone()); assertTrue(bThread2.allDone()); assertTrue(bThread3.allDone()); // the AllDone node exits assertTrue(zk.exists(barrierName + "/AllDone", false) != null); ZookeeperUtils.recursiveDelete(zk, barrierName); ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName); } /** * Tests the behavior of the barrier if all expected member nodes join in a * timely manner. * * @throws Exception */ @Test public void allMembersJoinNotAllDone() throws Exception { numOfMembers = 3; CountDownLatch everyoneDoneLatch = new CountDownLatch(numOfMembers); startLatch = new CountDownLatch(1); orbConf.setOrbZooKeeperQuorum("localhost:21810"); ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum()); OrbFastAllDoneBarrier testBarrier1 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member1", zk); OrbFastAllDoneBarrier testBarrier2 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member2", zk); OrbFastAllDoneBarrier testBarrier3 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member3", zk); BarrierThread bThread1 = new BarrierThread(testBarrier1, startLatch, everyoneDoneLatch, true); BarrierThread bThread2 = new BarrierThread(testBarrier2, startLatch, everyoneDoneLatch, true); BarrierThread bThread3 = new BarrierThread(testBarrier3, startLatch, everyoneDoneLatch, false); bThread1.start(); bThread2.start(); bThread3.start(); startLatch.countDown(); // start all threads everyoneDoneLatch.await(); // wait until all threads are done // the nodes have deleted themselves ont the way out assertTrue(zk.exists(barrierName + "/member1", false) == null); assertTrue(zk.exists(barrierName + "/member2", false) == null); assertTrue(zk.exists(barrierName + "/member3", false) == null); // the nodes say they are all done assertTrue(!bThread1.allDone()); assertTrue(!bThread2.allDone()); assertTrue(!bThread3.allDone()); // the AllDone node exits assertTrue(zk.exists(barrierName + "/AllClear", false) != null); ZookeeperUtils.recursiveDelete(zk, barrierName); ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName); } /** * Tests the behavior of the barrier if only some of the member nodes join. * * @throws Exception */ @Test public void someMembersJoin() throws Exception { numOfMembers = 3; startLatch = new CountDownLatch(1); CountDownLatch everyoneDoneLatch = new CountDownLatch(numOfMembers); CountDownLatch lastMemberLatch = new CountDownLatch(1); orbConf.setOrbZooKeeperQuorum("localhost:21810"); ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum()); OrbFastAllDoneBarrier testBarrier1 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member1", zk); OrbFastAllDoneBarrier testBarrier2 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member2", zk); OrbFastAllDoneBarrier testBarrier3 = new OrbFastAllDoneBarrier(orbConf, barrierName, numOfMembers, "member3", zk); BarrierThread bThread1 = new BarrierThread(testBarrier1, startLatch, everyoneDoneLatch, true); BarrierThread bThread2 = new BarrierThread(testBarrier2, startLatch, everyoneDoneLatch, true); BarrierThread bThread3 = new BarrierThread(testBarrier3, lastMemberLatch, everyoneDoneLatch, false); bThread1.start(); bThread2.start(); bThread3.start(); startLatch.countDown(); // start first 2 threads everyoneDoneLatch.await(500, TimeUnit.MILLISECONDS); // wait on the // threads with // 500ms // timeout, // expect to // timeout assertTrue((zk.exists(barrierName + "/member1DONE", false) != null) || (zk.exists(barrierName + "/member1", false) != null)); assertTrue((zk.exists(barrierName + "/member2DONE", false) != null) || (zk.exists(barrierName + "/member2", false) != null)); lastMemberLatch.countDown(); // start the last member everyoneDoneLatch.await(); assertTrue(zk.exists(barrierName + "/AllClear", false) != null); testBarrier1.makeInactive(); testBarrier2.makeInactive(); ZookeeperUtils.recursiveDelete(zk, barrierName); ZookeeperUtils.deleteNodeIfEmpty(zk, barrierName); zk.close(); } /** * Tests behavior of orbFastBarrier over groups of a large number and a * larger number of steps * * @throws InterruptedException * @throws IOException * @throws OrbZKFailure */ @Test public void StressTest() throws IOException, InterruptedException, OrbZKFailure { // deleteThreads(); int numBarrierStressThreads = 25; int numSteps = 25; CountDownLatch complete = new CountDownLatch(numBarrierStressThreads); CountDownLatch startLatch = new CountDownLatch(1); BarrierStressThread[] threads = new BarrierStressThread[numBarrierStressThreads]; orbConf.setOrbZooKeeperQuorum("localhost:21810"); ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum()); for (int i = 0; i < numBarrierStressThreads; i++) { ZookeeperUtils.recursiveDelete(zk, "/barrier" + i); ZookeeperUtils.deleteNodeIfEmpty(zk, "/barrier" + i); threads[i] = new BarrierStressThread(numSteps, complete, startLatch, numBarrierStressThreads, zk, orbConf, "member" + i); threads[i].start(); } startLatch.countDown(); complete.await(); boolean allBarriersCreated = true; for (int i = 0; i < numBarrierStressThreads; i++) { allBarriersCreated = allBarriersCreated && ZookeeperUtils.nodeExists(zk, "/barrier" + i); if (allBarriersCreated) { ZookeeperUtils.recursiveDelete(zk, "/barrier" + i); ZookeeperUtils.deleteNodeIfEmpty(zk, "/barrier" + i); } } assertTrue(allBarriersCreated); } /** * */ private void deleteThreads() throws InterruptedException, OrbZKFailure, IOException { orbConf.setOrbZooKeeperQuorum("localhost:21810"); ZooKeeper zk = ZookeeperUtils.connect(orbConf.getOrbZooKeeperQuorum()); for (int i = 0; i < 10; i++) { ZookeeperUtils.recursiveDelete(zk, "/barrier" + i); ZookeeperUtils.deleteNodeIfEmpty(zk, "/barrier" + i); } System.err.println("Waiting 10 seconds"); Thread.sleep(10000); } /** * This class defines a Thread that is used to start a member and have it * enter the barrier. * * @author long * */ class BarrierThread extends Thread { private OrbFastAllDoneBarrier testBarrier; private CountDownLatch startLatch; private CountDownLatch everyoneDoneLatch; private boolean allDone; private boolean isDone; /** * Constructs the BarrierThread. * * @param barrier * - name of the OrbFastBarrier * @param startLatch * - Used in conjunction with countDown within the calling * block of code to start Threads * @param everyoneDoneLatch * - Used to wait for all Threads to finish */ public BarrierThread(OrbFastAllDoneBarrier barrier, CountDownLatch startLatch, CountDownLatch everyoneDoneLatch, boolean isDone) { this.testBarrier = barrier; this.startLatch = startLatch; this.everyoneDoneLatch = everyoneDoneLatch; this.allDone = false; this.isDone = isDone; } /** * Runs the Thread to enter the barrier. It first awaits the latch to * start, then enters, and finally counts down the everyoneDoneLatch * once it is finished. */ public void run() { try { startLatch.await(); // wait for CountDown signal allDone = testBarrier.enter(isDone); everyoneDoneLatch.countDown(); // thread completed } catch (OrbZKFailure e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } public boolean allDone() { return allDone; } } /** * This class defines a Thread that is used to start a member and have it * enter the barrier. * * @author long * */ class BarrierStressThread extends Thread { private int numSteps; private CountDownLatch everyoneDoneLatch; private int numBarrierStressThreads; private ZooKeeper zk; private OrbConfiguration orbConf; private CountDownLatch waitToStart; private String member; /** * Constructs the BarrierStressThread. * * @param barrier * - name of the OrbFastBarrier * @param numSteps * - number of barriers thread will have to go through to * complete * @param everyoneDoneLatch * - Used to wait for all Threads to finish */ public BarrierStressThread(int numSteps, CountDownLatch everyoneDoneLatch, CountDownLatch waitToStart, int numBarrierStressThreads, ZooKeeper zk, OrbConfiguration orbConf, String member) { this.numSteps = numSteps; this.everyoneDoneLatch = everyoneDoneLatch; this.numBarrierStressThreads = numBarrierStressThreads; this.zk = zk; this.orbConf = orbConf; this.waitToStart = waitToStart; this.member = member; } /** * Runs the Thread to enter the barrier. It first awaits the latch to * start, then enters, and finally counts down the everyoneDoneLatch * once it is finished. */ public void run() { try { waitToStart.await(); for (int i = 0; i < numSteps; i++) { if (i < numSteps - 1) { OrbFastAllDoneBarrier ofb = new OrbFastAllDoneBarrier( orbConf, "/barrier" + i, numBarrierStressThreads, member, zk); assertTrue(!ofb.enter(false)); } else { OrbFastAllDoneBarrier ofb = new OrbFastAllDoneBarrier( orbConf, "/barrier" + i, numBarrierStressThreads, member, zk); assertTrue(ofb.enter(true)); } } everyoneDoneLatch.countDown(); // thread completed } catch (OrbZKFailure e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } }