Martin Ritchie wrote:
Hi Rafi,

I saw the syncDispatchQueue method but I don't think waiting for the
_queue to clear is not the right solution, IMO, for rollback, even on
0-10. When rollback is called you don't want the dispatcher to process
any more messages. Your client may have MessageListeners setup that
will take a long time to process, so the Dispatcher should stop
processing messages and perform the Rollback.

I've attached a new test for RollbackOrderTest that blocks because the
syncDispatchQueue waits for the Dispatcher to empty the _queue.
However, when called via the MessageListener.onMessage(), you end up
blocking the Dispatcher.

That's a good point, however won't this also be an issue in the design you're proposing? Regardless of which thread actually does the rollback processing, rollback needs to block until that processing is complete, and if you're waiting for the "ServiceRequest" to be processed from the thread that is supposed to process it then you have essentially the same deadlock you've attached below.

I think extracting the Dispatcher will make it clearer to show that
the message processing varies in each protocol and will allow the
Session classes to focus on the creation and control of
Consumer/Producers. This will allow Dispatchers for each protocol to
be cleaner and highlight the protocol differences at failover; A 0-8
Dispatcher that simply drops all pending messages compared to the 0-10
Dispatcher that attempts to process all the messages it has received.

I don't actually think any of this needs to be (or should be) protocol specific. AFAICT there's no relevant difference in the protocol semantics here, these issues are common to any protocol that does prefetch. For example, the choice of whether to drop or process pending messages in a given scenario could be made either way for any protocol version.

I think it is a significant change but I think it is worth it as it
will improve the readability of the Client code as well as improving
the testability. Currently AMQSession is not exactly easy to unit test
so splitting it in to more discrete components and unit testing them
will be beneficial.

The change boils down to:
- Extract Dispatcher Logic to Dispatcher_0_8 , Dispatcher_0_10
- Update AMQSession to use new Dispatcher
- Update Dispatcher to be able to stop processing the _queue of
messages and perform rollback.

I agree the client is badly in need of some improvements in maintainability and readability, however in this particular case I don't think moving the rollback processing from one thread to another actually improves the situation significantly. Fundamentally the rollback logic needs to be performed from at least two different threads, the dispatcher thread and the application thread. I suspect in order do this properly we really need to stop thinking in terms of code being associated with a given thread, and think instead about what locks we have, what data structures those locks protect, and which locks need to be held in order to execute a given piece of code.

In my experience the number one issue with the client is deadlocks and race conditions stemming from the large number of haphazardly defined locks/conditions that are littered throughout the client code. I think before we can safely and productively move large chunks of code around we really need to have some sort plan for documenting and simplifying the locking situation. Really we need to be able to articulate exactly what locks the client has, what data structure(s) each lock protects, and what order should be used to acquire multiple locks when necessary.

--Rafael

---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:dev-subscr...@qpid.apache.org

Reply via email to