package org.jgroups.tests;
import org.jgroups.Global;
import org.jgroups.Message;
import org.jgroups.util.*;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.IntStream;
/** Tests {@link org.jgroups.util.Table<Integer>}
* @author Bela Ban
*/
@Test(groups=Global.FUNCTIONAL)
public class TableTest {
protected static final Predicate<Message> dont_loopback_filter=msg -> msg != null && msg.isTransientFlagSet(Message.TransientFlag.DONT_LOOPBACK);
public static void testCreation() {
Table<Integer> table=new Table<>(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 void testAdd() {
Table<Integer> buf=new Table<>(3, 10, 0);
buf.add(1, 322649);
buf.add(2, 100000);
System.out.println("buf = " + buf);
assert buf.size() == 2;
}
public void testAddList() {
Table<Integer> buf=new Table<>(3, 10, 0);
List<LongTuple<Integer>> msgs=createList(1, 2);
boolean rc=buf.add(msgs);
System.out.println("buf = " + buf);
assert rc;
assert buf.size() == 2;
}
public void testAddListWithConstValue() {
Table<Integer> buf=new Table<>(3, 10, 0);
List<LongTuple<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(true, 0, element -> element.hashCode() == DUMMY.hashCode());
System.out.println("list = " + list);
assert list.size() == 10;
for(int num: list)
assert num == DUMMY;
}
public void testAddListWithRemoval() {
Table<Integer> buf=new Table<>(3, 10, 0);
List<LongTuple<Integer>> msgs=createList(1,2,3,4,5,6,7,8,9,10);
int size=msgs.size();
boolean added=buf.add(msgs);
System.out.println("buf = " + buf);
assert added;
assert msgs.size() == size;
msgs=createList(1,3,5,7);
size=msgs.size();
added=buf.add(msgs, true);
System.out.println("buf = " + buf);
assert !added;
assert msgs.isEmpty();
msgs=createList(1,3,5,7,9,10,11,12,13,14,15);
size=msgs.size();
added=buf.add(msgs, true);
System.out.println("buf = " + buf);
assert added;
assert msgs.size() == 5;
}
public void testAddition() {
Table<Integer> table=new Table<>(3, 10, 0);
assert !table.add(0, 0);
addAndGet(table, 1,5,9,10,11,19,20,29);
System.out.println("table: " + table.dump());
assert table.size() == 8;
int size=table.computeSize();
assert size == 8;
assert table.size() == table.computeSize();
assertCapacity(table.capacity(), 3, 10);
assertIndices(table, 0, 0, 29);
}
public static void testAdditionList() {
Table<Integer> table=new Table<>(3, 10, 0);
List<LongTuple<Integer>> msgs=createList(0);
assert !table.add(msgs);
long[] seqnos={1,5,9,10,11,19,20,29};
msgs=createList(seqnos);
assert table.add(msgs);
System.out.println("table: " + table.dump());
for(long seqno: seqnos)
assert table.get(seqno) == seqno;
assert table.size() == 8;
int size=table.computeSize();
assert size == 8;
assert table.size() == table.computeSize();
assertCapacity(table.capacity(), 3, 10);
assertIndices(table, 0, 0, 29);
}
public static void testAdditionWithOffset() {
Table<Integer> table=new Table<>(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);
}
public void testAdditionListWithOffset() {
Table<Integer> table=new Table<>(3, 10, 100);
long seqnos[]={101,105,109,110,111,119,120,129};
List<LongTuple<Integer>> msgs=createList(seqnos);
System.out.println("table: " + table.dump());
assert table.add(msgs);
assert table.size() == 8;
for(long seqno: seqnos)
assert table.get(seqno) == seqno;
assertCapacity(table.capacity(), 3, 10);
assertIndices(table, 100, 100, 129);
}
public static void testAddListWithResizing() {
Table<Integer> table=new Table<>(3, 5, 0);
List<LongTuple<Integer>> msgs=new ArrayList<>();
for(int i=1; i < 100; i++)
msgs.add(new LongTuple<>((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 == 1 : "number of resizings=" + num_resizes + " (expected 1)";
}
public static void testAddListWithResizingNegativeSeqnos() {
long seqno=Long.MAX_VALUE-50;
Table<Integer> table=new Table<>(3, 5, seqno);
List<LongTuple<Integer>> msgs=new ArrayList<>();
for(int i=1; i < 100; i++)
msgs.add(new LongTuple<>((long)i+seqno,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 == 1 : "number of resizings=" + num_resizes + " (expected 1)";
}
public static void testAddListWithResizing2() {
Table<Integer> table=new Table<>(3, 500, 0);
List<LongTuple<Integer>> msgs=new ArrayList<>();
for(int i=1; i < 100; i++)
msgs.add(new LongTuple<>((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)";
}
public static void testAdditionWithOffset2() {
Table<Integer> table=new Table<>(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 testAddWithWrapAround() {
Table<Integer> buf=new Table<>(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);
for(int i=0; i < 3; i++) {
Integer val=buf.remove(false);
System.out.println("removed " + val);
assert val != null;
}
System.out.println("buf = " + buf);
long low=buf.getLow();
buf.purge(8);
System.out.println("buf = " + buf);
assert buf.getLow() == 8;
for(long i=low; i <= 8; i++)
assert buf._get(i) == null : "message with seqno=" + i + " is not null";
for(int i=16; i <= 18; i++)
assert buf.add(i, i);
System.out.println("buf = " + buf);
while(buf.remove(false) != null)
;
System.out.println("buf = " + buf);
assert buf.isEmpty();
assert buf.getNumMissing() == 0;
low=buf.getLow();
buf.purge(18);
assert buf.getLow() == 18;
for(long i=low; i <= 18; i++)
assert buf._get(i) == null : "message with seqno=" + i + " is not null";
}
public void testAddWithWrapAroundAndRemoveMany() {
Table<Integer> buf=new Table<>(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 void testAddMissing() {
Table<Integer> buf=new Table<>(3, 10, 0);
for(int i: Arrays.asList(1,2,4,5,6))
buf.add(i, i);
System.out.println("buf = " + buf);
assert buf.size() == 5 && buf.getNumMissing() == 1;
Integer num=buf.remove();
assert num == 1;
num=buf.remove();
assert num == 2;
num=buf.remove();
assert num == null;
buf.add(3, 3);
System.out.println("buf = " + buf);
assert buf.size() == 4 && buf.getNumMissing() == 0;
for(int i=3; i <= 6; i++) {
num=buf.remove();
System.out.println("buf = " + buf);
assert num == i;
}
num=buf.remove();
assert num == null;
}
public static void testDuplicateAddition() {
Table<Integer> table=new Table<>(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 void testAddWithInvalidSeqno() {
Table<Integer> buf=new Table<>(3, 10, 20);
boolean success=buf.add(10, 0);
assert !success;
success=buf.add(20, 0);
assert !success;
assert buf.isEmpty();
}
/**
* 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<>(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;
}
/**
* 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<>(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 testAddAndRemove() {
Table<Message> table=new Table<>(3, 10, 0);
table.add(1, msg(1));
table.add(2, msg(2));
assert table.getHighestDeliverable() == 2;
table.removeMany(true, 10);
assert table.getHighestDelivered() == 2;
table.add(3, msg(3));
assert table.getHighestReceived() == 3;
table.add(4, msg(4, true), dont_loopback_filter);
assert table.getHighestDelivered() == 2;
assert table.getHighestDeliverable() == 4;
table.removeMany(false, 10);
assert table.getHighestDelivered() == 4;
table.add(5, msg(5, true),dont_loopback_filter);
table.add(6, msg(6, true), dont_loopback_filter);
assert table.getHighestDelivered() == 6;
}
public void testAddAndRemove2() {
Table<Message> table=new Table<>(3, 10, 0);
for(int i=1; i <=10; i++)
table.add(i, msg(i, true), dont_loopback_filter);
assert table.getHighestDelivered() == 10;
assert table.getHighestReceived() == 10;
assert table.getHighestDeliverable() == 10;
table.purge(10);
assert table.getHighestDelivered() == 10;
assert table.getHighestReceived() == 10;
assert table.getHighestDeliverable() == 10;
assert table.getLow() == 10;
}
public void testAddAndRemove3() {
Table<Message> table=new Table<>(3, 10, 3);
table.add(5, msg(5, true), dont_loopback_filter);
table.add(6, msg(6, true), dont_loopback_filter);
table.add(4, msg(4, true), dont_loopback_filter);
assert table.getHighestReceived() == 6;
assert table.getHighestDeliverable() == 6;
assert table.getHighestDelivered() == 6;
}
public void testAddAndRemove4() {
Table<Message> table=new Table<>(3, 10, 3);
table.add(7, msg(7, true), dont_loopback_filter);
table.add(6, msg(6, true), dont_loopback_filter);
table.add(4, msg(4, true), dont_loopback_filter);
assert table.getHighestReceived() == 7;
assert table.getHighestDeliverable() == 4;
assert table.getHighestDelivered() == 4;
}
public void testIndex() {
Table<Integer> buf=new Table<>(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";
}
public void testIndexWithRemoveMany() {
Table<Integer> buf=new Table<>(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 testComputeSize() {
Table<Integer> table=new Table<>(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 static void testComputeSize2() {
Table<Integer> table=new Table<>(3, 10, 0);
table.add(1, 1);
System.out.println("table = " + table);
assert table.computeSize() == table.size();
assert table.computeSize() == 1;
table.remove(false);
System.out.println("table = " + table);
assert table.computeSize() == table.size();
assert table.computeSize() == 0;
}
public static void testRemove() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 9; i++)
table.add(i,i);
table.add(20, 20);
System.out.println("table = " + table);
assert table.size() == 10;
assertIndices(table, 0, 0, 20);
int num_null_msgs=table.getNumMissing();
System.out.println("num_null_msgs = " + num_null_msgs);
assert num_null_msgs == 10;
for(long i=1; i <= 10; i++) // 10 is missing
table.remove();
System.out.println("table = " + table);
assert table.size() == 1;
assertIndices(table, 9, 9, 20);
num_null_msgs=table.getNumMissing();
System.out.println("num_null_msgs = " + num_null_msgs);
assert num_null_msgs == 10;
}
public void testRemove2() {
final Table<Integer> buf=new Table<>(3, 10, 0);
for(int i: Arrays.asList(1,2,3,4,5))
buf.add(i, i);
System.out.println("buf = " + buf);
assertIndices(buf, 0, 0, 5);
Integer el=buf.remove(true);
System.out.println("el = " + el);
assert el.equals(1);
el=buf.remove(false); // not encouraged ! nullify should always be true or false
System.out.println("el = " + el);
assert el.equals(2);
el=buf.remove(true);
System.out.println("el = " + el);
assert el.equals(3);
}
public static void testRemoveMany() {
Table<Integer> table=new Table<>(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 testRemoveMany2() {
Table<Integer> buf=new Table<>(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 void testRemoveManyWithNulling() {
Table<Integer> buf=new Table<>(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(true, 3);
System.out.println("list = " + list);
assert list != null && list.size() == 3;
for(int i: list)
assert buf._get(i) == null;
list=buf.removeMany(true, 0);
System.out.println("list = " + list);
assert list != null && list.size() == 4;
for(int i: list)
assert buf._get(i) == null;
list=buf.removeMany(false, 10);
assert list == null;
buf.add(8, 8);
list=buf.removeMany(true, 0);
System.out.println("list = " + list);
assert list != null && list.size() == 3;
for(int i: list)
assert buf._get(i) == null;
}
public static void testRemoveManyWithWrapping() {
Table<Integer> table=new Table<>(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(true, 0);
assert list.size() == 12;
assertIndices(table, 12, 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 testRemoveManyWithWrapping2() {
Table<Integer> table=new Table<>(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 testRemoveManyWithFilter() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, i);
List<Integer> list=table.removeMany(true, 0, element -> 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 static void testRemoveManyWithFilterAcceptAll() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, i);
List<Integer> list=table.removeMany(true, 0, element -> true);
System.out.println("list = " + list);
System.out.println("table = " + table);
assert list.size() == 10;
assert table.isEmpty();
}
public static void testRemoveManyWithFilterAcceptNone() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, i);
List<Integer> list=table.removeMany(true, 0, element -> false);
System.out.println("list = " + list);
System.out.println("table = " + table);
assert list == null;
assert table.isEmpty();
}
public static void testRemoveManyWithFilterAcceptNone2() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, i);
List<Integer> list=table.removeMany(true, 3, new Predicate<Integer>() {
int cnt=0;
public boolean test(Integer element) {return ++cnt <= 2;}});
System.out.println("list = " + list);
System.out.println("table = " + table);
assert list.size() == 2;
assert table.isEmpty();
}
public void testRemoveMany3() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, i);
List<Integer> result=table.removeMany(true, 0, null, ArrayList::new, ArrayList::add);
assert result != null && result.size() == 10;
assert table.isEmpty();
}
public void testRemoveManyIntoMessageBatch() {
Table<Message> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i, new Message(null, "hello"));
MessageBatch batch=new MessageBatch(table.size());
Supplier<MessageBatch> batch_creator=() -> batch;
BiConsumer<MessageBatch,Message> accumulator=MessageBatch::add;
MessageBatch result=table.removeMany(true, 0, null, batch_creator, accumulator);
assert !batch.isEmpty();
assert table.isEmpty();
assert batch.size() == 10;
assert result != null && result == batch;
IntStream.rangeClosed(11,15).forEach(seqno -> table.add(seqno, new Message(null, "test")));
batch.reset();
result=table.removeMany(true, 0, null, batch_creator, accumulator);
assert !batch.isEmpty();
assert table.isEmpty();
assert batch.size() == 5;
assert result != null && result == batch;
result=table.removeMany( true, 0, null, batch_creator, accumulator);
assert result == null;
}
public void testForEach() {
class MyVisitor<T> implements Table.Visitor<T> {
List<int[]> list=new ArrayList<>(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<>();
Table<Integer> table=new Table<>(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 testIteration() {
final Table<Integer> table=new Table<>(1, 10, 0);
List<Integer> list=new ArrayList<>(20);
IntStream.rangeClosed(1, 20).forEach(i -> {list.add(i); table.add(i,i);});
List<Integer> list2=new ArrayList<>();
for(Integer i: table)
list2.add(i);
System.out.println("list = " + list);
System.out.println("list2 = " + list2);
assert list2.equals(list);
}
public void testStream() {
final Table<Integer> table=new Table<>(1, 10, 0);
List<Integer> list=new ArrayList<>(20);
IntStream.rangeClosed(1, 20).forEach(i -> {list.add(i); table.add(i,i);});
List<Integer> list2=table.stream().collect(ArrayList::new, ArrayList::add, (l,el) -> {});
System.out.println("list = " + list);
System.out.println("list2 = " + list2);
assert list2.equals(list);
}
public void testGet() {
final Table<Integer> buf=new Table<>(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 testGetNullMessages() {
Table<Integer> table=new Table<>(3, 10, 0);
table.add(1, 1);
table.add(100, 100);
System.out.println("table = " + table);
int num_null_elements=table.getNumMissing();
assert num_null_elements == 98; // [2 .. 99]
table.add(50,50);
System.out.println("table = " + table);
assert table.size() == 3;
assert table.getNumMissing() == 97;
}
public static void testGetNullMessages2() {
Table<Integer> table=new Table<>(1, 10, 0);
table.add(1, 1);
table.add(5, 5);
System.out.println("table = " + table);
int num_null_elements=table.getNumMissing();
assert num_null_elements == 3; // [2 .. 4]
table.add(10,10);
System.out.println("table = " + table);
assert table.size() == 3;
assert table.getNumMissing() == 7;
table.add(14,14);
System.out.println("table = " + table);
assert table.size() == 4;
assert table.getNumMissing() == 10;
while(table.remove() != null)
;
System.out.println("table = " + table);
assert table.size() == 3;
assert table.getNumMissing() == 10;
}
public static void testGetMissing() {
Table<Integer> table=new Table<>(3, 10, 0);
SeqnoList missing=table.getMissing();
assert missing == null;
for(int num: Arrays.asList(2,4,6,8))
table.add(num, num);
System.out.println("table = " + table);
missing=table.getMissing();
System.out.println("missing=" + missing);
assert missing.size() == 4;
assert table.getNumMissing() == 4;
}
public static void testGetMissingWithOffset() {
Table<Integer> table=new Table<>(3, 10, 300000);
SeqnoList missing=table.getMissing();
assert missing == null;
for(int num: Arrays.asList(300002,300004,300006,300008))
table.add(num, num);
System.out.println("table = " + table);
missing=table.getMissing();
System.out.println("missing=" + missing);
assert missing.size() == 4;
assert table.getNumMissing() == 4;
table.add(300001,300001);
table.removeMany(true, 2);
missing=table.getMissing();
System.out.println("missing=" + missing);
assert missing.size() == 3;
assert table.getNumMissing() == 3;
}
public static void testGetMissing2() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int num: Arrays.asList(3,4,5))
table.add(num, num);
System.out.println("table = " + table);
SeqnoList missing=table.getMissing();
System.out.println("missing=" + missing);
assert missing.size() == 2; // the range [1-2]
assert table.getNumMissing() == 2;
}
public static void testGetMissing3() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int num: Collections.singletonList(8))
table.add(num, num);
System.out.println("table = " + table);
SeqnoList missing=table.getMissing();
System.out.println("missing=" + missing);
assert missing.size() == 7;
assert table.getNumMissing() == 7;
}
public void testGetMissing4() {
Table<Integer> buf=new Table<>(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;
}
public void testGetMissing5() {
Table<Integer> buf=new Table<>(3, 10, 0);
buf.add(1,1);
SeqnoList missing=buf.getMissing();
System.out.println("missing = " + missing);
assert missing == null && buf.getNumMissing() == 0;
buf=new Table<>(3, 10, 0);
buf.add(10,10);
missing=buf.getMissing();
System.out.println("missing = " + missing);
assert buf.getNumMissing() == missing.size();
buf=new Table<>(3, 10, 0);
buf.add(5,5);
missing=buf.getMissing();
System.out.println("missing = " + missing);
assert buf.getNumMissing() == missing.size();
buf=new Table<>(3, 10, 0);
buf.add(5,5); buf.add(7,7);
missing=buf.getMissing();
System.out.println("missing = " + missing);
assert missing.size() == 5;
assert buf.getNumMissing() == missing.size();
}
public void testGetMissingWithMaxSize() {
Table<Integer> buf=new Table<>(3, 10, 0);
for(int i=1; i <= 50; i++) {
if(i % 2 == 0)
buf.add(i,i);
}
assert buf.getNumMissing() == 25;
SeqnoList missing=buf.getMissing();
assert missing.size() == 25;
missing=buf.getMissing(10);
assert missing.size() == 10;
}
public static void testGetMissingLast() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int num: Arrays.asList(1,2,3,4,5,6,8))
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 testGetMissingFirst() {
Table<Integer> table=new Table<>(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 void testGetHighestDeliverable() {
Table<Integer> table=new Table<>(3, 10, 0);
System.out.println("table = " + table);
long highest_deliverable=table.getHighestDeliverable(), hd=table.getHighestDelivered();
int num_deliverable=table.getNumDeliverable();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 0;
assert highest_deliverable == 0;
assert num_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();
num_deliverable=table.getNumDeliverable();
hd=table.getHighestDelivered();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 0;
assert highest_deliverable == 6;
assert num_deliverable == 6;
table.removeMany(true, 4);
System.out.println("table = " + table);
highest_deliverable=table.getHighestDeliverable();
num_deliverable=table.getNumDeliverable();
hd=table.getHighestDelivered();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 4;
assert highest_deliverable == 6;
assert num_deliverable == 2;
table.removeMany(true, 100);
System.out.println("table = " + table);
highest_deliverable=table.getHighestDeliverable();
hd=table.getHighestDelivered();
num_deliverable=table.getNumDeliverable();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 6;
assert highest_deliverable == 6;
assert num_deliverable == 0;
table.add(7,7);
System.out.println("table = " + table);
highest_deliverable=table.getHighestDeliverable();
num_deliverable=table.getNumDeliverable();
hd=table.getHighestDelivered();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 6;
assert highest_deliverable == 8;
assert num_deliverable == 2;
table.removeMany(true, 100);
System.out.println("table = " + table);
highest_deliverable=table.getHighestDeliverable();
num_deliverable=table.getNumDeliverable();
hd=table.getHighestDelivered();
System.out.println("highest delivered=" + hd + ", highest deliverable=" + highest_deliverable);
assert hd == 8;
assert highest_deliverable == 8;
assert num_deliverable == 0;
}
public void testGetHighestDeliverable2() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i,i);
System.out.println("table = " + table);
table.removeMany(true, 20);
long highest_deliverable=table.getHighestDeliverable();
assert highest_deliverable == 10;
assert table.getHighestDelivered() == highest_deliverable;
}
public void testGetHighestDeliverable3() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 10; i++)
table.add(i,i);
System.out.println("table = " + table);
table.removeMany(true, 9);
long highest_deliverable=table.getHighestDeliverable();
assert highest_deliverable == 10;
}
public static void testMassAddition() {
Table<Integer> table=new Table<>(3, 10, 0);
final int NUM_ELEMENTS=10005;
for(int i=1; i <= NUM_ELEMENTS; i++)
table.add(i, i);
System.out.println("table = " + table);
assert table.size() == NUM_ELEMENTS;
assertCapacity(table.capacity(), table.getNumRows(), 10);
assertIndices(table, 0, 0, NUM_ELEMENTS);
assert table.getNumMissing() == 0;
}
public static void testResize() {
Table<Integer> table=new Table<>(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<>(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 testResizeWithPurgeAndGetOfNonExistingElement() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 50; i++)
addAndGet(table, i);
System.out.println("table: " + table);
assertIndices(table, 0, 0, 50);
assert table.size() == 50 && table.getNumMissing() == 0;
// now remove 15 messages
for(long i=1; i <= 15; i++) {
Integer num=table.remove(false);
assert num != null && num == i;
}
System.out.println("table after removal of seqno 15: " + table);
assertIndices(table, 0, 15, 50);
assert table.size() == 35 && table.getNumMissing() == 0;
table.purge(15);
System.out.println("now triggering a resize() by addition of seqno=55");
addAndGet(table, 55);
assertIndices(table, 15, 15, 55);
assert table.size() == 36 && table.getNumMissing() == 4;
// now we have elements 40-49 in row 1 and 55 in row 2:
List<Integer> list=new ArrayList<>(20);
for(int i=16; i < 50; i++)
list.add(i);
list.add(55);
for(long i=table.getOffset(); i < table.capacity() + table.getOffset(); i++) {
Integer num=table._get(i);
if(num != null) {
System.out.println("num=" + num);
list.remove(num);
}
}
System.out.println("table:\n" + table.dump());
assert list.isEmpty() : " list: " + Util.print(list);
}
public void testResizeWithPurge2() {
Table<Integer> table=new Table<>(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 testMove() {
Table<Integer> table=new Table<>(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 void testMove2() {
Table<Integer> table=new Table<>(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(35, 35); // 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 testMove3() {
Table<Integer> table=new Table<>(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 static void testPurge() {
Table<Integer> table=new Table<>(5, 10, 0);
for(int seqno=1; seqno <= 25; seqno++)
table.add(seqno, seqno);
int[] seqnos={30,31,32,37,38,39,40,41,42,47,48,49};
for(int seqno: seqnos)
table.add(seqno, seqno);
System.out.println("table (before remove):\n" + table.dump());
for(int seqno=1; seqno <= 22; seqno++)
table.remove(false);
System.out.println("\ntable (after remove 22, before purge):\n" + table.dump());
table.purge(22);
System.out.println("\ntable: (after purge 22):\n" + table.dump());
assert table.size() == 3 + seqnos.length;
assert table.computeSize() == table.size();
}
public void testPurge2() {
Table<Integer> buf=new Table<>(3, 10, 0);
for(int i=1; i <=7; i++) {
buf.add(i, i);
buf.remove(false);
}
System.out.println("buf = " + buf);
assert buf.isEmpty();
long low=buf.getLow();
buf.purge(3);
assert buf.getLow() == 3;
for(long i=low; i <= 3; i++)
assert buf._get(i) == null : "message with seqno=" + i + " is not null";
buf.purge(6);
assert buf._get(6) == null;
buf.purge(7);
assert buf._get(7) == null;
assert buf.getLow() == 7;
assert buf.isEmpty();
for(int i=7; i <= 14; i++) {
buf.add(i, i);
buf.remove(false);
}
System.out.println("buf = " + buf);
assert buf.isEmpty();
low=buf.getLow(); assert low == 7;
buf.purge(12);
System.out.println("buf = " + buf);
assert buf.getLow() == 12;
for(long i=low; i <= 12; i++)
assert buf._get(i) == null : "message with seqno=" + i + " is not null";
}
public void testPurge3() {
Table<Integer> table=new Table<>(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 testPurge4() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 100; i++)
table.add(i, i);
System.out.println("table = " + table);
table.removeMany(false, 53);
table.purge(53);
for(int i=54; i <= 100; i++)
assert table.get(i) == i;
}
public void testPurge5() {
Table<Integer> table=new Table<>(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 testPurgeForce() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 30; i++)
table.add(i, i);
System.out.println("table = " + table);
table.purge(15, true);
System.out.println("table = " + table);
assertIndices(table, 15, 15, 30);
for(int i=1; i <= 15; i++)
assert table._get(i) == null;
for(int i=16; i<= 30; i++)
assert table._get(i) != null;
assert table.get(5) == null && table.get(25) != null;
table.purge(30, true);
System.out.println("table = " + table);
assertIndices(table, 30, 30, 30);
assert table.isEmpty();
for(int i=1; i <= 30; i++)
assert table._get(i) == null;
for(int i=31; i <= 40; i++)
table.add(i, i);
System.out.println("table = " + table);
assert table.size() == 10;
assertIndices(table, 30, 30, 40);
table.purge(50, true);
System.out.println("table = " + table);
assert table.isEmpty();
assertIndices(table, 40, 40, 40);
}
// Tests purge(40) followed by purge(20) - the second purge() should be ignored
// https://issues.jboss.org/browse/JGRP-1872
public void testPurgeLower() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 30; i++)
table.add(i, i);
System.out.println("table = " + table);
table.purge(20, true);
assertIndices(table, 20, 20, 30);
table.purge(15, true);
assertIndices(table, 20,20, 30);
table=new Table<>(3, 10, 0);
for(int i=1; i <= 30; i++)
table.add(i, i);
System.out.println("table = " + table);
table.purge(20, true);
assertIndices(table, 20, 20, 30);
table.purge(15, false);
assertIndices(table, 20, 20, 30);
}
public void testCompact() {
Table<Integer> table=new Table<>(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 void testCompact2() {
Table<Integer> table=new Table<>(3, 10, 0);
for(int i=1; i <= 80; i++)
addAndGet(table, i);
assert table.size() == 80;
for(long i=1; i <= 60; i++)
table.remove();
assert table.size() == 20;
table.compact();
assert table.size() == 20;
assertCapacity(table.capacity(), table.getNumRows(), 10);
}
@Test(groups=Global.FUNCTIONAL)
public void testSeqnoOverflow() {
_testSeqnoOverflow(Long.MAX_VALUE - 10, 20);
_testSeqnoOverflow(-10, 20);
}
protected void _testSeqnoOverflow(long seqno, final int delta) {
long orig_seqno=seqno;
Table<Message> win=new Table<>(3, 10, seqno);
for(int i=1; i <= delta; i++) {
Message msg=new Message(null, "hello");
win.add(++seqno, msg);
}
System.out.println("win = " + win);
assert win.size() == delta;
assertIndices(win, orig_seqno, orig_seqno, seqno);
List<Message> msgs=win.removeMany(true, 200, null);
System.out.printf("removed %d msgs\n", msgs.size());
assert win.isEmpty();
assertIndices(win, seqno, seqno, seqno);
}
protected Message msg(int num) {return new Message(null, num);}
protected Message msg(int num, boolean set_dont_loopback) {
Message msg=msg(num);
if(set_dont_loopback)
msg.setTransientFlag(Message.TransientFlag.DONT_LOOPBACK);
return msg;
}
protected static void assertCapacity(int actual_capacity, int num_rows, int elements_per_row) {
int actual_elements_per_row=Util.getNextHigherPowerOfTwo(elements_per_row);
int expected_capacity=num_rows * actual_elements_per_row;
assert actual_capacity == expected_capacity
: "expected capacity of " + expected_capacity + " but got " + actual_capacity;
}
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;
}
}
protected static List<LongTuple<Integer>> createList(long ... seqnos) {
if(seqnos == null)
return null;
List<LongTuple<Integer>> msgs=new ArrayList<>(seqnos.length);
for(long seqno: seqnos)
msgs.add(new LongTuple<>(seqno, (int)seqno));
return msgs;
}
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();
}
protected static class Adder extends Thread {
protected final CountDownLatch latch;
protected final int seqno;
protected final Table<Integer> buf;
public Adder(CountDownLatch latch, int seqno, Table<Integer> buf) {
this.latch=latch;
this.seqno=seqno;
this.buf=buf;
}
public void run() {
try {
latch.await();
Util.sleepRandom(10, 500);
buf.add(seqno, seqno);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}