mirror of https://github.com/apache/activemq.git
transaction performance enhancements
git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@958009 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
39c536395a
commit
ddb2c91c20
|
@ -102,7 +102,7 @@ public class Queue extends BaseDestination implements Task, UsageListener {
|
||||||
private MessageGroupMap messageGroupOwners;
|
private MessageGroupMap messageGroupOwners;
|
||||||
private DispatchPolicy dispatchPolicy = new RoundRobinDispatchPolicy();
|
private DispatchPolicy dispatchPolicy = new RoundRobinDispatchPolicy();
|
||||||
private MessageGroupMapFactory messageGroupMapFactory = new MessageGroupHashBucketFactory();
|
private MessageGroupMapFactory messageGroupMapFactory = new MessageGroupHashBucketFactory();
|
||||||
private final Lock sendLock = new ReentrantLock();
|
final Lock sendLock = new ReentrantLock();
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
protected final Map<MessageId, Runnable> messagesWaitingForSpace = Collections
|
protected final Map<MessageId, Runnable> messagesWaitingForSpace = Collections
|
||||||
.synchronizedMap(new LinkedHashMap<MessageId, Runnable>());
|
.synchronizedMap(new LinkedHashMap<MessageId, Runnable>());
|
||||||
|
@ -616,9 +616,6 @@ public class Queue extends BaseDestination implements Task, UsageListener {
|
||||||
@Override
|
@Override
|
||||||
public void beforeCommit() throws Exception {
|
public void beforeCommit() throws Exception {
|
||||||
sendLock.lockInterruptibly();
|
sendLock.lockInterruptibly();
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void afterCommit() throws Exception {
|
|
||||||
try {
|
try {
|
||||||
// It could take while before we receive the commit
|
// It could take while before we receive the commit
|
||||||
// op, by that time the message could have expired..
|
// op, by that time the message could have expired..
|
||||||
|
|
|
@ -80,10 +80,11 @@ public class Topic extends BaseDestination implements Task {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
public Topic(BrokerService brokerService, ActiveMQDestination destination, TopicMessageStore store, DestinationStatistics parentStats, TaskRunnerFactory taskFactory) throws Exception {
|
public Topic(BrokerService brokerService, ActiveMQDestination destination, TopicMessageStore store,
|
||||||
|
DestinationStatistics parentStats, TaskRunnerFactory taskFactory) throws Exception {
|
||||||
super(brokerService, store, destination, parentStats);
|
super(brokerService, store, destination, parentStats);
|
||||||
this.topicStore = store;
|
this.topicStore = store;
|
||||||
//set default subscription recovery policy
|
// set default subscription recovery policy
|
||||||
subscriptionRecoveryPolicy = new NoSubscriptionRecoveryPolicy();
|
subscriptionRecoveryPolicy = new NoSubscriptionRecoveryPolicy();
|
||||||
this.taskRunner = taskFactory.createTaskRunner(this, "Topic " + destination.getPhysicalName());
|
this.taskRunner = taskFactory.createTaskRunner(this, "Topic " + destination.getPhysicalName());
|
||||||
}
|
}
|
||||||
|
@ -92,7 +93,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
public void initialize() throws Exception {
|
public void initialize() throws Exception {
|
||||||
super.initialize();
|
super.initialize();
|
||||||
if (store != null) {
|
if (store != null) {
|
||||||
// AMQ-2586: Better to leave this stat at zero than to give the user misleading metrics.
|
// AMQ-2586: Better to leave this stat at zero than to give the user
|
||||||
|
// misleading metrics.
|
||||||
// int messageCount = store.getMessageCount();
|
// int messageCount = store.getMessageCount();
|
||||||
// destinationStatistics.getMessages().setCount(messageCount);
|
// destinationStatistics.getMessages().setCount(messageCount);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +149,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSubscription(ConnectionContext context, Subscription sub, long lastDeliveredSequenceId) throws Exception {
|
public void removeSubscription(ConnectionContext context, Subscription sub, long lastDeliveredSequenceId)
|
||||||
|
throws Exception {
|
||||||
if (!sub.getConsumerInfo().isDurable()) {
|
if (!sub.getConsumerInfo().isDurable()) {
|
||||||
destinationStatistics.getConsumers().decrement();
|
destinationStatistics.getConsumers().decrement();
|
||||||
synchronized (consumers) {
|
synchronized (consumers) {
|
||||||
|
@ -267,7 +270,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
final ConnectionContext context = producerExchange.getConnectionContext();
|
final ConnectionContext context = producerExchange.getConnectionContext();
|
||||||
|
|
||||||
final ProducerInfo producerInfo = producerExchange.getProducerState().getInfo();
|
final ProducerInfo producerInfo = producerExchange.getProducerState().getInfo();
|
||||||
final boolean sendProducerAck = !message.isResponseRequired() && producerInfo.getWindowSize() > 0 && !context.isInRecoveryMode();
|
final boolean sendProducerAck = !message.isResponseRequired() && producerInfo.getWindowSize() > 0
|
||||||
|
&& !context.isInRecoveryMode();
|
||||||
|
|
||||||
// There is delay between the client sending it and it arriving at the
|
// There is delay between the client sending it and it arriving at the
|
||||||
// destination.. it may have expired.
|
// destination.. it may have expired.
|
||||||
|
@ -289,17 +293,24 @@ public class Topic extends BaseDestination implements Task {
|
||||||
|
|
||||||
if (warnOnProducerFlowControl) {
|
if (warnOnProducerFlowControl) {
|
||||||
warnOnProducerFlowControl = false;
|
warnOnProducerFlowControl = false;
|
||||||
LOG.info("Usage Manager memory limit ("+ memoryUsage.getLimit() + ") reached for " + getActiveMQDestination().getQualifiedName()
|
LOG
|
||||||
|
.info("Usage Manager memory limit ("
|
||||||
|
+ memoryUsage.getLimit()
|
||||||
|
+ ") reached for "
|
||||||
|
+ getActiveMQDestination().getQualifiedName()
|
||||||
+ ". Producers will be throttled to the rate at which messages are removed from this destination to prevent flooding it."
|
+ ". Producers will be throttled to the rate at which messages are removed from this destination to prevent flooding it."
|
||||||
+ " See http://activemq.apache.org/producer-flow-control.html for more info");
|
+ " See http://activemq.apache.org/producer-flow-control.html for more info");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (systemUsage.isSendFailIfNoSpace()) {
|
if (systemUsage.isSendFailIfNoSpace()) {
|
||||||
throw new javax.jms.ResourceAllocationException("Usage Manager memory limit ("+ memoryUsage.getLimit() + ") reached. Stopping producer (" + message.getProducerId() + ") to prevent flooding "
|
throw new javax.jms.ResourceAllocationException("Usage Manager memory limit ("
|
||||||
+ getActiveMQDestination().getQualifiedName() + "." + " See http://activemq.apache.org/producer-flow-control.html for more info");
|
+ memoryUsage.getLimit() + ") reached. Stopping producer (" + message.getProducerId()
|
||||||
|
+ ") to prevent flooding " + getActiveMQDestination().getQualifiedName() + "."
|
||||||
|
+ " See http://activemq.apache.org/producer-flow-control.html for more info");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can avoid blocking due to low usage if the producer is sending
|
// We can avoid blocking due to low usage if the producer is
|
||||||
|
// sending
|
||||||
// a sync message or
|
// a sync message or
|
||||||
// if it is using a producer window
|
// if it is using a producer window
|
||||||
if (producerInfo.getWindowSize() > 0 || message.isResponseRequired()) {
|
if (producerInfo.getWindowSize() > 0 || message.isResponseRequired()) {
|
||||||
|
@ -319,7 +330,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendProducerAck) {
|
if (sendProducerAck) {
|
||||||
ProducerAck ack = new ProducerAck(producerInfo.getProducerId(), message.getSize());
|
ProducerAck ack = new ProducerAck(producerInfo.getProducerId(), message
|
||||||
|
.getSize());
|
||||||
context.getConnection().dispatchAsync(ack);
|
context.getConnection().dispatchAsync(ack);
|
||||||
} else {
|
} else {
|
||||||
Response response = new Response();
|
Response response = new Response();
|
||||||
|
@ -338,7 +350,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the user manager is not full, then the task will not
|
// If the user manager is not full, then the task will
|
||||||
|
// not
|
||||||
// get called..
|
// get called..
|
||||||
if (!memoryUsage.notifyCallbackWhenNotFull(sendMessagesWaitingForSpaceTask)) {
|
if (!memoryUsage.notifyCallbackWhenNotFull(sendMessagesWaitingForSpaceTask)) {
|
||||||
// so call it directly here.
|
// so call it directly here.
|
||||||
|
@ -349,7 +362,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Producer flow control cannot be used, so we have do the flow
|
// Producer flow control cannot be used, so we have do the
|
||||||
|
// flow
|
||||||
// control at the broker
|
// control at the broker
|
||||||
// by blocking this thread until there is space available.
|
// by blocking this thread until there is space available.
|
||||||
|
|
||||||
|
@ -364,12 +378,20 @@ public class Topic extends BaseDestination implements Task {
|
||||||
if (count > 2 && context.isInTransaction()) {
|
if (count > 2 && context.isInTransaction()) {
|
||||||
count = 0;
|
count = 0;
|
||||||
int size = context.getTransaction().size();
|
int size = context.getTransaction().size();
|
||||||
LOG.warn("Waiting for space to send transacted message - transaction elements = " + size + " need more space to commit. Message = " + message);
|
LOG.warn("Waiting for space to send transacted message - transaction elements = "
|
||||||
|
+ size + " need more space to commit. Message = " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
waitForSpace(context, memoryUsage, "Usage Manager memory limit reached. Stopping producer (" + message.getProducerId() + ") to prevent flooding "
|
waitForSpace(
|
||||||
+ getActiveMQDestination().getQualifiedName() + "." + " See http://activemq.apache.org/producer-flow-control.html for more info");
|
context,
|
||||||
|
memoryUsage,
|
||||||
|
"Usage Manager memory limit reached. Stopping producer ("
|
||||||
|
+ message.getProducerId()
|
||||||
|
+ ") to prevent flooding "
|
||||||
|
+ getActiveMQDestination().getQualifiedName()
|
||||||
|
+ "."
|
||||||
|
+ " See http://activemq.apache.org/producer-flow-control.html for more info");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +425,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
synchronized void doMessageSend(final ProducerBrokerExchange producerExchange, final Message message) throws IOException, Exception {
|
synchronized void doMessageSend(final ProducerBrokerExchange producerExchange, final Message message)
|
||||||
|
throws IOException, Exception {
|
||||||
final ConnectionContext context = producerExchange.getConnectionContext();
|
final ConnectionContext context = producerExchange.getConnectionContext();
|
||||||
message.setRegionDestination(this);
|
message.setRegionDestination(this);
|
||||||
message.getMessageId().setBrokerSequenceId(getDestinationSequenceId());
|
message.getMessageId().setBrokerSequenceId(getDestinationSequenceId());
|
||||||
|
@ -411,7 +434,9 @@ public class Topic extends BaseDestination implements Task {
|
||||||
|
|
||||||
if (topicStore != null && message.isPersistent() && !canOptimizeOutPersistence()) {
|
if (topicStore != null && message.isPersistent() && !canOptimizeOutPersistence()) {
|
||||||
if (systemUsage.getStoreUsage().isFull(getStoreUsageHighWaterMark())) {
|
if (systemUsage.getStoreUsage().isFull(getStoreUsageHighWaterMark())) {
|
||||||
final String logMessage = "Usage Manager Store is Full, " + getStoreUsageHighWaterMark() + "% of " + systemUsage.getStoreUsage().getLimit() + ". Stopping producer (" + message.getProducerId() + ") to prevent flooding " + getActiveMQDestination().getQualifiedName() + "."
|
final String logMessage = "Usage Manager Store is Full, " + getStoreUsageHighWaterMark() + "% of "
|
||||||
|
+ systemUsage.getStoreUsage().getLimit() + ". Stopping producer (" + message.getProducerId()
|
||||||
|
+ ") to prevent flooding " + getActiveMQDestination().getQualifiedName() + "."
|
||||||
+ " See http://activemq.apache.org/producer-flow-control.html for more info";
|
+ " See http://activemq.apache.org/producer-flow-control.html for more info";
|
||||||
if (systemUsage.isSendFailIfNoSpace()) {
|
if (systemUsage.isSendFailIfNoSpace()) {
|
||||||
throw new javax.jms.ResourceAllocationException(logMessage);
|
throw new javax.jms.ResourceAllocationException(logMessage);
|
||||||
|
@ -427,7 +452,7 @@ public class Topic extends BaseDestination implements Task {
|
||||||
if (context.isInTransaction()) {
|
if (context.isInTransaction()) {
|
||||||
context.getTransaction().addSynchronization(new Synchronization() {
|
context.getTransaction().addSynchronization(new Synchronization() {
|
||||||
@Override
|
@Override
|
||||||
public void afterCommit() throws Exception {
|
public void beforeCommit() throws Exception {
|
||||||
// It could take while before we receive the commit
|
// It could take while before we receive the commit
|
||||||
// operration.. by that time the message could have
|
// operration.. by that time the message could have
|
||||||
// expired..
|
// expired..
|
||||||
|
@ -455,8 +480,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
if (result != null && !result.isCancelled()) {
|
if (result != null && !result.isCancelled()) {
|
||||||
try {
|
try {
|
||||||
result.get();
|
result.get();
|
||||||
}catch(CancellationException e) {
|
} catch (CancellationException e) {
|
||||||
//ignore - the task has been cancelled if the message
|
// ignore - the task has been cancelled if the message
|
||||||
// has already been deleted
|
// has already been deleted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,7 +497,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
return "Topic: destination=" + destination.getPhysicalName() + ", subscriptions=" + consumers.size();
|
return "Topic: destination=" + destination.getPhysicalName() + ", subscriptions=" + consumers.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acknowledge(ConnectionContext context, Subscription sub, final MessageAck ack, final MessageReference node) throws IOException {
|
public void acknowledge(ConnectionContext context, Subscription sub, final MessageAck ack,
|
||||||
|
final MessageReference node) throws IOException {
|
||||||
if (topicStore != null && node.isPersistent()) {
|
if (topicStore != null && node.isPersistent()) {
|
||||||
DurableTopicSubscription dsub = (DurableTopicSubscription) sub;
|
DurableTopicSubscription dsub = (DurableTopicSubscription) sub;
|
||||||
SubscriptionKey key = dsub.getSubscriptionKey();
|
SubscriptionKey key = dsub.getSubscriptionKey();
|
||||||
|
@ -580,7 +606,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void dispatch(final ConnectionContext context, Message message) throws Exception {
|
protected void dispatch(final ConnectionContext context, Message message) throws Exception {
|
||||||
// AMQ-2586: Better to leave this stat at zero than to give the user misleading metrics.
|
// AMQ-2586: Better to leave this stat at zero than to give the user
|
||||||
|
// misleading metrics.
|
||||||
// destinationStatistics.getMessages().increment();
|
// destinationStatistics.getMessages().increment();
|
||||||
destinationStatistics.getEnqueues().increment();
|
destinationStatistics.getEnqueues().increment();
|
||||||
dispatchValve.increment();
|
dispatchValve.increment();
|
||||||
|
@ -612,7 +639,8 @@ public class Topic extends BaseDestination implements Task {
|
||||||
|
|
||||||
public void messageExpired(ConnectionContext context, Subscription subs, MessageReference reference) {
|
public void messageExpired(ConnectionContext context, Subscription subs, MessageReference reference) {
|
||||||
broker.messageExpired(context, reference);
|
broker.messageExpired(context, reference);
|
||||||
// AMQ-2586: Better to leave this stat at zero than to give the user misleading metrics.
|
// AMQ-2586: Better to leave this stat at zero than to give the user
|
||||||
|
// misleading metrics.
|
||||||
// destinationStatistics.getMessages().decrement();
|
// destinationStatistics.getMessages().decrement();
|
||||||
destinationStatistics.getEnqueues().decrement();
|
destinationStatistics.getEnqueues().decrement();
|
||||||
destinationStatistics.getExpired().increment();
|
destinationStatistics.getExpired().increment();
|
||||||
|
@ -632,5 +660,4 @@ public class Topic extends BaseDestination implements Task {
|
||||||
return LOG;
|
return LOG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,7 +244,6 @@ public class KahaDBTransactionStore implements TransactionStore {
|
||||||
doneSomething = true;
|
doneSomething = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postCommit != null) {
|
if (postCommit != null) {
|
||||||
postCommit.run();
|
postCommit.run();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue