public static void testComputeSize() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int num : Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) table.add(num, num); System.out.println("table = " + table); assert table.computeSize() == 10; table.removeMany(false, 3); System.out.println("table = " + table); assert table.computeSize() == 7; table.removeMany(true, 4); System.out.println("table = " + table); assert table.computeSize() == table.size(); assert table.computeSize() == 3; }
public void testGetHighestDeliverable() { Table<Integer> table = new Table<Integer>(3, 10, 0); System.out.println("table = " + table); long highest_deliverable = table.getHighestDeliverable(), hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 0; assert highest_deliverable == 0; for (int num : Arrays.asList(1, 2, 3, 4, 5, 6, 8)) table.add(num, num); System.out.println("table = " + table); highest_deliverable = table.getHighestDeliverable(); hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 0; assert highest_deliverable == 6; table.removeMany(true, 4); System.out.println("table = " + table); highest_deliverable = table.getHighestDeliverable(); hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 4; assert highest_deliverable == 6; table.removeMany(true, 100); System.out.println("table = " + table); highest_deliverable = table.getHighestDeliverable(); hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 6; assert highest_deliverable == 6; table.add(7, 7); System.out.println("table = " + table); highest_deliverable = table.getHighestDeliverable(); hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 6; assert highest_deliverable == 8; table.removeMany(true, 100); System.out.println("table = " + table); highest_deliverable = table.getHighestDeliverable(); hd = table.getHighestDelivered(); System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable); assert hd == 8; assert highest_deliverable == 8; }
public void testResizeWithPurge2() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 50; i++) addAndGet(table, i); System.out.println("table = " + table); assert table.size() == 50; assertCapacity(table.capacity(), table.getNumRows(), 10); assertIndices(table, 0, 0, 50); table.removeMany(false, 43); System.out.println("table = " + table); assertIndices(table, 0, 43, 50); table.purge(43); System.out.println("table = " + table); assertIndices(table, 43, 43, 50); addAndGet(table, 52); assert table.get(43) == null; for (long i = 44; i <= 50; i++) { Integer num = table.get(i); assert num != null && num == i; } assert table.get(50) != null; assert table.get(51) == null; Integer num = table.get(52); assert num != null && num == 52; assert table.get(53) == null; }
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 static void testMove() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i < 50; i++) addAndGet(table, i); table.removeMany(true, 49); assert table.isEmpty(); addAndGet(table, 50); assert table.size() == 1; assertCapacity(table.capacity(), table.getNumRows(), 10); }
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 testRemoveMany2() { Table<Integer> buf = new Table<Integer>(3, 10, 0); for (int i : Arrays.asList(1, 2, 3, 4, 5, 6, 7, 9, 10)) buf.add(i, i); List<Integer> list = buf.removeMany(false, 3); System.out.println("list = " + list); assert list != null && list.size() == 3; list = buf.removeMany(false, 0); System.out.println("list = " + list); assert list != null && list.size() == 4; list = buf.removeMany(false, 10); assert list == null; buf.add(8, 8); list = buf.removeMany(false, 0); System.out.println("list = " + list); assert list != null && list.size() == 3; }
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); }
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 testAddWithWrapAroundAndRemoveMany() { Table<Integer> buf = new Table<Integer>(3, 10, 5); for (int i = 6; i <= 15; i++) assert buf.add(i, i) : "addition of seqno " + i + " failed"; System.out.println("buf = " + buf); List<Integer> removed = buf.removeMany(true, 3); System.out.println("removed " + removed); System.out.println("buf = " + buf); for (int i : removed) assert buf._get(i) == null; assertIndices(buf, 8, 8, 15); for (int i = 16; i <= 18; i++) assert buf.add(i, i); System.out.println("buf = " + buf); removed = buf.removeMany(true, 0); System.out.println("buf = " + buf); System.out.println("removed = " + removed); assert removed.size() == 10; for (int i : removed) assert buf._get(i) == null; assert buf.isEmpty(); assert buf.getNumMissing() == 0; assertIndices(buf, 18, 18, 18); }
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; }
/** * Creates a table and fills it to capacity. Then starts a number of adder threads, each trying to * add a seqno, blocking until there is more space. Each adder will block until the remover * removes elements, so the adder threads get unblocked and can then add their elements to the * buffer. */ public void testConcurrentAddAndRemove() throws Exception { final int NUM = 5; final Table<Integer> buf = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 10; i++) buf.add(i, i); // fill the buffer, add() will block now CountDownLatch latch = new CountDownLatch(1); Adder[] adders = new Adder[NUM]; for (int i = 0; i < adders.length; i++) { adders[i] = new Adder(latch, i + 11, buf); adders[i].start(); } System.out.println("releasing threads"); latch.countDown(); System.out.print("waiting for threads to be done: "); Thread remover = new Thread("Remover") { public void run() { Util.sleep(2000); List<Integer> list = buf.removeMany(true, 5); System.out.println("\nremover: removed = " + list); } }; remover.start(); for (Adder adder : adders) { try { adder.join(); } catch (InterruptedException e) { e.printStackTrace(); } } remover.join(); System.out.println("OK"); System.out.println("buf = " + buf); assert buf.size() == 10; assertIndices(buf, 5, 5, 15); List<Integer> list = buf.removeMany(true, 0); System.out.println("removed = " + list); assert list.size() == 10; for (int i = 6; i <= 15; i++) assert list.contains(i); assertIndices(buf, 15, 15, 15); }
public void testCompact() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 80; i++) addAndGet(table, i); assert table.size() == 80; assertIndices(table, 0, 0, 80); List<Integer> list = table.removeMany(false, 60); assert list.size() == 60; assert list.get(0) == 1 && list.get(list.size() - 1) == 60; assertIndices(table, 0, 60, 80); table.purge(60); assertIndices(table, 60, 60, 80); assert table.size() == 20; table.compact(); assertIndices(table, 60, 60, 80); assert table.size() == 20; assertCapacity(table.capacity(), table.getNumRows(), 10); }
public static void testRemoveManyWithFilterAcceptNone() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 10; i++) table.add(i, i); List<Integer> list = table.removeMany( null, true, 0, new Filter<Integer>() { public boolean accept(Integer element) { return false; } }); System.out.println("list = " + list); System.out.println("table = " + table); assert list == null; assert table.isEmpty(); }
/** * 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); } }
public static void testRemoveManyWithFilter() { Table<Integer> table = new Table<Integer>(3, 10, 0); for (int i = 1; i <= 10; i++) table.add(i, i); List<Integer> list = table.removeMany( null, true, 0, new Filter<Integer>() { public boolean accept(Integer element) { return element % 2 == 0; } }); System.out.println("list = " + list); System.out.println("table = " + table); assert list.size() == 5; assert table.isEmpty(); for (Integer num : Arrays.asList(2, 4, 6, 8, 10)) assert list.contains(num); }
public void testPurge5() { 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(false, 0); table.purge(10); for (int i = 1; i <= 10; i++) assert table._get(i) == null; for (int i = 11; i <= 100; i++) assert table.get(i) == i; table.purge(10); for (int i = 11; i <= 100; i++) assert table.get(i) == i; table.purge(50); for (int i = 1; i <= 50; i++) assert table._get(i) == null; for (int i = 51; i <= 100; i++) assert table.get(i) == i; table.purge(100); for (int i = 51; i <= 100; i++) assert table._get(i) == null; }
public void testAddListWithConstValue() { Table<Integer> buf = new Table<Integer>(3, 10, 0); List<Tuple<Long, Integer>> msgs = createList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); final Integer DUMMY = 0; boolean rc = buf.add(msgs, false, DUMMY); System.out.println("buf = " + buf); assert rc; assert buf.size() == 10; List<Integer> list = buf.removeMany( null, true, 0, new Filter<Integer>() { public boolean accept(Integer element) { return element.hashCode() == DUMMY.hashCode(); } }); System.out.println("list = " + list); assert list.size() == 10; for (int num : list) assert num == DUMMY; }
/** * 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); } }