org.jgroups.protocols.RemoveQueueBundler Maven / Gradle / Ivy
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 size() {
return rb.size();
}
protected void sendMessageList(Address dest, Address src, List list) {
super.sendMessageList(dest, src, list);
avg_batch_size.add(list.size());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy