Author: rgodfrey
Date: Tue Nov 10 11:09:02 2015
New Revision: 1713610

URL: http://svn.apache.org/viewvc?rev=1713610&view=rev
Log:
QPID-6820 : State change listeners on non-acquired messages do not get removed 
when consumers are closed

Modified:
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
    
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java?rev=1713610&r1=1713609&r2=1713610&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
 Tue Nov 10 11:09:02 2015
@@ -2215,7 +2215,8 @@ public abstract class AbstractQueue<X ex
                         //QPID-1187 - Treat the consumer as suspended for this 
message
                         // and wait for the message to be removed to continue 
delivery.
                         subActive = false;
-                        node.addStateChangeListener(new 
QueueEntryListener(sub));
+                        sub.awaitCredit(node);
+
                     }
                 }
 
@@ -2625,34 +2626,6 @@ public abstract class AbstractQueue<X ex
         }
     }
 
-    private final class QueueEntryListener implements 
StateChangeListener<MessageInstance, QueueEntry.State>
-    {
-
-        private final QueueConsumer<?> _sub;
-
-        public QueueEntryListener(final QueueConsumer<?> sub)
-        {
-            _sub = sub;
-        }
-
-        public boolean equals(Object o)
-        {
-            return o instanceof AbstractQueue.QueueEntryListener
-                    && _sub == ((QueueEntryListener) o)._sub;
-        }
-
-        public int hashCode()
-        {
-            return System.identityHashCode(_sub);
-        }
-
-        public void stateChanged(MessageInstance entry, QueueEntry.State 
oldSate, QueueEntry.State newState)
-        {
-            entry.removeStateChangeListener(this);
-            deliverAsync();
-        }
-    }
-
     public List<Long> getMessagesOnTheQueue(int num)
     {
         return getMessagesOnTheQueue(num, 0);

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java?rev=1713610&r1=1713609&r2=1713610&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
 Tue Nov 10 11:09:02 2015
@@ -51,4 +51,5 @@ public interface QueueConsumer<X extends
 
     QueueContext getQueueContext();
 
+    void awaitCredit(QueueEntry entry);
 }

Modified: 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
URL: 
http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java?rev=1713610&r1=1713609&r2=1713610&view=diff
==============================================================================
--- 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
 (original)
+++ 
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
 Tue Nov 10 11:09:02 2015
@@ -31,6 +31,7 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,6 +71,7 @@ class QueueConsumerImpl
     private final long _consumerNumber;
     private final long _createTime = System.currentTimeMillis();
     private final MessageInstance.ConsumerAcquiredState<QueueConsumerImpl> 
_owningState = new 
MessageInstance.ConsumerAcquiredState<QueueConsumerImpl>(this);
+    private final WaitingOnCreditMessageListener 
_waitingOnCreditMessageListener = new WaitingOnCreditMessageListener();
     private final boolean _acquires;
     private final boolean _seesRequeues;
     private final boolean _isTransient;
@@ -235,6 +237,12 @@ class QueueConsumerImpl
     }
 
     @Override
+    public void awaitCredit(final QueueEntry node)
+    {
+        _waitingOnCreditMessageListener.update(node);
+    }
+
+    @Override
     public void externalStateChange()
     {
         _queue.deliverAsync();
@@ -278,6 +286,7 @@ class QueueConsumerImpl
             _target.getSendLock();
             try
             {
+                _waitingOnCreditMessageListener.remove();
                 _target.consumerRemoved(this);
                 _target.removeStateChangeListener(_listener);
                 _queue.unregisterConsumer(this);
@@ -617,4 +626,44 @@ class QueueConsumerImpl
     {
         return _queue.getEventLogger();
     }
+
+    public class WaitingOnCreditMessageListener implements 
StateChangeListener<MessageInstance, QueueEntry.State>
+    {
+        private final AtomicReference<MessageInstance> _entry = new 
AtomicReference<>();
+
+        public WaitingOnCreditMessageListener()
+        {
+        }
+
+        public void update(final MessageInstance entry)
+        {
+            remove();
+            // this only happens under send lock so only one thread can be 
setting to a non null value at any time
+            _entry.set(entry);
+            entry.addStateChangeListener(this);
+            if(!entry.isAvailable())
+            {
+                _queue.deliverAsync();
+                remove();
+            }
+        }
+
+        public void remove()
+        {
+            MessageInstance instance;
+            if((instance = _entry.getAndSet(null)) != null)
+            {
+                instance.removeStateChangeListener(this);
+            }
+
+        }
+
+        public void stateChanged(MessageInstance entry, QueueEntry.State 
oldSate, QueueEntry.State newState)
+        {
+            entry.removeStateChangeListener(this);
+            _entry.compareAndSet(entry, null);
+            _queue.deliverAsync();
+        }
+
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to