package org.jgroups.tests;
import org.jgroups.Address;
import org.jgroups.Global;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.blocks.MethodCall;
import org.jgroups.blocks.RequestOptions;
import org.jgroups.blocks.ResponseMode;
import org.jgroups.blocks.RpcDispatcher;
import org.jgroups.util.RspList;
import org.jgroups.util.Util;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import java.util.List;
import java.util.Vector;
/**
* Test the distributed RPC deadlock detection mechanism, using one or two channels.
*
* @author John Giorgiadis
* @author Ovidiu Feodorov <ovidiuf@users.sourceforge.net>
* *
* @version $Revision: 1.23 $
*/
@Test(groups=Global.STACK_DEPENDENT,singleThreaded=true)
public class Deadlock2Test extends ChannelTestBase {
private String name = "Deadlock2Test";
private JChannel c1, c2;
@AfterMethod
void cleanup() {
Util.close(c1, c2);
}
/**
* Tests the deadlock resolution using self-calls on a single channel. The deadlock detection
* is turned on so the method call should go straight through. If there is a problem, JUnit will
* timeout.
*
* @throws Exception
*/
public void testOneChannel() throws Exception {
c1 = createChannel(true);
ServerObject serverObject = new ServerObject("obj1");
RpcDispatcher disp=new RpcDispatcher(c1, serverObject);
serverObject.setRpcDispatcher(disp);
c1.connect(name);
Address localAddress = c1.getAddress();
// call the nested group method on itself
MethodCall call = new MethodCall("outerMethod", new Object[0], new Class[0]);
log("calling outerMethod() on all members");
RspList rspList = disp.callRemoteMethods(null, call, new RequestOptions(ResponseMode.GET_ALL, 0));
log("results of outerMethod(): " + rspList);
Assert.assertEquals(1, rspList.size());
assertEquals("outerMethod[innerMethod]", rspList.getValue(localAddress));
assertTrue(rspList.isReceived(localAddress));
assertFalse(rspList.isSuspected(localAddress));
}
/**
* Tests the deadlock resolution using two different channels. The deadlock detection
* is turned on. It implements the following scenario:
*
* Channel1 Channel2
* | |
* + -------------------------------> outerMethod()
* | RPC
* | |
* | |
* | |
* | <-- innerMethod() <-----------------+ ---------+
* | | |
* | | <-- innerMethod()
*
* If there is a deadlock, JUnit will timeout and fail the test.
*
*/
public void testTwoChannels() throws Throwable {
ServerObject obj1, obj2 = null;
c1 = createChannel(true);
obj1 = new ServerObject("obj1");
RpcDispatcher disp1=new RpcDispatcher(c1, obj1);
obj1.setRpcDispatcher(disp1);
c1.connect(name);
c2 = createChannel(c1);
obj2 = new ServerObject("obj2");
RpcDispatcher disp2=new RpcDispatcher(c2, obj2);
obj2.setRpcDispatcher(disp2);
c2.connect(name);
Address localAddress2 = c2.getAddress();
// call a point-to-point method on Member 2 that triggers a nested distributed RPC
MethodCall call = new MethodCall("outerMethod", new Object[0], new Class[0]);
log("calling outerMethod() on " + localAddress2);
Object retval = disp1.callRemoteMethod(localAddress2, call, new RequestOptions(ResponseMode.GET_ALL, 0));
log("results of outerMethod(): " + retval);
}
public void testTwoChannelsWithInitialMulticast() throws Exception {
ServerObject obj1, obj2 = null;
c1 = createChannel(true);
obj1 = new ServerObject("obj1");
RpcDispatcher disp1=new RpcDispatcher(c1, obj1);
obj1.setRpcDispatcher(disp1);
c1.connect(name);
c2 = createChannel(c1);
obj2 = new ServerObject("obj2");
RpcDispatcher disp2=new RpcDispatcher(c2, obj2);
obj2.setRpcDispatcher(disp2);
c2.connect(name);
Vector<Address> dests=new Vector<Address>();
dests.add(c1.getAddress());
dests.add(c2.getAddress());
// call a point-to-point method on Member 2 that triggers a nested distributed RPC
MethodCall call = new MethodCall("outerMethod", new Object[0], new Class[0]);
log("calling outerMethod() on all members");
RspList rsps = disp1.callRemoteMethods(dests, call, new RequestOptions(ResponseMode.GET_ALL, 0));
log("results of outerMethod():\n" + rsps);
Assert.assertEquals(2, rsps.size());
}
static void log(String msg) {
System.out.println("[" + Thread.currentThread() + "] " + msg);
}
public static class ServerObject {
String myName;
public ServerObject(String name) {
this.myName=name;
}
private RpcDispatcher disp;
/**
* The ServerObject keeps a reference to its dispatcher to be able to send nested group
* RPCs.
*/
public void setRpcDispatcher(RpcDispatcher rpcDispatcher) {
this.disp = rpcDispatcher;
}
public String outerMethod() throws Exception {
log("**** outerMethod() received, calling innerMethod() on all members");
MethodCall call = new MethodCall("innerMethod", new Object[0], new Class[0]);
// RspList rspList = disp.callRemoteMethods(null, call, GroupResponseMode.GET_ALL, 5000);
RequestOptions opts=new RequestOptions(ResponseMode.GET_ALL, 0, false, null, (Message.Flag[])null);
opts.setFlags(Message.Flag.OOB);
RspList<String> rspList = disp.callRemoteMethods(null, call, opts);
List<String> results = rspList.getResults();
log("results of calling innerMethod():\n" + rspList);
StringBuilder sb=new StringBuilder("outerMethod[");
boolean first=true;
for(String s: results) {
if(first)
first=false;
else
sb.append(";");
sb.append(s);
}
sb.append("]");
return sb.toString();
}
public static String innerMethod() {
log("**** innerMethod() received, returning result");
return "innerMethod";
}
}
}