sb.append(')');
log.trace(sb);
}
ReceiverEntry entry=recv_table.get(sender);
AckReceiverWindow 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.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) {
sendRequestForFirstSeqno(sender); // drops the message and returns (see below)
return;
}
}
byte result=win.add2(seqno, msg); // win is guaranteed to be non-null if we get here
boolean added=result > 0;
num_msgs_received++;
num_bytes_received+=msg.getLength();
// Cannot be replaced with if(!added), see https://jira.jboss.org/jira/browse/JGRP-1043 comment 15/Sep/09 06:57 AM
// We *have* to do send the ACK, to cover the following scenario:
// - A sends #3 to B
// - B removes #3 and sends ACK(3) to A. B's next_to_remove is now 4
// - B's ACK(3) to A is dropped by the network
// - A keeps retransmitting #3 to B, until it gets an ACK(3)
// -B will never ACK #3 if the 2 lines below are commented ==> endless retransmission of A's #3 !
if(result == -1) { // only ack if seqno was < next_to_remove !
sendAck(sender, seqno);
}
// An OOB message is passed up immediately. Later, when remove() is called, we discard it. This affects ordering !
// http://jira.jboss.com/jira/browse/JGRP-377
if(msg.isFlagSet(Message.OOB) && added) {
try {
up_prot.up(evt);
}
catch(Throwable t) {
log.error("couldn't deliver OOB message " + msg, t);
}
}
final AtomicBoolean processing=win.getProcessing();
if(!processing.compareAndSet(false, true)) {
return;
}
// try to remove (from the AckReceiverWindow) as many messages as possible as pass them up
// Prevents concurrent passing up of messages by different threads (http://jira.jboss.com/jira/browse/JGRP-198);
// this is all the more important once we have a concurrent stack (http://jira.jboss.com/jira/browse/JGRP-181),
// where lots of threads can come up to this point concurrently, but only 1 is allowed to pass at a time
// We *can* deliver messages from *different* senders concurrently, e.g. reception of P1, Q1, P2, Q2 can result in
// delivery of P1, Q1, Q2, P2: FIFO (implemented by UNICAST) says messages need to be delivered only in the
// order in which they were sent by their senders
try {
while(true) {
Tuple<List<Message>,Long> tuple=win.removeMany(max_msg_batch_size);
if(tuple == null)
return;
List<Message> msgs=tuple.getVal1();
if(msgs.isEmpty())
return;