package org.jgroups.tests; import org.jgroups.*; import org.jgroups.jmx.JmxConfigurator; import org.jgroups.logging.Log; import org.jgroups.logging.LogFactory; import org.jgroups.protocols.DISCARD; import org.jgroups.protocols.PING; import org.jgroups.protocols.SHARED_LOOPBACK; import org.jgroups.protocols.UNICAST; import org.jgroups.protocols.pbcast.GMS; import org.jgroups.protocols.pbcast.NAKACK2; import org.jgroups.protocols.pbcast.STABLE; import org.jgroups.stack.DiagnosticsHandler; import org.jgroups.stack.ProtocolStack; import org.jgroups.util.*; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.IOException; import java.net.InetAddress; import java.util.*; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Tests a merge where {A}, {B}, {C} and {D} are found, and then one of the members doesn't answer the merge request. * Goal: the merge should *not* get cancelled, but instead all 3 non-faulty member should merge * @author Bela Ban */ @Test(groups=Global.FUNCTIONAL,sequential=true) public class MergeTest2 { protected MyDiagnosticsHandler handler; protected JChannel a,b,c,d; @BeforeMethod void setUp() throws Exception { handler=new MyDiagnosticsHandler(InetAddress.getByName("224.0.75.75"), 7500, LogFactory.getLog(DiagnosticsHandler.class), new DefaultSocketFactory(), new DefaultThreadFactory("", false)); handler.start(); TimeScheduler timer=new TimeScheduler2(new DefaultThreadFactory("Timer", true, true), 5,10, 3000, 1000, "abort"); ThreadPoolExecutor oob_thread_pool=new ThreadPoolExecutor(5, 50, 3000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000)); oob_thread_pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); ThreadPoolExecutor thread_pool=new ThreadPoolExecutor(5, 10, 3000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10000)); thread_pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); a=createChannel("A", timer, thread_pool, oob_thread_pool); b=createChannel("B", timer, thread_pool, oob_thread_pool); c=createChannel("C", timer, thread_pool, oob_thread_pool); d=createChannel("D", timer, thread_pool, oob_thread_pool); } protected JChannel createChannel(String name, TimeScheduler timer, Executor thread_pool, Executor oob_thread_pool) throws Exception { SHARED_LOOPBACK shared_loopback=(SHARED_LOOPBACK)new SHARED_LOOPBACK().setValue("enable_bundling", false); shared_loopback.setTimer(timer); shared_loopback.setOOBThreadPool(oob_thread_pool); shared_loopback.setDefaultThreadPool(thread_pool); shared_loopback.setDiagnosticsHandler(handler); JChannel retval=Util.createChannel(shared_loopback, new DISCARD().setValue("discard_all",true), new PING().setValue("timeout",100), new NAKACK2().setValue("use_mcast_xmit",false) .setValue("log_discard_msgs",false).setValue("log_not_found_msgs",false), new UNICAST(), new STABLE().setValue("max_bytes",50000), new GMS().setValue("print_local_addr",false) .setValue("leave_timeout",100) .setValue("merge_timeout",3000) .setValue("log_view_warnings",false) .setValue("view_ack_collection_timeout",50) .setValue("log_collect_msgs",false)); retval.setName(name); JmxConfigurator.registerChannel(retval, Util.getMBeanServer(), name, retval.getClusterName(), true); retval.connect("MergeTest2"); return retval; } @AfterMethod void tearDown() throws Exception { for(JChannel ch: new JChannel[]{a,b,c,d}) { ProtocolStack stack=ch.getProtocolStack(); String cluster_name=ch.getClusterName(); stack.stopStack(cluster_name); stack.destroy(); } handler.destroy(); } public void testMergeWithMissingMergeResponse() { JChannel merge_leader=findMergeLeader(a,b,c,d); List<Address> non_faulty_members=new ArrayList<Address>(); non_faulty_members.addAll(Arrays.asList(a.getAddress(),b.getAddress(),c.getAddress(),d.getAddress())); List<Address> tmp=new ArrayList<Address>(non_faulty_members); tmp.remove(merge_leader.getAddress()); Address faulty_member=(Address)Util.pickRandomElement(tmp); non_faulty_members.remove(faulty_member); System.out.println("\nMerge leader: " + merge_leader.getAddress() + "\nFaulty member: " + faulty_member + "\nNon-faulty members: " + non_faulty_members); for(JChannel ch: new JChannel[]{a,b,c,d}) { // excluding faulty member, as it still discards messages assert ch.getView().size() == 1; if(ch.getAddress().equals(faulty_member)) // skip the faulty member; it keeps discarding messages continue; DISCARD discard=(DISCARD)ch.getProtocolStack().findProtocol(DISCARD.class); discard.setDiscardAll(false); } Map<Address,View> merge_views=new HashMap<Address,View>(4); for(JChannel ch: new JChannel[]{a,b,c,d}) { merge_views.put(ch.getAddress(), ch.getView()); // here, we include D } System.out.println("Injecting MERGE event into merge leader " + merge_leader.getAddress()); GMS gms=(GMS)merge_leader.getProtocolStack().findProtocol(GMS.class); gms.setLevel("trace"); gms.up(new Event(Event.MERGE, merge_views)); for(int i=0; i < 20; i++) { boolean done=true; System.out.println(); for(JChannel ch: new JChannel[]{a,b,c,d}) { if(!ch.getAddress().equals(faulty_member)) { System.out.println("==> " + ch.getAddress() + ": " + ch.getView()); if(ch.getView().size() != 3) done=false; } } if(done) break; Util.sleep(3000); } for(JChannel ch: new JChannel[]{a,b,c,d}) { if(ch.getAddress().equals(faulty_member)) assert ch.getView().size() == 1; else assert ch.getView().size() == 3 : ch.getAddress() + "'s view: " + ch.getView(); } } protected JChannel findMergeLeader(JChannel ... channels) { Set<Address> tmp=new TreeSet<Address>(); for(JChannel ch: channels) tmp.add(ch.getAddress()); Address leader=tmp.iterator().next(); for(JChannel ch: channels) if(ch.getAddress().equals(leader)) return ch; return null; } protected static class MyDiagnosticsHandler extends DiagnosticsHandler { protected MyDiagnosticsHandler(InetAddress diagnostics_addr, int diagnostics_port, Log log, SocketFactory socket_factory, ThreadFactory thread_factory) { super(diagnostics_addr,diagnostics_port,log,socket_factory,thread_factory); } public void start() throws IOException { super.start(); } public void stop() { } public void destroy() { super.stop(); } } }