/** * Try to remove as many messages as possible from the table as pass them up. Prevents concurrent * passing up of messages by different threads (http://jira.jboss.com/jira/browse/JGRP-198); 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 in the order in which they were sent */ protected int removeAndDeliver( final AtomicBoolean processing, Table<Message> win, Address sender) { int retval = 0; boolean released_processing = false; try { while (true) { List<Message> list = win.removeMany(processing, true, max_msg_batch_size); if (list == null) { released_processing = true; return retval; } MessageBatch batch = new MessageBatch(local_addr, sender, null, false, list); for (Message msg_to_deliver : batch) { // discard OOB msg: it has already been delivered // (http://jira.jboss.com/jira/browse/JGRP-377) if (msg_to_deliver.isFlagSet(Message.Flag.OOB)) batch.remove(msg_to_deliver); } try { if (log.isTraceEnabled()) { Message first = batch.first(), last = batch.last(); StringBuilder sb = new StringBuilder(local_addr + ": delivering"); if (first != null && last != null) { UnicastHeader hdr1 = (UnicastHeader) first.getHeader(id), hdr2 = (UnicastHeader) last.getHeader(id); sb.append(" #").append(hdr1.seqno).append(" - #").append(hdr2.seqno); } sb.append(" (" + batch.size()).append(" messages)"); log.trace(sb); } up_prot.up(batch); } catch (Throwable t) { log.error("failed to deliver batch " + batch, t); } } } finally { // processing is always set in win.remove(processing) above and never here ! This code is just // a // 2nd line of defense should there be an exception before win.remove(processing) sets // processing if (!released_processing) processing.set(false); } }
/** * Check whether the hashmap contains an entry e for <code>sender</code> (create if not). If * 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. */ protected void handleDataReceived( Address sender, long seqno, short 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); if (conn_id != 0) sb.append(", conn_id=").append(conn_id); if (first) sb.append(", first"); sb.append(')'); log.trace(sb); } ReceiverEntry entry = getReceiverEntry(sender, seqno, first, conn_id); if (entry == null) return; if (conn_expiry_timeout > 0) entry.update(); Table<Message> win = entry.received_msgs; boolean added = win.add(seqno, msg); // win is guaranteed to be non-null if we get here num_msgs_received++; if (added) { int len = msg.getLength(); if (len > 0 && entry.incrementStable(len)) sendStableMessage( sender, entry.recv_conn_id, win.getHighestDelivered(), win.getHighestReceived()); } // 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 as many messages as possible and 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 boolean released_processing = false; try { while (true) { List<Message> msgs = win.removeMany(processing, true, max_msg_batch_size); // remove my own messages if (msgs == null || msgs.isEmpty()) { released_processing = true; return; } for (Message m : msgs) { // discard OOB msg: it has already been delivered // (http://jira.jboss.com/jira/browse/JGRP-377) if (m.isFlagSet(Message.OOB)) continue; try { up_prot.up(new Event(Event.MSG, m)); } catch (Throwable t) { log.error("couldn't deliver message " + m, t); } } } } finally { // processing is always set in win.remove(processing) above and never here ! This code is just // a // 2nd line of defense should there be an exception before win.remove(processing) sets // processing if (!released_processing) processing.set(false); } }