mirror of https://github.com/apache/activemq.git
https://issues.apache.org/activemq/browse/AMQ-855 allow prefetch==0 to work with receive(timeout) and receiveNoWait()
git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@439442 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e16114f99b
commit
a19bfd4c9a
|
@ -381,6 +381,8 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
} else if ( md.getMessage()==null ) {
|
||||||
|
return null;
|
||||||
} else if (md.getMessage().isExpired()) {
|
} else if (md.getMessage().isExpired()) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Received expired message: " + md);
|
log.debug("Received expired message: " + md);
|
||||||
|
@ -415,9 +417,10 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
* this message consumer is concurrently closed
|
* this message consumer is concurrently closed
|
||||||
*/
|
*/
|
||||||
public Message receive() throws JMSException {
|
public Message receive() throws JMSException {
|
||||||
sendPullCommand();
|
|
||||||
checkClosed();
|
checkClosed();
|
||||||
checkMessageListener();
|
checkMessageListener();
|
||||||
|
|
||||||
|
sendPullCommand(-1);
|
||||||
MessageDispatch md = dequeue(-1);
|
MessageDispatch md = dequeue(-1);
|
||||||
if (md == null)
|
if (md == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -454,13 +457,12 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
* expires, and the call blocks indefinitely.
|
* expires, and the call blocks indefinitely.
|
||||||
*
|
*
|
||||||
* @param timeout
|
* @param timeout
|
||||||
* the timeout value (in milliseconds)
|
* the timeout value (in milliseconds), a time out of zero never expires.
|
||||||
* @return the next message produced for this message consumer, or null if
|
* @return the next message produced for this message consumer, or null if
|
||||||
* the timeout expires or this message consumer is concurrently
|
* the timeout expires or this message consumer is concurrently
|
||||||
* closed
|
* closed
|
||||||
*/
|
*/
|
||||||
public Message receive(long timeout) throws JMSException {
|
public Message receive(long timeout) throws JMSException {
|
||||||
sendPullCommand();
|
|
||||||
checkClosed();
|
checkClosed();
|
||||||
checkMessageListener();
|
checkMessageListener();
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
|
@ -468,8 +470,16 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendPullCommand(timeout);
|
||||||
while (timeout > 0) {
|
while (timeout > 0) {
|
||||||
MessageDispatch md = dequeue(timeout);
|
|
||||||
|
MessageDispatch md;
|
||||||
|
if (info.getPrefetchSize() == 0) {
|
||||||
|
md = dequeue(-1); // We let the broker let us know when we timeout.
|
||||||
|
} else {
|
||||||
|
md = dequeue(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
if (md == null)
|
if (md == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -492,7 +502,15 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
public Message receiveNoWait() throws JMSException {
|
public Message receiveNoWait() throws JMSException {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
checkMessageListener();
|
checkMessageListener();
|
||||||
MessageDispatch md = dequeue(0);
|
sendPullCommand(-1);
|
||||||
|
|
||||||
|
MessageDispatch md;
|
||||||
|
if (info.getPrefetchSize() == 0) {
|
||||||
|
md = dequeue(-1); // We let the broker let us know when we timeout.
|
||||||
|
} else {
|
||||||
|
md = dequeue(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (md == null)
|
if (md == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -598,10 +616,11 @@ public class ActiveMQMessageConsumer implements MessageAvailableConsumer, StatsC
|
||||||
* we are about to receive
|
* we are about to receive
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected void sendPullCommand() throws JMSException {
|
protected void sendPullCommand(long timeout) throws JMSException {
|
||||||
if (info.getPrefetchSize() == 0) {
|
if (info.getPrefetchSize() == 0) {
|
||||||
MessagePull messagePull = new MessagePull();
|
MessagePull messagePull = new MessagePull();
|
||||||
messagePull.configure(info);
|
messagePull.configure(info);
|
||||||
|
messagePull.setTimeout(timeout);
|
||||||
session.asyncSendPacket(messagePull);
|
session.asyncSendPacket(messagePull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.apache.activemq.command.Message;
|
||||||
import org.apache.activemq.command.MessageId;
|
import org.apache.activemq.command.MessageId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only used by the {@link QueueMessageReference#END_OF_BROWSE_MARKER}
|
* Only used by the {@link QueueMessageReference#NULL_MESSAGE}
|
||||||
*/
|
*/
|
||||||
final class EndOfBrowseMarkerQueueMessageReference implements
|
final class EndOfBrowseMarkerQueueMessageReference implements
|
||||||
QueueMessageReference {
|
QueueMessageReference {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.activemq.command.MessageDispatchNotification;
|
||||||
import org.apache.activemq.command.MessageId;
|
import org.apache.activemq.command.MessageId;
|
||||||
import org.apache.activemq.command.MessagePull;
|
import org.apache.activemq.command.MessagePull;
|
||||||
import org.apache.activemq.command.Response;
|
import org.apache.activemq.command.Response;
|
||||||
|
import org.apache.activemq.thread.Scheduler;
|
||||||
import org.apache.activemq.transaction.Synchronization;
|
import org.apache.activemq.transaction.Synchronization;
|
||||||
import org.apache.activemq.util.BrokerSupport;
|
import org.apache.activemq.util.BrokerSupport;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -68,16 +69,51 @@ abstract public class PrefetchSubscription extends AbstractSubscription{
|
||||||
/**
|
/**
|
||||||
* Allows a message to be pulled on demand by a client
|
* Allows a message to be pulled on demand by a client
|
||||||
*/
|
*/
|
||||||
public Response pullMessage(ConnectionContext context, MessagePull pull) throws Exception {
|
synchronized public Response pullMessage(ConnectionContext context, MessagePull pull) throws Exception {
|
||||||
if (getPrefetchSize() == 0) {
|
// The slave should not deliver pull messages. TODO: when the slave becomes a master,
|
||||||
|
// He should send a NULL message to all the consumers to 'wake them up' in case
|
||||||
|
// they were waiting for a message.
|
||||||
|
if (getPrefetchSize() == 0 && !isSlaveBroker()) {
|
||||||
prefetchExtension++;
|
prefetchExtension++;
|
||||||
|
|
||||||
|
final long dispatchCounterBeforePull = dispatchCounter;
|
||||||
dispatchMatched();
|
dispatchMatched();
|
||||||
|
|
||||||
// TODO it might be nice one day to actually return the message itself
|
// If there was nothing dispatched.. we may need to setup a timeout.
|
||||||
|
if( dispatchCounterBeforePull == dispatchCounter ) {
|
||||||
|
// imediate timeout used by receiveNoWait()
|
||||||
|
if( pull.getTimeout() == -1 ) {
|
||||||
|
// Send a NULL message.
|
||||||
|
add(QueueMessageReference.NULL_MESSAGE);
|
||||||
|
dispatchMatched();
|
||||||
|
}
|
||||||
|
if( pull.getTimeout() > 0 ) {
|
||||||
|
Scheduler.executeAfterDelay(new Runnable(){
|
||||||
|
public void run() {
|
||||||
|
pullTimeout(dispatchCounterBeforePull);
|
||||||
|
}
|
||||||
|
}, pull.getTimeout());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Occurs when a pull times out. If nothing has been dispatched
|
||||||
|
* since the timeout was setup, then send the NULL message.
|
||||||
|
*/
|
||||||
|
synchronized private void pullTimeout(long dispatchCounterBeforePull) {
|
||||||
|
if( dispatchCounterBeforePull == dispatchCounter ) {
|
||||||
|
try {
|
||||||
|
add(QueueMessageReference.NULL_MESSAGE);
|
||||||
|
dispatchMatched();
|
||||||
|
} catch (Exception e) {
|
||||||
|
context.getConnection().serviceException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized public void add(MessageReference node) throws Exception{
|
synchronized public void add(MessageReference node) throws Exception{
|
||||||
enqueueCounter++;
|
enqueueCounter++;
|
||||||
if(!isFull()){
|
if(!isFull()){
|
||||||
|
@ -311,9 +347,17 @@ abstract public class PrefetchSubscription extends AbstractSubscription{
|
||||||
}
|
}
|
||||||
// Make sure we can dispatch a message.
|
// Make sure we can dispatch a message.
|
||||||
if(canDispatch(node)&&!isSlaveBroker()){
|
if(canDispatch(node)&&!isSlaveBroker()){
|
||||||
dispatchCounter++;
|
|
||||||
MessageDispatch md=createMessageDispatch(node,message);
|
MessageDispatch md=createMessageDispatch(node,message);
|
||||||
|
|
||||||
|
// NULL messages don't count... they don't get Acked.
|
||||||
|
if( node != QueueMessageReference.NULL_MESSAGE ) {
|
||||||
|
dispatchCounter++;
|
||||||
dispatched.addLast(node);
|
dispatched.addLast(node);
|
||||||
|
} else {
|
||||||
|
prefetchExtension=Math.max(0,prefetchExtension-1);
|
||||||
|
}
|
||||||
|
|
||||||
if(info.isDispatchAsync()){
|
if(info.isDispatchAsync()){
|
||||||
md.setConsumer(new Runnable(){
|
md.setConsumer(new Runnable(){
|
||||||
public void run(){
|
public void run(){
|
||||||
|
@ -335,8 +379,10 @@ abstract public class PrefetchSubscription extends AbstractSubscription{
|
||||||
|
|
||||||
synchronized protected void onDispatch(final MessageReference node,final Message message){
|
synchronized protected void onDispatch(final MessageReference node,final Message message){
|
||||||
if(node.getRegionDestination()!=null){
|
if(node.getRegionDestination()!=null){
|
||||||
|
if( node != QueueMessageReference.NULL_MESSAGE ) {
|
||||||
node.getRegionDestination().getDestinationStatistics().onMessageDequeue(message);
|
node.getRegionDestination().getDestinationStatistics().onMessageDequeue(message);
|
||||||
context.getConnection().getStatistics().onMessageDequeue(message);
|
context.getConnection().getStatistics().onMessageDequeue(message);
|
||||||
|
}
|
||||||
try{
|
try{
|
||||||
dispatchMatched();
|
dispatchMatched();
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
|
@ -365,6 +411,13 @@ abstract public class PrefetchSubscription extends AbstractSubscription{
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected MessageDispatch createMessageDispatch(MessageReference node,Message message){
|
protected MessageDispatch createMessageDispatch(MessageReference node,Message message){
|
||||||
|
if( node == QueueMessageReference.NULL_MESSAGE ) {
|
||||||
|
MessageDispatch md = new MessageDispatch();
|
||||||
|
md.setMessage(null);
|
||||||
|
md.setConsumerId( info.getConsumerId() );
|
||||||
|
md.setDestination( null );
|
||||||
|
return md;
|
||||||
|
} else {
|
||||||
MessageDispatch md=new MessageDispatch();
|
MessageDispatch md=new MessageDispatch();
|
||||||
md.setConsumerId(info.getConsumerId());
|
md.setConsumerId(info.getConsumerId());
|
||||||
md.setDestination(node.getRegionDestination().getActiveMQDestination());
|
md.setDestination(node.getRegionDestination().getActiveMQDestination());
|
||||||
|
@ -372,6 +425,7 @@ abstract public class PrefetchSubscription extends AbstractSubscription{
|
||||||
md.setRedeliveryCounter(node.getRedeliveryCounter());
|
md.setRedeliveryCounter(node.getRedeliveryCounter());
|
||||||
return md;
|
return md;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use when a matched message is about to be dispatched to the client.
|
* Use when a matched message is about to be dispatched to the client.
|
||||||
|
|
|
@ -17,16 +17,14 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.broker.region;
|
package org.apache.activemq.broker.region;
|
||||||
|
|
||||||
import javax.jms.InvalidSelectorException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.jms.InvalidSelectorException;
|
||||||
|
|
||||||
import org.apache.activemq.broker.Broker;
|
import org.apache.activemq.broker.Broker;
|
||||||
import org.apache.activemq.broker.ConnectionContext;
|
import org.apache.activemq.broker.ConnectionContext;
|
||||||
import org.apache.activemq.command.ConsumerInfo;
|
import org.apache.activemq.command.ConsumerInfo;
|
||||||
import org.apache.activemq.command.Message;
|
|
||||||
import org.apache.activemq.command.MessageAck;
|
import org.apache.activemq.command.MessageAck;
|
||||||
import org.apache.activemq.command.MessageDispatch;
|
|
||||||
import org.apache.activemq.filter.MessageEvaluationContext;
|
import org.apache.activemq.filter.MessageEvaluationContext;
|
||||||
|
|
||||||
public class QueueBrowserSubscription extends QueueSubscription {
|
public class QueueBrowserSubscription extends QueueSubscription {
|
||||||
|
@ -53,19 +51,7 @@ public class QueueBrowserSubscription extends QueueSubscription {
|
||||||
|
|
||||||
public void browseDone() throws Exception {
|
public void browseDone() throws Exception {
|
||||||
browseDone = true;
|
browseDone = true;
|
||||||
add(QueueMessageReference.END_OF_BROWSE_MARKER);
|
add(QueueMessageReference.NULL_MESSAGE);
|
||||||
}
|
|
||||||
|
|
||||||
protected MessageDispatch createMessageDispatch(MessageReference node, Message message) {
|
|
||||||
if( node == QueueMessageReference.END_OF_BROWSE_MARKER ) {
|
|
||||||
MessageDispatch md = new MessageDispatch();
|
|
||||||
md.setMessage(null);
|
|
||||||
md.setConsumerId( info.getConsumerId() );
|
|
||||||
md.setDestination( null );
|
|
||||||
return md;
|
|
||||||
} else {
|
|
||||||
return super.createMessageDispatch(node, message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(MessageReference node, MessageEvaluationContext context) throws IOException {
|
public boolean matches(MessageReference node, MessageEvaluationContext context) throws IOException {
|
||||||
|
|
|
@ -25,7 +25,7 @@ package org.apache.activemq.broker.region;
|
||||||
*/
|
*/
|
||||||
public interface QueueMessageReference extends MessageReference {
|
public interface QueueMessageReference extends MessageReference {
|
||||||
|
|
||||||
public static final QueueMessageReference END_OF_BROWSE_MARKER = new EndOfBrowseMarkerQueueMessageReference();
|
public static final QueueMessageReference NULL_MESSAGE = new EndOfBrowseMarkerQueueMessageReference();
|
||||||
|
|
||||||
public boolean isAcked();
|
public boolean isAcked();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue