If we use PerDestinationBundler with use_single_sender_thread=false, we could start multiple consumers (PerDestinationBundler.send()):
SendBuffer buf=dests.get(dest); if(buf == null) { buf=dests.computeIfAbsent(dest, k -> new SendBuffer(msg.dest())); buf.start(); }
When 2 threads call this concurrently, and the SendBuffer has already been created, then 2 consumers could be started:
public SendBuffer start() { if(!use_single_sender_thread) { if(sendbuf_runner == null) sendbuf_runner=new Runner(fac, name, this, null); sendbuf_runner.start(); } return this; }
The creation of the runner is not protected by a lock.
Result: the multiple runners are each reading messages from the queue and sending them in parallel. If TCP.use_lock_to_send is false (and this is the case, as PerDestinationBundler sets it to false!), the access to the socket's output stream is not synchronized.
This might result in garbage at the receiver and retransmission.