- Made the dispatchValve handling a little safer.. it was previously possible that an exception could cause the broker to miss turning it off before trying to turn it on.

- better producer flow control logic, was not working for sync send producers without a window


git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@559915 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Hiram R. Chirino 2007-07-26 18:07:16 +00:00
parent 3b88ba0c47
commit 6a928d5cfe
1 changed files with 54 additions and 41 deletions

View File

@ -19,10 +19,12 @@ package org.apache.activemq.broker.region;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.jms.InvalidSelectorException; import javax.jms.InvalidSelectorException;
import javax.jms.JMSException; import javax.jms.JMSException;
@ -48,6 +50,7 @@ import org.apache.activemq.command.Message;
import org.apache.activemq.command.MessageAck; import org.apache.activemq.command.MessageAck;
import org.apache.activemq.command.MessageId; import org.apache.activemq.command.MessageId;
import org.apache.activemq.command.ProducerAck; import org.apache.activemq.command.ProducerAck;
import org.apache.activemq.command.Response;
import org.apache.activemq.filter.BooleanExpression; import org.apache.activemq.filter.BooleanExpression;
import org.apache.activemq.filter.MessageEvaluationContext; import org.apache.activemq.filter.MessageEvaluationContext;
import org.apache.activemq.kaha.Store; import org.apache.activemq.kaha.Store;
@ -217,28 +220,31 @@ public class Queue implements Destination, Task {
// duplicates // duplicates
// etc. // etc.
dispatchValve.turnOff(); dispatchValve.turnOff();
msgContext.setDestination(destination); try {
synchronized(pagedInMessages){ msgContext.setDestination(destination);
// Add all the matching messages in the queue to the synchronized(pagedInMessages){
// subscription. // Add all the matching messages in the queue to the
for(Iterator i=pagedInMessages.iterator();i.hasNext();){ // subscription.
QueueMessageReference node=(QueueMessageReference)i.next(); for(Iterator i=pagedInMessages.iterator();i.hasNext();){
if(node.isDropped()){ QueueMessageReference node=(QueueMessageReference)i.next();
continue; if(node.isDropped()){
} continue;
try{ }
msgContext.setMessageReference(node); try{
if(sub.matches(node,msgContext)){ msgContext.setMessageReference(node);
sub.add(node); if(sub.matches(node,msgContext)){
} sub.add(node);
}catch(IOException e){ }
log.warn("Could not load message: "+e,e); }catch(IOException e){
} log.warn("Could not load message: "+e,e);
} }
}
}
} finally {
dispatchValve.turnOn();
} }
}finally{ }finally{
msgContext.clear(); msgContext.clear();
dispatchValve.turnOn();
} }
} }
@ -251,7 +257,6 @@ public class Queue implements Destination, Task {
// while // while
// removing up a subscription. // removing up a subscription.
dispatchValve.turnOff(); dispatchValve.turnOff();
try { try {
synchronized (consumers) { synchronized (consumers) {
@ -353,10 +358,12 @@ public class Queue implements Destination, Task {
final ConnectionContext context = producerExchange.getConnectionContext(); final ConnectionContext context = producerExchange.getConnectionContext();
// 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.
final boolean sendProducerAck = ( !message.isResponseRequired() || producerExchange.getProducerState().getInfo().getWindowSize() > 0 ) && !context.isInRecoveryMode();
if(message.isExpired()){ if(message.isExpired()){
broker.messageExpired(context,message); broker.messageExpired(context,message);
destinationStatistics.getMessages().decrement(); destinationStatistics.getMessages().decrement();
if( ( !message.isResponseRequired() || producerExchange.getProducerState().getInfo().getWindowSize() > 0 ) && !context.isInRecoveryMode() ) { if( sendProducerAck ) {
ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize()); ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize());
context.getConnection().dispatchAsync(ack); context.getConnection().dispatchAsync(ack);
} }
@ -373,24 +380,28 @@ public class Queue implements Destination, Task {
synchronized( messagesWaitingForSpace ) { synchronized( messagesWaitingForSpace ) {
messagesWaitingForSpace.add(new Runnable() { messagesWaitingForSpace.add(new Runnable() {
public void run() { public void run() {
// While waiting for space to free up... the message may have expired.
if(message.isExpired()){
broker.messageExpired(context,message);
destinationStatistics.getMessages().decrement();
if( !message.isResponseRequired() && !context.isInRecoveryMode() ) {
ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize());
context.getConnection().dispatchAsync(ack);
}
return;
}
try { try {
doMessageSend(producerExchange, message);
// While waiting for space to free up... the message may have expired.
if(message.isExpired()) {
broker.messageExpired(context,message);
destinationStatistics.getMessages().decrement();
} else {
doMessageSend(producerExchange, message);
}
if( sendProducerAck ) {
ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize());
context.getConnection().dispatchAsync(ack);
} else {
Response response = new Response();
response.setCorrelationId(message.getCommandId());
context.getConnection().dispatchAsync(response);
}
} catch (Exception e) { } catch (Exception e) {
if( message.isResponseRequired() && !context.isInRecoveryMode() ) { if( !sendProducerAck && !context.isInRecoveryMode() ) {
ExceptionResponse response = new ExceptionResponse(e); ExceptionResponse response = new ExceptionResponse(e);
response.setCorrelationId(message.getCommandId()); response.setCorrelationId(message.getCommandId());
context.getConnection().dispatchAsync(response); context.getConnection().dispatchAsync(response);
@ -428,6 +439,10 @@ public class Queue implements Destination, Task {
} }
} }
doMessageSend(producerExchange, message); doMessageSend(producerExchange, message);
if( sendProducerAck ) {
ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize());
context.getConnection().dispatchAsync(ack);
}
} }
void doMessageSend(final ProducerBrokerExchange producerExchange, final Message message) throws IOException, Exception { void doMessageSend(final ProducerBrokerExchange producerExchange, final Message message) throws IOException, Exception {
@ -436,10 +451,6 @@ public class Queue implements Destination, Task {
if(store!=null&&message.isPersistent()){ if(store!=null&&message.isPersistent()){
store.addMessage(context,message); store.addMessage(context,message);
} }
if( ( !message.isResponseRequired() || producerExchange.getProducerState().getInfo().getWindowSize() > 0 ) && !context.isInRecoveryMode() ) {
ProducerAck ack = new ProducerAck(producerExchange.getProducerState().getInfo().getProducerId(), message.getSize());
context.getConnection().dispatchAsync(ack);
}
if(context.isInTransaction()){ if(context.isInTransaction()){
// If this is a transacted message.. increase the usage now so that a big TX does not blow up // If this is a transacted message.. increase the usage now so that a big TX does not blow up
// our memory. This increment is decremented once the tx finishes.. // our memory. This increment is decremented once the tx finishes..
@ -986,6 +997,7 @@ public class Queue implements Destination, Task {
} }
private List doPageIn(boolean force) throws Exception{ private List doPageIn(boolean force) throws Exception{
final int toPageIn=maximumPagedInMessages-pagedInMessages.size(); final int toPageIn=maximumPagedInMessages-pagedInMessages.size();
List result=null; List result=null;
if((force||!consumers.isEmpty())&&toPageIn>0){ if((force||!consumers.isEmpty())&&toPageIn>0){
@ -995,6 +1007,7 @@ public class Queue implements Destination, Task {
int count=0; int count=0;
result=new ArrayList(toPageIn); result=new ArrayList(toPageIn);
synchronized(messages){ synchronized(messages){
try{ try{
messages.reset(); messages.reset();
while(messages.hasNext()&&count<toPageIn){ while(messages.hasNext()&&count<toPageIn){