package org.jgroups.tests; import org.jgroups.Address; import org.jgroups.JChannel; import org.jgroups.Message; import org.jgroups.blocks.MethodCall; import org.jgroups.blocks.RequestOptions; import org.jgroups.blocks.RpcDispatcher; import org.jgroups.protocols.*; import org.jgroups.protocols.pbcast.GMS; import org.jgroups.protocols.pbcast.NAKACK2; import org.jgroups.protocols.pbcast.STABLE; import org.jgroups.stack.Protocol; import org.jgroups.stack.ProtocolStack; import org.jgroups.util.Util; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * Tests https://issues.jboss.org/browse/JGRP-1675 * @author Bela Ban * @since 3.5 */ public class RemoteGetStressTest { protected JChannel[] channels; protected List<Address> target_members; // B, C, D protected RpcDispatcher[] dispatchers; protected Random random = new Random(); protected static final int NUM_THREADS=40; protected static final int SIZE=100 * 1000; // size of a GET response protected static final byte[] BUF=new byte[SIZE]; protected static final MethodCall GET_METHOD; protected static final long TIMEOUT=3 * 60 * 1000; // ms protected static final AtomicInteger count=new AtomicInteger(1); protected static final RequestOptions OPTIONS=RequestOptions.SYNC().timeout(TIMEOUT) .flags(Message.Flag.OOB).anycasting(true); protected static boolean USE_SLEEPS=true; static { try { Method get_method=RemoteGetStressTest.class.getMethod("get"); GET_METHOD=new MethodCall(get_method); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } } protected void start() throws Exception { String[] names={"A", "B", "C", "D"}; channels=new JChannel[4]; dispatchers=new RpcDispatcher[channels.length]; for(int i=0; i < channels.length; i++) { channels[i]=createChannel(names[i]); dispatchers[i]=new RpcDispatcher(channels[i], this); channels[i].connect("cluster"); } Util.waitUntilAllChannelsHaveSameView(10000, 500, channels); System.out.println("view A: " + channels[0].getView()); target_members=Arrays.asList(channels[1].getAddress(), channels[2].getAddress(), channels[3].getAddress()); final AtomicInteger success=new AtomicInteger(0), failure=new AtomicInteger(0); if(USE_SLEEPS) insertDISCARD(channels[0], 0.2); long start=System.currentTimeMillis(); Invoker[] invokers=new Invoker[NUM_THREADS]; for(int i=0; i < invokers.length; i++) { invokers[i]=new Invoker(dispatchers[0], success, failure); invokers[i].start(); } for(Invoker invoker: invokers) invoker.join(); long time=System.currentTimeMillis() - start; System.out.println("\n\n**** success: " + success + ", failure=" + failure + ", time=" + time + " ms"); Util.keyPress("enter to terminate"); stop(); } protected void stop() { for(RpcDispatcher disp: dispatchers) disp.stop(); Util.close(channels); } protected static JChannel createChannel(String name) throws Exception { Protocol[] protocols={ new SHARED_LOOPBACK().setValue("thread_pool_min_threads", 1) .setValue("thread_pool_max_threads", 5), new SHARED_LOOPBACK_PING(), new NAKACK2(), new UNICAST3(), new STABLE(), new GMS(), new UFC(), new MFC().setValue("max_credits", 2000000).setValue("min_threshold", 0.4), new FRAG2().fragSize(8000), }; return new JChannel(protocols).name(name); } public static BigObject get() { return new BigObject(count.getAndIncrement()); } public static void main(String[] args) throws Exception { RemoteGetStressTest test=new RemoteGetStressTest(); test.start(); } protected Address randomMember() { return Util.pickRandomElement(target_members); } protected static void insertDISCARD(JChannel ch, double discard_rate) throws Exception { TP transport=ch.getProtocolStack().getTransport(); DISCARD discard=new DISCARD(); discard.setUpDiscardRate(discard_rate); ch.getProtocolStack().insertProtocol(discard, ProtocolStack.Position.ABOVE, transport.getClass()); } protected class Invoker extends Thread { protected final RpcDispatcher disp; protected final AtomicInteger success, failure; public Invoker(RpcDispatcher disp, AtomicInteger success, AtomicInteger failure) { this.disp=disp; this.success=success; this.failure=failure; } public void run() { ArrayList<Address> targets = new ArrayList<>(channels[0].getView().getMembers()); targets.remove(random.nextInt(targets.size())); Collections.rotate(targets, random.nextInt(targets.size())); Future<BigObject>[] futures = new Future[targets.size()]; for(int i=0; i < targets.size(); i++) { Address target=targets.get(i); try { futures[i]=disp.callRemoteMethodWithFuture(target, GET_METHOD, OPTIONS); } catch(Exception e) { e.printStackTrace(); } } for(Future<BigObject> future: futures) { if(future == null) continue; try { BigObject result=future.get(TIMEOUT, TimeUnit.MILLISECONDS); if(result != null) { System.out.println("received object #" + result.num); success.incrementAndGet(); return; } } catch(Exception e) { e.printStackTrace(); } } failure.incrementAndGet(); } } public static class BigObject implements Serializable { private static final long serialVersionUID=1265292900051224502L; int num; public BigObject(int num) { this.num = num; } public BigObject() { } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); byte[] buf = new byte[SIZE]; out.write(buf); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); byte[] buf = new byte[SIZE]; in.read(buf); if(USE_SLEEPS) Util.sleepRandom(1, 10); } @Override public String toString() { return "BigObject#" + num; } } }