package org.jgroups.tests;
import org.jgroups.Address;
import org.jgroups.Message;
import org.jgroups.PhysicalAddress;
import org.jgroups.protocols.Bundler;
import org.jgroups.protocols.RingBufferBundlerLockless2;
import org.jgroups.protocols.TP;
import org.jgroups.util.AsciiString;
import org.jgroups.util.DefaultThreadFactory;
import org.jgroups.util.Util;
import org.testng.annotations.Test;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Stream;
/**
* @author Bela Ban
* @since 4.0
*/
@Test
public class RingBundlerTestLockless2 {
protected static final Address a=Util.createRandomAddress("A"), b=Util.createRandomAddress("B"),
c=Util.createRandomAddress("C"), d=Util.createRandomAddress("D");
public void testSimpleSend() throws Exception {
RingBufferBundlerLockless2 bundler=new RingBufferBundlerLockless2(16);
RingBundlerTest.MockTransport transport=new RingBundlerTest.MockTransport();
bundler.init(transport);
final CountDownLatch latch=new CountDownLatch(1);
Sender[] senders=new Sender[20];
for(int i=0; i < senders.length; i++) {
senders[i]=new Sender(latch, bundler);
senders[i].start();
}
latch.countDown();
for(Sender sender: senders)
sender.join();
System.out.println("bundler = " + bundler);
bundler._readMessages();
System.out.println("bundler = " + bundler);
}
public void testSendToMultipleDestinations() throws Exception {
RingBufferBundlerLockless2 bundler=new RingBufferBundlerLockless2(16);
RingBundlerTest.MockTransport transport=new RingBundlerTest.MockTransport();
bundler.init(transport);
for(int i =0; i < 6; i++)
bundler.send(new Message(null));
int cnt=bundler.size();
assert cnt == 6;
bundler._readMessages();
System.out.println("bundler = " + bundler);
assert bundler.readIndex() == 6;
assert bundler.writeIndex() == 7;
assert bundler.size() == 0;
assert transport.map.get(null) == 1;
transport.map.clear();
for(Message msg: create(10000, null, a,a,a,b,c,d,d,a, null, null, a))
bundler.send(msg);
System.out.println("bundler = " + bundler);
cnt=bundler.size();
assert cnt == 12;
assert bundler.readIndex() == 6;
assert bundler.writeIndex() == 3;
bundler._readMessages();
assert bundler.readIndex() == 2;
assert bundler.writeIndex() == 3;
assert bundler.size() == 0;
Stream.of(null, a, b, c, d).forEach(msg -> {assert transport.map.get(msg) == 1;});
}
public void testSendWithNULL_MSG() throws Exception {
RingBufferBundlerLockless2 bundler=new RingBufferBundlerLockless2(16);
RingBundlerTest.MockTransport transport=new RingBundlerTest.MockTransport();
bundler.init(transport);
Message[] buf=(Message[])Util.getField(Util.getField(RingBufferBundlerLockless2.class, "buf"), bundler);
Field write_index_field=Util.getField(RingBufferBundlerLockless2.class, "write_index");
write_index_field.setAccessible(true);
buf[1]=buf[2]=RingBufferBundlerLockless2.NULL_MSG;
buf[3]=null;
write_index_field.set(bundler, 4);
System.out.println("bundler = " + bundler);
assert bundler.size() == 3;
bundler._readMessages();
System.out.println("bundler = " + bundler);
assert bundler.writeIndex() == 4;
assert bundler.readIndex() == 2;
assert bundler.size() == 1;
buf[3]=new Message(null);
bundler._readMessages();
assert bundler.readIndex() == 3;
assert bundler.size() == 0;
}
protected List<Message> create(int msg_size, Address ... destinations) {
List<Message> list=new ArrayList<>(destinations.length);
for(Address dest: destinations)
list.add(new Message(dest, new byte[msg_size]));
return list;
}
protected static class Sender extends Thread {
protected final CountDownLatch latch;
protected final Bundler bundler;
public Sender(CountDownLatch latch, Bundler bundler) {
this.latch=latch;
this.bundler=bundler;
}
public void run() {
try {
latch.await();
}
catch(InterruptedException e) {
e.printStackTrace();
}
try {
bundler.send(new Message(a));
}
catch(Exception e) {
e.printStackTrace();
}
}
}
protected static class MockTransport extends TP {
protected final Map<Address,Integer> map=new HashMap<>();
public MockTransport() {
this.cluster_name=new AsciiString("mock");
thread_factory=new DefaultThreadFactory("", false);
}
public boolean supportsMulticasting() {
return false;
}
public void sendMulticast(byte[] data, int offset, int length) throws Exception {
incrCount(null);
}
protected void sendToSingleMember(Address dest, byte[] buf, int offset, int length) throws Exception {
incrCount(dest);
}
public void sendUnicast(PhysicalAddress dest, byte[] data, int offset, int length) throws Exception {
}
public String getInfo() {
return null;
}
protected PhysicalAddress getPhysicalAddress() {
return null;
}
protected void incrCount(Address dest) {
Integer count=map.get(dest);
if(count == null)
map.put(dest, 1);
else
map.put(dest, count+1);
}
}
}