|
10 | 10 | import org.jgroups.util.*;
|
11 | 11 |
|
12 | 12 | import java.util.*;
|
13 |
| -import java.util.concurrent.ConcurrentHashMap; |
14 |
| -import java.util.concurrent.ConcurrentMap; |
15 |
| -import java.util.concurrent.Future; |
16 |
| -import java.util.concurrent.TimeUnit; |
| 13 | +import java.util.concurrent.*; |
17 | 14 | import java.util.concurrent.atomic.AtomicBoolean;
|
18 | 15 | import java.util.concurrent.atomic.AtomicInteger;
|
19 | 16 | import java.util.concurrent.atomic.AtomicLong;
|
@@ -60,20 +57,18 @@ public class NAKACK2 extends Protocol implements DiagnosticsHandler.ProbeHandler
|
60 | 57 | @Property(description="Use a multicast to request retransmission of missing messages")
|
61 | 58 | protected boolean use_mcast_xmit_req;
|
62 | 59 |
|
63 |
| - |
64 | 60 | /**
|
65 | 61 | * Ask a random member for retransmission of a missing message. If set to
|
66 | 62 | * true, discard_delivered_msgs will be set to false
|
67 | 63 | */
|
68 | 64 | @Property(description="Ask a random member for retransmission of a missing message. Default is false")
|
69 | 65 | protected boolean xmit_from_random_member;
|
70 | 66 |
|
71 |
| - |
72 | 67 | /**
|
73 | 68 | * Messages that have been received in order are sent up the stack (= delivered to the application).
|
74 |
| - * Delivered messages are removed from the retransmission buffer, so they can get GC'ed by the JVM. When this |
75 |
| - * property is true, everyone (except the sender of a message) removes the message from their retransission |
76 |
| - * buffers as soon as it has been delivered to the application |
| 69 | + * Delivered messages are removed from the retransmit table, so they can get GC'ed by the JVM. When this |
| 70 | + * property is true, everyone (except the sender of a message) removes the message from their retransmit |
| 71 | + * table as soon as it has been delivered to the application |
77 | 72 | */
|
78 | 73 | @Property(description="Should messages delivered to application be discarded")
|
79 | 74 | protected boolean discard_delivered_msgs=true;
|
@@ -110,7 +105,7 @@ public class NAKACK2 extends Protocol implements DiagnosticsHandler.ProbeHandler
|
110 | 105 | @Property(description="Size of the queue to hold messages received after creating the channel, but before being " +
|
111 | 106 | "connected (is_server=false). After becoming the server, the messages in the queue are fed into up() and the " +
|
112 | 107 | "queue is cleared. The motivation is to avoid retransmissions (see https://issues.redhat.com/browse/JGRP-1509 " +
|
113 |
| - "for details). 0 disables the queue.") |
| 108 | + "for details).") |
114 | 109 | protected int become_server_queue_size=50;
|
115 | 110 |
|
116 | 111 | @Property(description="Time during which identical warnings about messages from a non member will be suppressed. " +
|
@@ -257,7 +252,7 @@ public void setResendLastSeqno(boolean flag) {
|
257 | 252 | /** Keeps a bounded list of the last N digest sets */
|
258 | 253 | protected final BoundedList<String> digest_history=new BoundedList<>(10);
|
259 | 254 |
|
260 |
| - protected BoundedList<Message> become_server_queue; |
| 255 | + protected Queue<Message> become_server_queue; |
261 | 256 |
|
262 | 257 | /** Log to suppress identical warnings for messages from non-members */
|
263 | 258 | protected SuppressLog<Address> suppress_log_non_member;
|
@@ -338,7 +333,7 @@ public <T extends Protocol> T setLevel(String level) {
|
338 | 333 |
|
339 | 334 | @ManagedAttribute(description="Actual size of the become_server_queue",type=AttributeType.SCALAR)
|
340 | 335 | public int getBecomeServerQueueSizeActual() {
|
341 |
| - return become_server_queue != null? become_server_queue.size() : -1; |
| 336 | + return become_server_queue.size(); |
342 | 337 | }
|
343 | 338 |
|
344 | 339 | /** Returns the receive window for sender; only used for testing. Do not use ! */
|
@@ -499,8 +494,23 @@ public void init() throws Exception {
|
499 | 494 | }
|
500 | 495 | }
|
501 | 496 |
|
502 |
| - if(become_server_queue_size > 0) |
503 |
| - become_server_queue=new BoundedList<>(become_server_queue_size); |
| 497 | + if(xmit_interval <= 0) { |
| 498 | + // https://issues.redhat.com/browse/JGRP-2675 |
| 499 | + become_server_queue=new ConcurrentLinkedQueue<>(); |
| 500 | + RejectedExecutionHandler handler=transport.getThreadPool().getRejectedExecutionHandler(); |
| 501 | + if(!(handler instanceof ThreadPoolExecutor.CallerRunsPolicy)) { |
| 502 | + log.warn("%s: xmit_interval of %d requires a CallerRunsPolicy in the thread pool; replacing %s", |
| 503 | + local_addr, xmit_interval, handler.getClass().getSimpleName()); |
| 504 | + transport.getThreadPool().setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| 505 | + } |
| 506 | + } |
| 507 | + else { |
| 508 | + if(become_server_queue_size <= 0) { |
| 509 | + log.warn("%s: %s.become_server_queue_size is <= 0; setting it to 10", local_addr, NAKACK2.class.getSimpleName()); |
| 510 | + become_server_queue_size=10; |
| 511 | + } |
| 512 | + become_server_queue=new ArrayBlockingQueue<>(become_server_queue_size); |
| 513 | + } |
504 | 514 |
|
505 | 515 | if(suppress_time_non_member_warnings > 0)
|
506 | 516 | suppress_log_non_member=new SuppressLog<>(log, "MsgDroppedNak", "SuppressMsg");
|
@@ -539,8 +549,7 @@ public void start() throws Exception {
|
539 | 549 | public void stop() {
|
540 | 550 | running=false;
|
541 | 551 | is_server=false;
|
542 |
| - if(become_server_queue != null) |
543 |
| - become_server_queue.clear(); |
| 552 | + become_server_queue.clear(); |
544 | 553 | stopRetransmitTask();
|
545 | 554 | xmit_task_map.clear();
|
546 | 555 | stable_xmit_map.clear();
|
@@ -785,12 +794,10 @@ public String[] supportedKeys() {
|
785 | 794 | /* --------------------------------- Private Methods --------------------------------------- */
|
786 | 795 |
|
787 | 796 | protected void queueMessage(Message msg, long seqno) {
|
788 |
| - if(become_server_queue != null) { |
789 |
| - become_server_queue.add(msg); |
790 |
| - log.trace("%s: message %s#%d was added to queue (not yet server)", local_addr, msg.getSrc(), seqno); |
791 |
| - } |
| 797 | + if(become_server_queue.offer(msg)) // discards item if queue is full |
| 798 | + log.trace("%s: message %s#%d was queued (not yet server)", local_addr, msg.getSrc(), seqno); |
792 | 799 | else
|
793 |
| - log.trace("%s: message %s#%d was discarded (not yet server)", local_addr, msg.getSrc(), seqno); |
| 800 | + log.trace("%s: message %s#%d was discarded (not yet server, queue full)", local_addr, msg.getSrc(), seqno); |
794 | 801 | }
|
795 | 802 |
|
796 | 803 | protected void unknownMember(Address sender, Object message) {
|
@@ -1028,19 +1035,14 @@ protected void deliverBatch(MessageBatch batch) {
|
1028 | 1035 | * {@link GMS#installView(org.jgroups.View,org.jgroups.util.Digest)} method (called when a view is installed).
|
1029 | 1036 | */
|
1030 | 1037 | protected void flushBecomeServerQueue() {
|
1031 |
| - if(become_server_queue != null && !become_server_queue.isEmpty()) { |
| 1038 | + if(!become_server_queue.isEmpty()) { |
1032 | 1039 | log.trace("%s: flushing become_server_queue (%d elements)", local_addr, become_server_queue.size());
|
1033 |
| - |
1034 | 1040 | TP transport=getTransport();
|
1035 |
| - for(final Message msg: become_server_queue) { |
1036 |
| - transport.getThreadPool().execute(() -> { |
1037 |
| - try { |
1038 |
| - up(msg); |
1039 |
| - } |
1040 |
| - finally { |
1041 |
| - become_server_queue.remove(msg); |
1042 |
| - } |
1043 |
| - }); |
| 1041 | + for(;;) { |
| 1042 | + final Message msg=become_server_queue.poll(); |
| 1043 | + if(msg == null) |
| 1044 | + break; |
| 1045 | + transport.getThreadPool().execute(() -> up(msg)); |
1044 | 1046 | }
|
1045 | 1047 | }
|
1046 | 1048 | }
|
@@ -1436,7 +1438,7 @@ protected void stable(Digest digest) {
|
1436 | 1438 | // check whether the last seqno received for a sender P in the stability digest is > last seqno
|
1437 | 1439 | // received for P in my digest. if yes, request retransmission (see "Last Message Dropped" topic in DESIGN)
|
1438 | 1440 | Table<Message> buf=xmit_table.get(member);
|
1439 |
| - if(buf != null) { |
| 1441 | + if(buf != null && xmit_interval > 0) { |
1440 | 1442 | long my_hr=buf.getHighestReceived();
|
1441 | 1443 | Long prev_hr=stable_xmit_map.get(member);
|
1442 | 1444 | if(prev_hr != null && prev_hr > my_hr) {
|
@@ -1501,7 +1503,7 @@ protected static long sizeOfAllMessages(Table<Message> buf, boolean include_head
|
1501 | 1503 | }
|
1502 | 1504 |
|
1503 | 1505 | protected void startRetransmitTask() {
|
1504 |
| - if(xmit_task == null || xmit_task.isDone()) |
| 1506 | + if(xmit_interval > 0 && (xmit_task == null || xmit_task.isDone())) |
1505 | 1507 | xmit_task=timer.scheduleWithFixedDelay(new RetransmitTask(), 0, xmit_interval, TimeUnit.MILLISECONDS, sends_can_block);
|
1506 | 1508 | }
|
1507 | 1509 |
|
|
0 commit comments