Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

-Added synchronization around removal and re-creation of a window in…

… UNICAST and UNICAST2

 - Added testMultipleConcurrentResets() to UNICAST(2)_ConnectionTests
 [https://issues.jboss.org/browse/JGRP-1347]
  • Loading branch information...
commit 0be52c0d7ceff851b971ee26a12cc6d6ee0e949f 1 parent 8b98023
@belaban authored
View
59 src/org/jgroups/protocols/UNICAST.java
@@ -67,6 +67,8 @@
private final ConcurrentMap<Address, SenderEntry> send_table=Util.createConcurrentMap();
private final ConcurrentMap<Address, ReceiverEntry> recv_table=Util.createConcurrentMap();
+ protected final ReentrantLock recv_table_lock=new ReentrantLock();
+
private final List<Address> members=new ArrayList<Address>(11);
private Address local_addr=null;
@@ -496,7 +498,7 @@ public void expired(Address key) {
* e.received_msgs is null and <code>first</code> is true: create a new AckReceiverWindow(seqno) and
* add message. Set e.received_msgs to the new window. Else just add the message.
*/
- private void handleDataReceived(Address sender, long seqno, long conn_id, boolean first, Message msg, Event evt) {
+ protected void handleDataReceived(Address sender, long seqno, long conn_id, boolean first, Message msg, Event evt) {
if(log.isTraceEnabled()) {
StringBuilder sb=new StringBuilder();
sb.append(local_addr).append(" <-- DATA(").append(sender).append(": #").append(seqno);
@@ -506,36 +508,45 @@ private void handleDataReceived(Address sender, long seqno, long conn_id, boole
log.trace(sb);
}
- ReceiverEntry entry=recv_table.get(sender);
- AckReceiverWindow win=entry != null? entry.received_msgs : null;
+ AckReceiverWindow win;
- if(first) {
- if(entry == null) {
- entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
- win=entry.received_msgs;
- }
- else { // entry != null && win != null
- if(conn_id != entry.recv_conn_id) {
- if(log.isTraceEnabled())
- log.trace(local_addr + ": conn_id=" + conn_id + " != " + entry.recv_conn_id + "; resetting receiver window");
-
- ReceiverEntry entry2=recv_table.remove(sender);
- if(entry2 != null)
- entry2.received_msgs.reset();
-
+ recv_table_lock.lock();
+ try {
+ ReceiverEntry entry=recv_table.get(sender);
+ win=entry != null? entry.received_msgs : null;
+ if(first) {
+ if(entry == null) {
entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
win=entry.received_msgs;
}
- else {
- ;
+ else { // entry != null && win != null
+ if(conn_id != entry.recv_conn_id) {
+ if(log.isTraceEnabled())
+ log.trace(local_addr + ": conn_id=" + conn_id + " != " + entry.recv_conn_id + "; resetting receiver window");
+
+ ReceiverEntry entry2=recv_table.remove(sender);
+ if(entry2 != null)
+ entry2.received_msgs.reset();
+
+ entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
+ win=entry.received_msgs;
+ }
+ else {
+ ;
+ }
+ }
+ }
+ else { // entry == null && win == null OR entry != null && win == null OR entry != null && win != null
+ if(win == null || entry.recv_conn_id != conn_id) {
+ recv_table_lock.unlock();
+ sendRequestForFirstSeqno(sender); // drops the message and returns (see below)
+ return;
}
}
}
- else { // entry == null && win == null OR entry != null && win == null OR entry != null && win != null
- if(win == null || entry.recv_conn_id != conn_id) {
- sendRequestForFirstSeqno(sender); // drops the message and returns (see below)
- return;
- }
+ finally {
+ if(recv_table_lock.isHeldByCurrentThread())
+ recv_table_lock.unlock();
}
byte result=win.add2(seqno, msg); // win is guaranteed to be non-null if we get here
View
60 src/org/jgroups/protocols/UNICAST2.java
@@ -90,6 +90,8 @@
private final ConcurrentMap<Address, SenderEntry> send_table=Util.createConcurrentMap();
private final ConcurrentMap<Address, ReceiverEntry> recv_table=Util.createConcurrentMap();
+ protected final ReentrantLock recv_table_lock=new ReentrantLock();
+
private final List<Address> members=new ArrayList<Address>(11);
private Address local_addr=null;
@@ -602,7 +604,7 @@ public void expired(Address key) {
* e.received_msgs is null and <code>first</code> is true: create a new AckReceiverWindow(seqno) and
* add message. Set e.received_msgs to the new window. Else just add the message.
*/
- private void handleDataReceived(Address sender, long seqno, long conn_id, boolean first, Message msg, Event evt) {
+ protected void handleDataReceived(Address sender, long seqno, long conn_id, boolean first, Message msg, Event evt) {
if(log.isTraceEnabled()) {
StringBuilder sb=new StringBuilder();
sb.append(local_addr).append(" <-- DATA(").append(sender).append(": #").append(seqno);
@@ -612,37 +614,47 @@ private void handleDataReceived(Address sender, long seqno, long conn_id, boolea
log.trace(sb);
}
- ReceiverEntry entry=recv_table.get(sender);
- NakReceiverWindow win=entry != null? entry.received_msgs : null;
-
- if(first) {
- if(entry == null) {
- entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
- win=entry.received_msgs;
- }
- else { // entry != null && win != null
- if(conn_id != entry.recv_conn_id) {
- if(log.isTraceEnabled())
- log.trace(local_addr + ": conn_id=" + conn_id + " != " + entry.recv_conn_id + "; resetting receiver window");
-
- ReceiverEntry entry2=recv_table.remove(sender);
- if(entry2 != null)
- entry2.received_msgs.destroy();
+ ReceiverEntry entry;
+ NakReceiverWindow win;
+ recv_table_lock.lock();
+ try {
+ entry=recv_table.get(sender);
+ win=entry != null? entry.received_msgs : null;
+ if(first) {
+ if(entry == null) {
entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
win=entry.received_msgs;
}
- else {
- ;
+ else { // entry != null && win != null
+ if(conn_id != entry.recv_conn_id) {
+ if(log.isTraceEnabled())
+ log.trace(local_addr + ": conn_id=" + conn_id + " != " + entry.recv_conn_id + "; resetting receiver window");
+
+ ReceiverEntry entry2=recv_table.remove(sender);
+ if(entry2 != null)
+ entry2.received_msgs.destroy();
+
+ entry=getOrCreateReceiverEntry(sender, seqno, conn_id);
+ win=entry.received_msgs;
+ }
+ else {
+ ;
+ }
}
}
- }
- else { // entry == null && win == null OR entry != null && win == null OR entry != null && win != null
- if(win == null || entry.recv_conn_id != conn_id) {
- sendRequestForFirstSeqno(sender, seqno); // drops the message and returns (see below)
- return;
+ else { // entry == null && win == null OR entry != null && win == null OR entry != null && win != null
+ if(win == null || entry.recv_conn_id != conn_id) {
+ recv_table_lock.unlock();
+ sendRequestForFirstSeqno(sender, seqno); // drops the message and returns (see below)
+ return;
+ }
}
}
+ finally {
+ if(recv_table_lock.isHeldByCurrentThread())
+ recv_table_lock.unlock();
+ }
boolean added=win.add(seqno, msg); // win is guaranteed to be non-null if we get here
num_msgs_received++;
View
53 tests/junit-functional/org/jgroups/tests/UNICAST2_ConnectionTests.java
@@ -11,6 +11,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CyclicBarrier;
/**
* Tests unilateral closings of UNICAST2 connections. The test scenarios are described in doc/design.UNICAST.new.txt.
@@ -123,6 +124,58 @@ public void testAClosingUnilaterallyButLosingFirstMessage() throws Exception {
}
+ /** Tests concurrent reception of multiple messages with a different conn_id (https://issues.jboss.org/browse/JGRP-1347) */
+ public void testMultipleConcurrentResets() throws Exception {
+ sendAndCheck(a, b_addr, 1, r2);
+
+ // now close connection on A unilaterally
+ System.out.println("==== Closing the connection on A");
+ u1.removeConnection(b_addr);
+
+ r2.clear();
+
+ final UNICAST2 unicast=(UNICAST2)b.getProtocolStack().findProtocol(UNICAST2.class);
+
+ int NUM=10;
+
+ final List<Message> msgs=new ArrayList<Message>(NUM);
+
+ for(int i=1; i <= NUM; i++) {
+ Message msg=new Message(b_addr, a_addr, "m" + i);
+ UNICAST2.Unicast2Header hdr=UNICAST2.Unicast2Header.createDataHeader(1, (short)2, true);
+ msg.putHeader(unicast.getId(), hdr);
+ msgs.add(msg);
+ }
+
+
+ Thread[] threads=new Thread[NUM];
+ final CyclicBarrier barrier=new CyclicBarrier(NUM+1);
+ for(int i=0; i < NUM; i++) {
+ final int index=i;
+ threads[i]=new Thread() {
+ public void run() {
+ try {
+ barrier.await();
+ unicast.up(new Event(Event.MSG, msgs.get(index)));
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ threads[i].start();
+ }
+
+ barrier.await();
+ for(Thread thread: threads)
+ thread.join();
+
+ List<Message> list=r2.getMessages();
+ System.out.println("list = " + print(list));
+
+ assert list.size() == 1 : "list must have 1 element but has " + list.size() + ": " + print(list);
+ }
+
/**
* Send num unicasts on both channels and verify the other end received them
View
97 tests/junit-functional/org/jgroups/tests/UNICAST_ConnectionTests.java
@@ -1,19 +1,21 @@
package org.jgroups.tests;
import org.jgroups.*;
+import org.jgroups.protocols.UNICAST;
+import org.jgroups.protocols.UNICAST2;
import org.jgroups.stack.Protocol;
import org.jgroups.stack.ProtocolStack;
-import org.jgroups.protocols.UNICAST;
import org.jgroups.util.Util;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import java.util.List;
import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CyclicBarrier;
/**
- * Tests unilateral closings of UNICAST connections. The test scenarios are described in doc/design.UNICAST.new.txt.
+ * Tests unilateral closings of UNICAST connections. The test scenarios are described in doc/design/UNICAST2.txt
* @author Bela Ban
*/
@Test(groups=Global.FUNCTIONAL,sequential=true)
@@ -21,7 +23,7 @@
private JChannel a, b;
private Address a_addr, b_addr;
private MyReceiver r1, r2;
- private UNICAST u1, u2;
+ private Protocol u1, u2;
private static final String props="SHARED_LOOPBACK:UNICAST";
private static final String CLUSTER="UNICAST_ConnectionTests";
@@ -31,15 +33,17 @@ void start() throws Exception {
r1=new MyReceiver("A");
r2=new MyReceiver("B");
a=new JChannel(props);
+ a.setName("A");
a.connect(CLUSTER);
a_addr=a.getAddress();
a.setReceiver(r1);
- u1=(UNICAST)a.getProtocolStack().findProtocol(UNICAST.class);
+ u1=a.getProtocolStack().findProtocol(UNICAST.class);
b=new JChannel(props);
+ b.setName("B");
b.connect(CLUSTER);
b_addr=b.getAddress();
b.setReceiver(r2);
- u2=(UNICAST)b.getProtocolStack().findProtocol(UNICAST.class);
+ u2=b.getProtocolStack().findProtocol(UNICAST.class);
System.out.println("A=" + a_addr + ", B=" + b_addr);
}
@@ -65,8 +69,8 @@ public void testBothChannelsClosing() throws Exception {
// now close the connections to each other
System.out.println("==== Closing the connections on both sides");
- u1.removeConnection(b_addr);
- u2.removeConnection(a_addr);
+ removeConnection(u1, b_addr);
+ removeConnection(u2, a_addr);
r1.clear(); r2.clear();
// causes new connection establishment
@@ -82,7 +86,7 @@ public void testAClosingUnilaterally() throws Exception {
// now close connection on A unilaterally
System.out.println("==== Closing the connection on A");
- u1.removeConnection(b_addr);
+ removeConnection(u1, b_addr);
// then send messages from A to B
sendAndCheck(a, b_addr, 10, r2);
@@ -96,7 +100,7 @@ public void testBClosingUnilaterally() throws Exception {
// now close connection on A unilaterally
System.out.println("==== Closing the connection on B");
- u2.removeConnection(a_addr);
+ removeConnection(u2, a_addr);
// then send messages from A to B
sendAndCheck(a, b_addr, 10, r2);
@@ -108,11 +112,11 @@ public void testBClosingUnilaterally() throws Exception {
* but loses the first message
*/
public void testAClosingUnilaterallyButLosingFirstMessage() throws Exception {
- sendToEachOtherAndCheck(10);
+ sendAndCheck(a, b_addr, 10, r2);
// now close connection on A unilaterally
System.out.println("==== Closing the connection on A");
- u1.removeConnection(b_addr);
+ removeConnection(u1, b_addr);
// add a Drop protocol to drop the first unicast message
Drop drop=new Drop(true);
@@ -122,6 +126,58 @@ public void testAClosingUnilaterallyButLosingFirstMessage() throws Exception {
sendAndCheck(a, b_addr, 10, r2);
}
+ /** Tests concurrent reception of multiple messages with a different conn_id (https://issues.jboss.org/browse/JGRP-1347) */
+ public void testMultipleConcurrentResets() throws Exception {
+ sendAndCheck(a, b_addr, 1, r2);
+
+ // now close connection on A unilaterally
+ System.out.println("==== Closing the connection on A");
+ removeConnection(u1, b_addr);
+
+ r2.clear();
+
+ final UNICAST unicast=(UNICAST)b.getProtocolStack().findProtocol(UNICAST.class);
+
+ int NUM=10;
+
+ final List<Message> msgs=new ArrayList<Message>(NUM);
+
+ for(int i=1; i <= NUM; i++) {
+ Message msg=new Message(b_addr, a_addr, "m" + i);
+ UNICAST.UnicastHeader hdr=UNICAST.UnicastHeader.createDataHeader(1, (short)2, true);
+ msg.putHeader(unicast.getId(), hdr);
+ msgs.add(msg);
+ }
+
+
+ Thread[] threads=new Thread[NUM];
+ final CyclicBarrier barrier=new CyclicBarrier(NUM+1);
+ for(int i=0; i < NUM; i++) {
+ final int index=i;
+ threads[i]=new Thread() {
+ public void run() {
+ try {
+ barrier.await();
+ unicast.up(new Event(Event.MSG, msgs.get(index)));
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ threads[i].start();
+ }
+
+ barrier.await();
+ for(Thread thread: threads)
+ thread.join();
+
+ List<Message> list=r2.getMessages();
+ System.out.println("list = " + print(list));
+
+ assert list.size() == 1 : "list must have 1 element but has " + list.size() + ": " + print(list);
+ }
+
/**
@@ -152,14 +208,27 @@ private static void sendAndCheck(JChannel channel, Address dest, int num, MyRece
for(int i=1; i <= num; i++)
channel.send(dest, "m" + i);
List<Message> list=receiver.getMessages();
- for(int i=0; i < 10; i++) {
+ for(int i=0; i < 20; i++) {
if(list.size() == num)
break;
Util.sleep(500);
}
System.out.println("list = " + print(list));
int size=list.size();
- assert size == num : "list has " + size + " elements";
+ assert size == num : "list has " + size + " elements: " + list;
+ }
+
+ protected void removeConnection(Protocol prot, Address target) {
+ if(prot instanceof UNICAST) {
+ UNICAST unicast=(UNICAST)prot;
+ unicast.removeConnection(target);
+ }
+ else if(prot instanceof UNICAST2) {
+ UNICAST2 unicast=(UNICAST2)prot;
+ unicast.removeConnection(target);
+ }
+ else
+ throw new IllegalArgumentException("prot (" + prot + ") needs to be UNICAST or UNICAST2");
}
Please sign in to comment.
Something went wrong with that request. Please try again.