@Test(dataProvider = "createTimer") public void test9(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); win.add(6, new Message()); System.out.println("win: " + win); while ((win.remove()) != null) ; win.stable(6); // 6 is ignore as it is >= highest delivered message System.out.println("win: " + win); assert win.get(2) != null; check(win, 0, 6, 4); win.add(5, new Message()); check(win, 0, 6, 4); while ((win.remove()) != null) ; check(win, 0, 6, 6); win.stable(6); check(win, 6, 6, 6); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testHighestDelivered(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); check(win, 0, 4, 0); win.add(10, new Message()); check(win, 0, 10, 0); System.out.println("win: " + win); win.add(9, new Message()); win.add(7, new Message()); win.add(8, new Message()); win.add(6, new Message()); win.add(5, new Message()); System.out.println("win: " + win); check(win, 0, 10, 0); while ((win.remove()) != null) ; check(win, 0, 10, 10); win.stable(5); System.out.println("win: " + win); check(win, 5, 10, 10); win.stable(10); System.out.println("win: " + win); check(win, 10, 10, 10); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void test8(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); win.add(6, new Message()); check(win, 0, 6, 0); // haven't delivered a message yet while (win.remove() != null) ; check(win, 0, 6, 4); win.add(5, new Message()); check(win, 0, 6, 4); win.remove(); check(win, 0, 6, 5); win.remove(); check(win, 0, 6, 6); win.stable(4); check(win, 4, 6, 6); win.stable(6); check(win, 6, 6, 6); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testAdd(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); check(win, 0, 0, 0); win.add(0, new Message()); // discarded, next expected is 1 check(win, 0, 0, 0); win.add(1, new Message()); check(win, 0, 1, 0); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); check(win, 0, 4, 0); win.add(6, new Message()); check(win, 0, 6, 0); win.add(5, new Message()); check(win, 0, 6, 0); while (win.remove() != null) ; check(win, 0, 6, 6); win.stable(4); check(win, 4, 6, 6); win.stable(6); check(win, 6, 6, 6); } finally { timer.stop(); } }
private ReceiverEntry getOrCreateReceiverEntry(Address sender, long seqno, short conn_id) { NakReceiverWindow win = new NakReceiverWindow( sender, this, seqno - 1, timer, use_range_based_retransmitter, xmit_table_num_rows, xmit_table_msgs_per_row, xmit_table_resize_factor, xmit_table_max_compaction_time, xmit_table_automatic_purging); if (exponential_backoff > 0) win.setRetransmitTimeouts(new ExponentialInterval(exponential_backoff)); else win.setRetransmitTimeouts(new StaticInterval(timeout)); ReceiverEntry entry = new ReceiverEntry(win, conn_id, max_stable_msgs); ReceiverEntry entry2 = recv_table.putIfAbsent(sender, entry); if (entry2 != null) return entry2; if (log.isTraceEnabled()) log.trace( local_addr + ": created receiver window for " + sender + " at seqno=#" + seqno + " for conn-id=" + conn_id); return entry; }
@ManagedOperation(description = "Compacts the retransmission tables") public void compact() { for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) { NakReceiverWindow win = entry.getValue().received_msgs; win.compact(); } }
protected void sendStableMessage(Address dest, short conn_id, long low, long high) { Message stable_msg = new Message(dest, null, null); Unicast2Header hdr = Unicast2Header.createStableHeader(conn_id, low, high); stable_msg.putHeader(this.id, hdr); stable_msg.setFlag(Message.OOB); if (log.isTraceEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(local_addr) .append(" --> STABLE(") .append(dest) .append(": ") .append(low) .append("-") .append(high) .append(", conn_id=") .append(conn_id) .append(")"); log.trace(sb.toString()); } down_prot.down(new Event(Event.MSG, stable_msg)); ReceiverEntry entry = recv_table.get(dest); NakReceiverWindow win = entry != null ? entry.received_msgs : null; if (win != null) win.stable(win.getHighestDelivered()); }
@ManagedOperation( description = "Sends a STABLE message to all senders. This causes message purging and potential" + " retransmissions from senders") public void sendStableMessages() { for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) { Address dest = entry.getKey(); ReceiverEntry val = entry.getValue(); NakReceiverWindow win = val != null ? val.received_msgs : null; if (win != null) { long[] tmp = win.getDigest(); long low = tmp[0], high = tmp[1]; if (val.last_highest == high) { if (val.num_stable_msgs >= val.max_stable_msgs) { continue; } else val.num_stable_msgs++; } else { val.last_highest = high; val.num_stable_msgs = 1; } sendStableMessage(dest, val.recv_conn_id, low, high); } } }
@Test(dataProvider = "createTimer") public void testMissingMessages3(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(5, new Message()); check(win, 0, 5, 0); win.add(8, new Message()); check(win, 0, 8, 0); win.add(9, new Message()); check(win, 0, 9, 0); System.out.println("win: " + win); win.add(2, new Message()); check(win, 0, 9, 0); win.add(3, new Message()); win.add(4, new Message()); check(win, 0, 9, 0); win.add(7, new Message()); check(win, 0, 9, 0); win.add(6, new Message()); check(win, 0, 9, 0); win.add(10, new Message()); check(win, 0, 10, 0); win.add(11, new Message()); check(win, 0, 11, 0); System.out.println("win: " + win); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testMissingMessages4(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 100, timer); win.add(101, new Message()); win.add(105, new Message()); check(win, 0, 105, 100); win.add(108, new Message()); check(win, 0, 108, 100); win.add(109, new Message()); check(win, 0, 109, 100); System.out.println("win: " + win); win.add(102, new Message()); check(win, 0, 109, 100); win.add(103, new Message()); win.add(104, new Message()); check(win, 0, 109, 100); win.add(107, new Message()); check(win, 0, 109, 100); win.add(106, new Message()); check(win, 0, 109, 100); win.add(110, new Message()); check(win, 0, 110, 100); win.add(110, new Message()); check(win, 0, 110, 100); System.out.println("win: " + win); } finally { timer.stop(); } }
@ManagedOperation( description = "Purges highes delivered messages and compacts the retransmission tables") public void purgeAndCompact() { for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) { NakReceiverWindow win = entry.getValue().received_msgs; win.stable(win.getHighestDelivered()); win.compact(); } }
@Test(dataProvider = "createTimer") public void test1(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 1, timer); check(win, 0, 1, 1); assert win.get(23) == null; } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void test4(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 1, timer); win.add(2, new Message()); check(win, 0, 2, 1); } finally { timer.stop(); } }
public void removeReceiveConnection(Address mbr) { ReceiverEntry entry2 = recv_table.remove(mbr); if (entry2 != null) { NakReceiverWindow win = entry2.received_msgs; if (win != null) sendStableMessage( mbr, entry2.recv_conn_id, win.getHighestDelivered(), win.getHighestReceived()); entry2.reset(); } }
@ManagedOperation(description = "Returns the sizes of all NakReceiverWindow.RetransmitTables") public String printRetransmitTableSizes() { StringBuilder sb = new StringBuilder(); for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) { NakReceiverWindow win = entry.getValue().received_msgs; sb.append(entry.getKey() + ": ") .append(win.getRetransmitTableSize()) .append(" (capacity=" + win.getRetransmitTableCapacity()) .append(", fill factor=" + win.getRetransmitTableFillFactor() + "%)\n"); } return sb.toString(); }
@Test(dataProvider = "createTimer") public void test10(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); while ((win.remove()) != null) ; check(win, 0, 4, 4); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testAddOOBAtTail(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); boolean rc; rc = win.add(1, oob()); assert rc; rc = win.add(2, oob()); assert rc; rc = win.add(2, oob()); assert !(rc); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void test12(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message(null, null, new Integer(1))); win.add(2, new Message(null, null, new Integer(2))); win.add(3, new Message(null, null, new Integer(3))); Assert.assertEquals(1, ((Integer) win.remove().getObject()).intValue()); Assert.assertEquals(2, ((Integer) win.remove().getObject()).intValue()); Assert.assertEquals(3, ((Integer) win.remove().getObject()).intValue()); } finally { timer.stop(); } }
private static void add(int num_msgs, TimeScheduler timer) { try { long start, stop; double time_per_msg; NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 1, timer); start = System.currentTimeMillis(); for (int i = 1; i < 1 + num_msgs; i++) { win.add(i, new Message()); } stop = System.currentTimeMillis(); time_per_msg = (stop - start) / (double) num_msgs; System.out.println( "-- time for " + num_msgs + " msgs: " + (stop - start) + ", " + time_per_msg + " ms/msg"); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void test6(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 100, timer); win.add(101, new Message()); System.out.println("win: " + win); win.add(100, new Message()); System.out.println("win: " + win); check(win, 0, 101, 100); win.remove(); System.out.println("win: " + win); check(win, 0, 101, 101); while ((win.remove()) != null) ; check(win, 0, 101, 101); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testHasMessagesToRemove(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); assert !win.hasMessagesToRemove(); win.add(2, new Message()); assert !win.hasMessagesToRemove(); win.add(1, oob()); assert win.hasMessagesToRemove(); win.remove(); assert win.hasMessagesToRemove(); win.remove(); assert !win.hasMessagesToRemove(); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testRemoveRegularAndOOBMessages(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, msg()); System.out.println("win = " + win); win.remove(); System.out.println("win = " + win); assert win.getHighestDelivered() == 1; win.add(3, msg()); win.remove(); System.out.println("win = " + win); assert win.getHighestDelivered() == 1; win.add(2, oob()); win.removeOOBMessage(); System.out.println("win = " + win); assert win.getHighestDelivered() == 2; } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testRemoveOOBMessage(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); System.out.println("win = " + win); win.add(2, msg()); System.out.println("win = " + win); assert win.removeOOBMessage() == null; assert win.remove() == null; win.add(1, oob()); System.out.println("win = " + win); assert win.removeOOBMessage() != null; System.out.println("win = " + win); assert win.removeOOBMessage() == null; assert win.remove() != null; assert win.remove() == null; assert win.removeOOBMessage() == null; } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testRemoveOOBMessages(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(0, msg()); List<Message> list = win.removeOOBMessages(); assert list.isEmpty(); win.add(1, oob()); win.add(2, oob()); win.add(3, msg()); win.add(4, oob()); list = win.removeOOBMessages(); assert list.size() == 2; list = win.removeOOBMessages(); assert list.isEmpty(); win.remove(); list = win.removeOOBMessages(); assert list.size() == 1; } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void test3(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); assert win.get(1) != null; check(win, 0, 1, 0); win.add(2, new Message()); check(win, 0, 2, 0); assert win.get(2) != null; win.remove(); check(win, 0, 2, 1); win.remove(); check(win, 0, 2, 2); } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testRetransmitter(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, msg()); win.add(2, msg()); win.add(3, msg()); win.add(5, msg()); win.add(6, msg()); System.out.println("win = " + win); int num_pending_xmits = win.getPendingXmits(); assert num_pending_xmits == 1; win.add(4, msg()); num_pending_xmits = win.getPendingXmits(); assert num_pending_xmits == 0; } finally { timer.stop(); } }
@Test(dataProvider = "createTimer") public void testRemoveMany(TimeScheduler timer) { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, msg()); win.add(2, msg()); win.add(3, msg()); win.add(5, msg()); win.add(6, msg()); System.out.println("win = " + win); List<Message> msgs = win.removeMany(null); System.out.println("msgs = " + msgs); assert msgs.size() == 3; win.add(4, msg()); msgs = win.removeMany(null); System.out.println("msgs = " + msgs); assert msgs.size() == 3; } finally { timer.stop(); } }
private static void check( NakReceiverWindow win, long lowest, long highest_received, long highest_delivered) { Assert.assertEquals( win.getLowestSeen(), lowest, "lowest=" + lowest + ", win.lowest=" + win.getLowestSeen()); Assert.assertEquals( win.getHighestReceived(), highest_received, "highest_received=" + highest_received + ", win.highest_received=" + win.getHighestReceived()); Assert.assertEquals( win.getHighestDelivered(), highest_delivered, "highest_delivered=" + highest_delivered + ", win.highest_delivered=" + win.getHighestDelivered()); }
@Test(dataProvider = "createTimer") public void test7(TimeScheduler timer) throws Exception { try { NakReceiverWindow win = new NakReceiverWindow(sender, cmd, 0, timer); win.add(1, new Message()); win.add(2, new Message()); win.add(3, new Message()); win.add(4, new Message()); check(win, 0, 4, 0); System.out.println("Note that the subsequent warning is expected:"); win.stable(4); // no-op because we haven't even removed 4 messages check(win, 0, 4, 0); while (win.remove() != null) ; check(win, 0, 4, 4); win.stable(4); check(win, 4, 4, 4); } finally { timer.stop(); } }
/** * Check whether the hashtable 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; 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 { // 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) { 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(); } entry.update(); boolean added = win.add(seqno, msg); // win is guaranteed to be non-null if we get here num_msgs_received++; num_bytes_received += msg.getLength(); if (added) { int len = msg.getLength(); if (len > 0) { boolean send_stable_msg = false; entry.lock(); try { entry.received_bytes += len; if (entry.received_bytes >= max_bytes) { entry.received_bytes = 0; send_stable_msg = true; } } finally { entry.unlock(); } if (send_stable_msg) 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 (from the AckReceiverWindow) 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); } }