public void testPurge3() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 100; i++) table.add(i, i); System.out.println("table = " + table); table.removeMany(true, 53); for (int i = 54; i <= 100; i++) assert table.get(i) == i; }
public void testAdd() { Table<Integer> buf = new Table<Integer>(3, 10, 0); buf.add(1, 322649); buf.add(2, 100000); System.out.println("buf = " + buf); assert buf.size() == 2; }
protected void handleAckReceived(Address sender, long seqno, short conn_id) { if (log.isTraceEnabled()) log.trace( new StringBuilder() .append(local_addr) .append(" <-- ACK(") .append(sender) .append(": #") .append(seqno) .append(", conn-id=") .append(conn_id) .append(')')); SenderEntry entry = send_table.get(sender); if (entry != null && entry.send_conn_id != conn_id) { if (log.isTraceEnabled()) log.trace( local_addr + ": my conn_id (" + entry.send_conn_id + ") != received conn_id (" + conn_id + "); discarding ACK"); return; } Table<Message> win = entry != null ? entry.sent_msgs : null; if (win != null) { win.purge(seqno, true); // removes all messages <= seqno (forced purge) num_acks_received++; } }
/** * Runs NUM adder threads, each adder adds 1 (unique) seqno. When all adders are done, we should * have NUM elements in the table. */ public void testConcurrentAdd() { final int NUM = 100; final Table<Integer> buf = new Table<Integer>(3, 10, 0); CountDownLatch latch = new CountDownLatch(1); Adder[] adders = new Adder[NUM]; for (int i = 0; i < adders.length; i++) { adders[i] = new Adder(latch, i + 1, buf); adders[i].start(); } System.out.println("starting threads"); latch.countDown(); System.out.print("waiting for threads to be done: "); for (Adder adder : adders) { try { adder.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("OK"); System.out.println("buf = " + buf); assert buf.size() == NUM; }
@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(); Table<Message> 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 >= 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); } } }
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++; } }
/** * We need to resend our first message with our conn_id * * @param sender * @param seqno Resend the non null messages in the range [lowest .. seqno] */ protected void handleResendingOfFirstMessage(Address sender, long seqno) { if (log.isTraceEnabled()) log.trace(local_addr + " <-- SEND_FIRST_SEQNO(" + sender + "," + seqno + ")"); SenderEntry entry = send_table.get(sender); Table<Message> win = entry != null ? entry.sent_msgs : null; if (win == null) { if (log.isErrorEnabled()) log.error(local_addr + ": sender window for " + sender + " not found"); return; } boolean first_sent = false; for (long i = win.getLow() + 1; i <= seqno; i++) { Message rsp = win.get(i); if (rsp == null) continue; if (first_sent) { down_prot.down(new Event(Event.MSG, rsp)); } else { first_sent = true; // We need to copy the UnicastHeader and put it back into the message because Message.copy() // doesn't copy // the headers and therefore we'd modify the original message in the sender retransmission // window // (https://jira.jboss.org/jira/browse/JGRP-965) Message copy = rsp.copy(); Unicast2Header hdr = (Unicast2Header) copy.getHeader(this.id); Unicast2Header newhdr = hdr.copy(); newhdr.first = true; copy.putHeader(this.id, newhdr); down_prot.down(new Event(Event.MSG, copy)); } } }
public void testAddList() { Table<Integer> buf = new Table<Integer>(3, 10, 0); List<Tuple<Long, Integer>> msgs = createList(1, 2); boolean rc = buf.add(msgs); System.out.println("buf = " + buf); assert rc; assert buf.size() == 2; }
public static void testDuplicateAddition() { Table<Integer> table = new Table<Integer>(3, 10, 0); addAndGet(table, 1, 5, 9, 10); assert !table.add(5, 5); assert table.get(5) == 5; assert table.size() == 4; assertIndices(table, 0, 0, 10); }
public static void testCreation() { Table<Integer> table = new Table<Integer>(3, 10, 0); System.out.println("table = " + table); int size = table.size(); assert size == 0; assert table.get(15) == null; assertIndices(table, 0, 0, 0); }
public static void testAdditionWithOffset() { Table<Integer> table = new Table<Integer>(3, 10, 100); addAndGet(table, 101, 105, 109, 110, 111, 119, 120, 129); System.out.println("table: " + table.dump()); assert table.size() == 8; assertCapacity(table.capacity(), 3, 10); assertIndices(table, 100, 100, 129); }
protected static void addAndGet(Table<Integer> table, int... seqnos) { for (int seqno : seqnos) { boolean added = table.add((long) seqno, seqno); assert added; Integer val = table.get(seqno); assert val != null && val == seqno; } }
public void testAddWithInvalidSeqno() { Table<Integer> buf = new Table<Integer>(3, 10, 20); boolean success = buf.add(10, 0); assert !success; success = buf.add(20, 0); assert !success; assert buf.isEmpty(); }
public static void testAdditionWithOffset2() { Table<Integer> table = new Table<Integer>(3, 10, 2); addAndGet(table, 1000, 1001); table.compact(); addAndGet(table, 1005, 1009, 1010, 1011, 1019, 1020, 1029); System.out.println("table: " + table.dump()); assert table.size() == 9; assertIndices(table, 2, 2, 1029); }
public void testGet() { final Table<Integer> buf = new Table<Integer>(3, 10, 0); for (int i : Arrays.asList(1, 2, 3, 4, 5)) buf.add(i, i); assert buf.get(0) == null; assert buf.get(1) == 1; assert buf.get(10) == null; assert buf.get(5) == 5; assert buf.get(6) == null; }
public static void testGetMissingFirst() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int num : Arrays.asList(2, 3, 4, 5)) table.add(num, num); System.out.println("table = " + table); SeqnoList missing = table.getMissing(); System.out.println("missing=" + missing); assert missing.size() == 1; assert table.getNumMissing() == 1; }
public static void testMove3() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i < 30; i++) table.add(i, i); table.removeMany(true, 23); System.out.println("table = " + table); table.add(30, 30); // triggers a resize() --> move() for (int i = 1; i <= 23; i++) assert table._get(i) == null; for (int i = 24; i < 30; i++) assert table._get(i) != null; }
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 static void testAddListWithResizing2() { Table<Integer> table = new Table<Integer>(3, 500, 0); List<Tuple<Long, Integer>> msgs = new ArrayList<Tuple<Long, Integer>>(); for (int i = 1; i < 100; i++) msgs.add(new Tuple<Long, Integer>((long) i, i)); table.add(msgs, false); System.out.println("table = " + table); int num_resizes = table.getNumResizes(); System.out.println("num_resizes = " + num_resizes); assert num_resizes == 0 : "number of resizings=" + num_resizes + " (expected 0)"; }
@ManagedOperation(description = "Prints the contents of the send windows for all members") public String printSendWindowMessages() { StringBuilder ret = new StringBuilder(local_addr + ":\n"); for (Map.Entry<Address, SenderEntry> entry : send_table.entrySet()) { Address addr = entry.getKey(); Table<Message> buf = entry.getValue().sent_msgs; ret.append(addr).append(": ").append(buf.toString()).append('\n'); } return ret.toString(); }
public void run() { for (Map.Entry<Address, ReceiverEntry> entry : recv_table.entrySet()) { Address target = entry.getKey(); // target to send retransmit requests to ReceiverEntry val = entry.getValue(); Table<Message> buf = val != null ? val.received_msgs : null; if (buf != null && buf.getNumMissing() > 0) { SeqnoList missing = buf.getMissing(); if (missing != null) retransmit(missing, target); } } }
public void testGetMissing4() { Table<Integer> buf = new Table<Integer>(3, 30, 0); for (int i : Arrays.asList(2, 5, 10, 11, 12, 13, 15, 20, 28, 30)) buf.add(i, i); System.out.println("buf = " + buf); int missing = buf.getNumMissing(); assert missing == 20; System.out.println("missing=" + missing); SeqnoList missing_list = buf.getMissing(); System.out.println("missing_list = " + missing_list); assert missing_list.size() == missing; }
/** * 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 = 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++; // 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 int num_msgs = removeAndDeliver(processing, win); if (num_msgs > 0) { long hd = win.getHighestDelivered(); sendAck(sender, hd); } }
public static void testRemoveMany() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int seqno : Arrays.asList(1, 2, 3, 4, 5, 7, 8, 9, 10)) table.add(seqno, seqno); System.out.println("table = " + table); assertIndices(table, 0, 0, 10); List<Integer> list = table.removeMany(true, 4); System.out.println("list=" + list + ", table=" + table); assert table.size() == 5 && table.getNumMissing() == 1; assert list != null && list.size() == 4; for (int num : Arrays.asList(1, 2, 3, 4)) assert list.contains(num); assertIndices(table, 4, 4, 10); }
protected void handleBatchReceived(Address sender, Map<Short, List<Message>> map) { for (Map.Entry<Short, List<Message>> element : map.entrySet()) { final List<Message> msg_list = element.getValue(); if (log.isTraceEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(local_addr) .append(" <-- DATA(") .append(sender) .append(": " + printMessageList(msg_list)) .append(')'); log.trace(sb); } short conn_id = element.getKey(); ReceiverEntry entry = null; for (Message msg : msg_list) { UnicastHeader hdr = (UnicastHeader) msg.getHeader(id); entry = getReceiverEntry(sender, hdr.seqno, hdr.first, conn_id); if (entry == null) continue; Table<Message> win = entry.received_msgs; boolean msg_added = win.add(hdr.seqno, msg); // win is guaranteed to be non-null if we get here num_msgs_received++; if (hdr.first && msg_added) sendAck( sender, hdr.seqno, conn_id); // send an ack immediately when we received the first message of a conn // 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.Flag.OOB) && msg_added) { try { up_prot.up(new Event(Event.MSG, msg)); } catch (Throwable t) { log.error("couldn't deliver OOB message " + msg, t); } } } if (entry != null && conn_expiry_timeout > 0) entry.update(); } ReceiverEntry entry = recv_table.get(sender); Table<Message> win = entry != null ? entry.received_msgs : null; if (win != null) { final AtomicBoolean processing = win.getProcessing(); if (processing.compareAndSet(false, true)) { removeAndDeliver(processing, win, sender); sendAck(sender, win.getHighestDeliverable(), entry.recv_conn_id); } } }
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 static void testRemoveManyWithWrapping2() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int seqno : Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 20)) table.add(seqno, seqno); System.out.println("table = " + table); assertIndices(table, 0, 0, 20); assert table.size() == 18 && table.getNumMissing() == 2; List<Integer> list = table.removeMany(false, 0); assert list.size() == 12; assertIndices(table, 0, 12, 20); assert table.size() == 6 && table.getNumMissing() == 2; table.purge(12); assertIndices(table, 12, 12, 20); assert table.size() == 6 && table.getNumMissing() == 2; }
public static void testResize() { Table<Integer> table = new Table<Integer>(3, 10, 0); assertCapacity(table.capacity(), table.getNumRows(), 10); addAndGet(table, 30); addAndGet(table, 35); assertCapacity(table.capacity(), table.getNumRows(), 10); addAndGet(table, 500); assertCapacity(table.capacity(), table.getNumRows(), 10); addAndGet(table, 515); assertCapacity(table.capacity(), table.getNumRows(), 10); }
public void testResizeWithPurge() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 100; i++) addAndGet(table, i); System.out.println("table: " + table); // now remove 60 messages for (int i = 1; i <= 60; i++) { Integer num = table.remove(); assert num != null && num == i; } System.out.println("table after removal of seqno 60: " + table); table.purge(50); System.out.println("now triggering a resize() by addition of seqno=120"); addAndGet(table, 120); }
public void testGetList() { final Table<Integer> buf = new Table<Integer>(3, 10, 0); for (int i : Arrays.asList(1, 2, 3, 4, 5)) buf.add(i, i); List<Integer> elements = buf.get(3, 5); System.out.println("elements = " + elements); assert elements != null && elements.size() == 3; assert elements.contains(3) && elements.contains(4) && elements.contains(5); elements = buf.get(4, 10); System.out.println("elements = " + elements); assert elements != null && elements.size() == 2; assert elements.contains(4) && elements.contains(5); elements = buf.get(10, 20); assert elements == null; }