package org.jgroups.tests; import org.jgroups.*; import org.jgroups.protocols.*; import org.jgroups.util.Util; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicInteger; /** * Tests the BARRIER protocol * @author Bela Ban */ @Test(groups=Global.FUNCTIONAL,singleThreaded=true) public class BARRIERTest { protected JChannel ch; protected Discovery discovery_prot; protected BARRIER barrier_prot; protected TP tp; @BeforeMethod void setUp() throws Exception { ch=new JChannel(tp=new SHARED_LOOPBACK(), discovery_prot=new SHARED_LOOPBACK_PING(), barrier_prot=new BARRIER()).name("A"); ch.connect("BARRIERTest"); } @AfterMethod void destroy() {Util.close(ch);} public void testBlocking() { assert !barrier_prot.isClosed(); ch.down(new Event(Event.CLOSE_BARRIER)); assert barrier_prot.isClosed(); ch.down(new Event(Event.OPEN_BARRIER)); assert !barrier_prot.isClosed(); } public void testThreadsBlockedOnBarrier() { MyReceiver receiver=new MyReceiver(); ch.setReceiver(receiver); ch.down(new Event(Event.CLOSE_BARRIER)); // BARRIER starts discarding messages from now on for(int i=0; i < 5; i++) { new Thread() {public void run() { discovery_prot.up(createMessage());}}.start(); } Util.sleep(2000); int num_in_flight_threads=barrier_prot.getNumberOfInFlightThreads(); assert num_in_flight_threads == 0; ch.down(new Event(Event.OPEN_BARRIER)); Util.sleep(2000); num_in_flight_threads=barrier_prot.getNumberOfInFlightThreads(); assert num_in_flight_threads == 0; int received_msgs=receiver.getNumberOfReceivedMessages(); assert received_msgs == 0 : "expected " + 0 + " messages but got " + received_msgs; } public void testThreadsBlockedOnMutex() throws Exception { final CyclicBarrier barrier=new CyclicBarrier(3); BlockingReceiver receiver=new BlockingReceiver(barrier); ch.setReceiver(receiver); Thread[] threads=new Thread[2]; for(int i=1; i <= threads.length; i++) { Thread thread=new Thread() { public void run() { discovery_prot.up(createMessage());} }; thread.setName("blocker-" + i); thread.start(); } waitUntilNumThreadsAreBlocked(2, 10000, 500); assert barrier_prot.getNumberOfInFlightThreads() == 2; barrier.await(); // starts the threads waitUntilNumThreadsAreBlocked(0, 10000, 500); assert barrier_prot.getNumberOfInFlightThreads() == 0; } public void testThreadFlushTimeout() throws Exception { final CyclicBarrier barrier=new CyclicBarrier(3); BlockingReceiver receiver=new BlockingReceiver(barrier); ch.setReceiver(receiver); barrier_prot.setValue("flush_timeout", 2000); Thread[] threads=new Thread[2]; for(int i=1; i <= threads.length; i++) { Thread thread=new Thread() { public void run() { discovery_prot.up(createMessage());} }; thread.setName("blocker-" + i); thread.start(); } // wait until all threads are blocked waitUntilNumThreadsAreBlocked(2, 10000, 500); assert barrier_prot.getNumberOfInFlightThreads() == 2; try { ch.down(new Event(Event.CLOSE_BARRIER)); assert false : "closing BARRIER should have thrown an exception as threads couldn't be flushed"; } catch(Exception ex) { System.out.println("got exception as expected: " + ex); } barrier.await(); } protected Message createMessage() { return new Message(null).src(ch.getAddress()).putHeader(tp.getId(),new TpHeader("BARRIERTest")); } protected void waitUntilNumThreadsAreBlocked(int expected, long timeout, long interval) { long target_time=System.currentTimeMillis() + timeout; while(System.currentTimeMillis() < target_time) { if(barrier_prot.getNumberOfInFlightThreads() == expected) break; Util.sleep(interval); } } protected static class MyReceiver extends ReceiverAdapter { protected final AtomicInteger num_mgs_received=new AtomicInteger(0); public void receive(Message msg) { if(num_mgs_received.incrementAndGet() % 1000 == 0) System.out.println("<== " + num_mgs_received.get()); } public int getNumberOfReceivedMessages() { return num_mgs_received.get(); } } protected static class BlockingReceiver extends ReceiverAdapter { protected final CyclicBarrier barrier; BlockingReceiver(CyclicBarrier barrier) { this.barrier=barrier; } public void receive(Message msg) { try { barrier.await(); } catch(Exception e) { e.printStackTrace(); } } } }