protected static <T> void assertIndices(Table<T> table, long low, long hd, long hr) { assert table.getLow() == low : "expected low=" + low + " but was " + table.getLow(); assert table.getHighestDelivered() == hd : "expected hd=" + hd + " but was " + table.getHighestDelivered(); assert table.getHighestReceived() == hr : "expected hr=" + hr + " but was " + table.getHighestReceived(); }
public static void testForEach() { class MyVisitor<T> implements Table.Visitor<T> { List<int[]> list = new ArrayList<int[]>(20); public boolean visit(long seqno, T element, int row, int column) { System.out.println("#" + seqno + ": " + element + ", row=" + row + ", column=" + column); list.add(new int[] {row, column}); return true; } } MyVisitor<Integer> visitor = new MyVisitor<Integer>(); Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 20; i++) table.add(i, i); System.out.println("table = " + table); table.forEach(table.getLow() + 1, table.getHighestReceived() - 1, visitor); int count = 1; for (int[] pair : visitor.list) { int row = pair[0], column = pair[1]; if (count < Util.getNextHigherPowerOfTwo(10)) { assert row == 0; assert column == count; } else { assert row == 1; assert column == count - Util.getNextHigherPowerOfTwo(10); } count++; } }
public void removeReceiveConnection(Address mbr) { ReceiverEntry entry2 = recv_table.remove(mbr); if (entry2 != null) { Table<Message> win = entry2.received_msgs; if (win != null) sendStableMessage( mbr, entry2.recv_conn_id, win.getHighestDelivered(), win.getHighestReceived()); entry2.reset(); } }
public void run() { for (SenderEntry val : send_table.values()) { Table<Message> buf = val != null ? val.sent_msgs : null; if (buf != null && !buf.isEmpty()) { long from = buf.getHighestDelivered() + 1, to = buf.getHighestReceived(); List<Message> list = buf.get(from, to); if (list != null) { for (Message msg : list) retransmit(msg); } } } }
public void testIndexWithRemoveMany() { Table<Integer> buf = new Table<Integer>(3, 10, 5); assert buf.getHighestDelivered() == 5; assert buf.getHighestReceived() == 5; buf.add(6, 6); buf.add(7, 7); long low = buf.getLow(); buf.removeMany(true, 0); System.out.println("buf = " + buf); for (long i = low; i <= 7; i++) assert buf._get(i) == null : "message with seqno=" + i + " is not null"; assertIndices(buf, 7, 7, 7); }
public void testIndex() { Table<Integer> buf = new Table<Integer>(3, 10, 5); assert buf.getHighestDelivered() == 5; assert buf.getHighestReceived() == 5; buf.add(6, 6); buf.add(7, 7); buf.remove(false); buf.remove(false); long low = buf.getLow(); assert low == 5; buf.purge(4); buf.purge(5); buf.purge(6); buf.purge(7); System.out.println("buf = " + buf); for (long i = low; i <= 7; i++) assert buf._get(i) == null : "message with seqno=" + i + " is not null"; }
/** * Purge all messages in window for local_addr, which are <= low. Check if the window's highest * received message is > high: if true, retransmit all messages from high - win.high to sender * * @param sender * @param hd Highest delivered seqno * @param hr Highest received seqno */ protected void stable(Address sender, short conn_id, long hd, long hr) { SenderEntry entry = send_table.get(sender); Table<Message> win = entry != null ? entry.sent_msgs : null; if (win == null) return; if (log.isTraceEnabled()) log.trace( new StringBuilder() .append(local_addr) .append(" <-- STABLE(") .append(sender) .append(": ") .append(hd) .append("-") .append(hr) .append(", conn_id=" + conn_id) + ")"); if (entry.send_conn_id != conn_id) { log.warn( local_addr + ": my conn_id (" + entry.send_conn_id + ") != received conn_id (" + conn_id + "); discarding STABLE message !"); return; } win.purge(hd, true); long win_hr = win.getHighestReceived(); if (win_hr > hr) { for (long seqno = hr; seqno <= win_hr; seqno++) { Message msg = win.get( seqno); // destination is still the same (the member which sent the STABLE message) if (msg != null) down_prot.down(new Event(Event.MSG, msg)); } } }
/** * 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); } }