org.jgroups.protocols.BaseBundler 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.View;
import org.jgroups.annotations.GuardedBy;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.Property;
import org.jgroups.conf.AttributeType;
import org.jgroups.logging.Log;
import org.jgroups.util.AverageMinMax;
import org.jgroups.util.ByteArrayDataOutputStream;
import org.jgroups.util.Util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import static org.jgroups.protocols.TP.MSG_OVERHEAD;
/**
* Implements storing of messages in a hashmap and sending of single messages and message batches. Most bundler
* implementations will want to extend this class
* @author Bela Ban
* @since 4.0
*/
public abstract class BaseBundler implements Bundler {
/** Keys are destinations, values are lists of Messages */
protected final Map> msgs=new HashMap<>(24);
protected TP transport;
protected final ReentrantLock lock=new ReentrantLock();
protected @GuardedBy("lock") long count; // current number of bytes accumulated
protected ByteArrayDataOutputStream output;
protected Log log;
/**
* Maximum number of bytes for messages to be queued until they are sent.
* This value needs to be smaller than the largest datagram packet size in case of UDP
*/
@Property(name="max_size", type=AttributeType.BYTES,
description="Maximum number of bytes for messages to be queued until they are sent")
protected int max_size=64000;
@Property(description="The max number of elements in a bundler if the bundler supports size limitations",
type=AttributeType.SCALAR)
protected int capacity=16384;
@ManagedAttribute(description="Time (us) to send the bundled messages")
protected final AverageMinMax avg_send_time=new AverageMinMax().unit(TimeUnit.MICROSECONDS);
public int getCapacity() {return capacity;}
public Bundler setCapacity(int c) {this.capacity=c; return this;}
public int getMaxSize() {return max_size;}
public Bundler setMaxSize(int s) {max_size=s; return this;}
public void init(TP transport) {
this.transport=transport;
log=transport.getLog();
output=new ByteArrayDataOutputStream(max_size + MSG_OVERHEAD);
}
public void resetStats() {
avg_send_time.clear();
}
public void start() {}
public void stop() {}
public void send(Message msg) throws Exception {}
public void viewChange(View view) {
// code removed (https://issues.redhat.com/browse/JGRP-2324)
}
/** Returns the total number of messages in the hashmap */
@ManagedAttribute(description="The number of unsent messages in the bundler")
public int size() {
lock.lock();
try {
return msgs.values().stream().map(List::size).reduce(0, Integer::sum);
}
finally {
lock.unlock();
}
}
@ManagedAttribute(description="Size of the queue (if available")
public int getQueueSize() {
return -1;
}
/**
* Sends all messages in the map. Messages for the same destination are bundled into a message list.
* The map will be cleared when done.
*/
@GuardedBy("lock") protected void sendBundledMessages() {
long start=System.nanoTime();
for(Map.Entry> entry: msgs.entrySet()) {
List list=entry.getValue();
if(list.isEmpty())
continue;
output.position(0);
if(list.size() == 1)
sendSingleMessage(list.get(0));
else {
Address dst=entry.getKey();
sendMessageList(dst, list.get(0).getSrc(), list);
if(transport.statsEnabled())
transport.getMessageStats().incrNumBatchesSent(1);
}
list.clear();
}
count=0;
long time_us=(System.nanoTime()-start) / 1_000;
avg_send_time.add(time_us);
}
protected void sendSingleMessage(final Message msg) {
Address dest=msg.getDest();
try {
Util.writeMessage(msg, output, dest == null);
transport.doSend(output.buffer(), 0, output.position(), dest);
if(transport.statsEnabled())
transport.getMessageStats().incrNumSingleMsgsSent(1);
}
catch(Throwable e) {
log.trace(Util.getMessage("SendFailure"),
transport.getAddress(), (dest == null? "cluster" : dest), msg.size(), e.toString(), msg.printHeaders());
}
}
protected void sendMessageList(final Address dest, final Address src, final List list) {
try {
Util.writeMessageList(dest, src, transport.cluster_name.chars(), list, output, dest == null, transport.getId());
transport.doSend(output.buffer(), 0, output.position(), dest);
}
catch(Throwable e) {
log.trace(Util.getMessage("FailureSendingMsgBundle"), transport.getAddress(), e);
}
}
@GuardedBy("lock") protected void addMessage(Message msg, int size) {
Address dest=msg.getDest();
List tmp=msgs.computeIfAbsent(dest, k -> new ArrayList<>(16));
tmp.add(msg);
count+=size;
}
}