org.jgroups.protocols.RemoveQueueBundler Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
package org.jgroups.protocols;
import org.jgroups.Address;
import org.jgroups.Message;
import org.jgroups.annotations.Experimental;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.util.AverageMinMax;
import org.jgroups.util.DefaultThreadFactory;
import org.jgroups.util.RingBuffer;
import org.jgroups.util.Runner;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Bundler implementation which sends message batches (or single messages) as soon as the remove queue is full
* (or max_bundler_size would be exceeded).
* Messages are removed from the main queue and processed as follows (assuming they all fit into the remove queue):
* A B B C C A causes the following sends: {AA} -> {CC} -> {BB}
* Note that null is also a valid destination (send-to-all).
* Contrary to {@link TransferQueueBundler}, this bundler uses a {@link RingBuffer} rather than an ArrayBlockingQueue
* and the size of the remove queue is fixed. TransferQueueBundler increases the size of the remove queue
* dynamically, which leads to higher latency if the remove queue grows too much.
*
* JIRA: https://issues.jboss.org/browse/JGRP-2171
* @author Bela Ban
* @since 4.0.4
*/
@Experimental
public class RemoveQueueBundler extends BaseBundler {
protected RingBuffer rb;
protected Runner runner;
protected Message[] remove_queue;
protected final AverageMinMax avg_batch_size=new AverageMinMax();
protected int queue_size=1024;
@ManagedAttribute(description="Remove queue size")
public int rqbRemoveQueueSize() {return remove_queue.length;}
@ManagedAttribute(description="Sets the size of the remove queue; creates a new remove queue")
public void rqbRemoveQueueSize(int size) {
if(size == queue_size) return;
queue_size=size;
remove_queue=new Message[queue_size];
}
@ManagedAttribute(description="Average batch length")
public String rqbAvgBatchSize() {return avg_batch_size.toString();}
@ManagedAttribute(description="Current number of messages (to be sent) in the ring buffer")
public int rqbRingBufferSize() {return rb.size();}
public Map getStats() {
Map map=new HashMap<>();
map.put("avg-batch-size", avg_batch_size.toString());
map.put("ring-buffer-size", rb.size());
map.put("remove-queue-size", queue_size);
return map;
}
public void resetStats() {
avg_batch_size.clear();
}
public void init(TP transport) {
super.init(transport);
rb=new RingBuffer(Message.class, transport.getBundlerCapacity());
remove_queue=new Message[queue_size];
runner=new Runner(new DefaultThreadFactory("aqb", true, true), "runner", this::run, null);
}
public synchronized void start() {
super.start();
runner.start();
}
public synchronized void stop() {
runner.stop();
super.stop();
}
public void send(Message msg) throws Exception {
rb.put(msg);
}
public void run() {
try {
int drained=rb.drainToBlocking(remove_queue);
if(drained == 1) {
output.position(0);
sendSingleMessage(remove_queue[0]);
return;
}
for(int i=0; i < drained; i++) {
Message msg=remove_queue[i];
long size=msg.size();
if(count + size >= transport.getMaxBundleSize())
sendBundledMessages();
addMessage(msg, msg.size());
}
sendBundledMessages();
}
catch(Throwable t) {
}
}
public int getQueueSize() {
return rb.size();
}
public int size() {
return rb.size();
}
protected void sendMessageList(Address dest, Address src, List list) {
super.sendMessageList(dest, src, list);
avg_batch_size.add(list.size());
}
}