mirror of https://github.com/apache/activemq.git
Switching to a List to track dispatched messages in a TopicSubscription to be consistent with a PrefetchSubscription and to prevent an error in case acks come back out of order.
This commit is contained in:
parent
9827427f46
commit
2b7bb6f81b
|
@ -17,11 +17,9 @@
|
||||||
package org.apache.activemq.broker.region;
|
package org.apache.activemq.broker.region;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.NavigableMap;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
@ -76,19 +74,9 @@ public class TopicSubscription extends AbstractSubscription {
|
||||||
protected boolean active = false;
|
protected boolean active = false;
|
||||||
protected boolean discarding = false;
|
protected boolean discarding = false;
|
||||||
|
|
||||||
|
//Used for inflight message size calculations
|
||||||
/**
|
protected final Object dispatchLock = new Object();
|
||||||
* This Map is used to keep track of messages that have been dispatched in sorted order to
|
protected final List<MessageReference> dispatched = new ArrayList<MessageReference>();
|
||||||
* optimize message acknowledgement
|
|
||||||
*/
|
|
||||||
private NavigableMap<MessageId, MessageReference> dispatched = new ConcurrentSkipListMap<>(
|
|
||||||
new Comparator<MessageId>() {
|
|
||||||
@Override
|
|
||||||
public int compare(MessageId m1, MessageId m2) {
|
|
||||||
return m1 == null ? (m2 == null ? 0 : -1) : (m2 == null ? 1
|
|
||||||
: Long.compare(m1.getBrokerSequenceId(), m2.getBrokerSequenceId()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public TopicSubscription(Broker broker,ConnectionContext context, ConsumerInfo info, SystemUsage usageManager) throws Exception {
|
public TopicSubscription(Broker broker,ConnectionContext context, ConsumerInfo info, SystemUsage usageManager) throws Exception {
|
||||||
super(broker, context, info);
|
super(broker, context, info);
|
||||||
|
@ -267,11 +255,13 @@ public class TopicSubscription extends AbstractSubscription {
|
||||||
MessageReference node = matched.next();
|
MessageReference node = matched.next();
|
||||||
node.decrementReferenceCount();
|
node.decrementReferenceCount();
|
||||||
if (node.getMessageId().equals(mdn.getMessageId())) {
|
if (node.getMessageId().equals(mdn.getMessageId())) {
|
||||||
|
synchronized(dispatchLock) {
|
||||||
matched.remove();
|
matched.remove();
|
||||||
getSubscriptionStatistics().getDispatched().increment();
|
getSubscriptionStatistics().getDispatched().increment();
|
||||||
dispatched.put(node.getMessageId(), node);
|
dispatched.add(node);
|
||||||
getSubscriptionStatistics().getInflightMessageSize().addSize(node.getSize());
|
getSubscriptionStatistics().getInflightMessageSize().addSize(node.getSize());
|
||||||
node.decrementReferenceCount();
|
node.decrementReferenceCount();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,23 +393,31 @@ public class TopicSubscription extends AbstractSubscription {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the inflight statistics on message ack. Since a message ack could be a range,
|
* Update the inflight statistics on message ack.
|
||||||
* we need to grab a subtree of the dispatched map to acknowledge messages. Finding the
|
|
||||||
* subMap is an O(log n) operation.
|
|
||||||
* @param ack
|
* @param ack
|
||||||
*/
|
*/
|
||||||
private void updateInflightMessageSizeOnAck(final MessageAck ack) {
|
private void updateInflightMessageSizeOnAck(final MessageAck ack) {
|
||||||
if (ack.getFirstMessageId() != null) {
|
synchronized(dispatchLock) {
|
||||||
NavigableMap<MessageId, MessageReference> acked = dispatched
|
boolean inAckRange = false;
|
||||||
.subMap(ack.getFirstMessageId(), true, ack.getLastMessageId(), true);
|
List<MessageReference> removeList = new ArrayList<MessageReference>();
|
||||||
Iterator<MessageId> i = acked.keySet().iterator();
|
for (final MessageReference node : dispatched) {
|
||||||
while (i.hasNext()) {
|
MessageId messageId = node.getMessageId();
|
||||||
getSubscriptionStatistics().getInflightMessageSize().addSize(-acked.get(i.next()).getSize());
|
if (ack.getFirstMessageId() == null
|
||||||
i.remove();
|
|| ack.getFirstMessageId().equals(messageId)) {
|
||||||
|
inAckRange = true;
|
||||||
|
}
|
||||||
|
if (inAckRange) {
|
||||||
|
removeList.add(node);
|
||||||
|
if (ack.getLastMessageId().equals(messageId)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final MessageReference node : removeList) {
|
||||||
|
dispatched.remove(node);
|
||||||
|
getSubscriptionStatistics().getInflightMessageSize().addSize(-node.getSize());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
getSubscriptionStatistics().getInflightMessageSize().addSize(-dispatched.get(ack.getLastMessageId()).getSize());
|
|
||||||
dispatched.remove(ack.getLastMessageId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,9 +643,12 @@ public class TopicSubscription extends AbstractSubscription {
|
||||||
md.setConsumerId(info.getConsumerId());
|
md.setConsumerId(info.getConsumerId());
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
md.setDestination(((Destination)node.getRegionDestination()).getActiveMQDestination());
|
md.setDestination(((Destination)node.getRegionDestination()).getActiveMQDestination());
|
||||||
|
synchronized(dispatchLock) {
|
||||||
getSubscriptionStatistics().getDispatched().increment();
|
getSubscriptionStatistics().getDispatched().increment();
|
||||||
dispatched.put(node.getMessageId(), node);
|
dispatched.add(node);
|
||||||
getSubscriptionStatistics().getInflightMessageSize().addSize(node.getSize());
|
getSubscriptionStatistics().getInflightMessageSize().addSize(node.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
// Keep track if this subscription is receiving messages from a single destination.
|
// Keep track if this subscription is receiving messages from a single destination.
|
||||||
if (singleDestination) {
|
if (singleDestination) {
|
||||||
if (destination == null) {
|
if (destination == null) {
|
||||||
|
@ -729,8 +730,10 @@ public class TopicSubscription extends AbstractSubscription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSlowConsumer(false);
|
setSlowConsumer(false);
|
||||||
|
synchronized(dispatchLock) {
|
||||||
dispatched.clear();
|
dispatched.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPrefetchSize() {
|
public int getPrefetchSize() {
|
||||||
|
|
Loading…
Reference in New Issue