Working on https://jira.jboss.org/jira/browse/JBMESSAGING-1505 about delivery optimization for consumers with selectors.
The idea of the optimization is to provide to consumers with selectors their own iterators on the queue so that they don't have to rescan the whole queue to find messages which they can handle (when the filter match the message)
This means that:
- consumers with filters have an associated iterator that is used when the queue deliver messages
- consumers without filters will peek the messages from the queue
In order to distinguish between the 2 types of consumers, we need to peek the consumer which will handle the message from the distributor. I added a peekConsumer() to the Distributor interface to be able to do that.
This works fine for RoundRobinDistributor but it is broken for GroupingRoundRobinDistributor (in that case, it must know the message to determine which consumer will handle it).
As message groups and queues with selectors are not compatible, there are several options:
1/ forbids to use consumers with filters on a queue with message groups
2/ degrades the delivery algorithm in case of message groups with consumers with filters. In that case, the current algorithm is used (with a full scan of the queue for each call to deliver) (+ warning log)
I think (2) is a better option: this will give us the optimization in the most common case and handles the anti pattern case with a degradation of performance.
The only real con is that this means we maintain 2 delivery algorithm:
- an optimized one (round robin distribution)
- an degraded one (messages groups distribution + consumers with filters)
depending on the distribution policy type, when QueueImpl.deliver() is called we either use the deliverWithFullScan() (aka the current deliver algorithm) in the grouping distribution case or
deliverWithIterators() in the round robin case
Some remarks on the new optimized algorithm:
* when a consumer with filter has finished iterating on the queue, I reassigned to it a new messageReferences.iterator() so that it can handle new messages.
However this means it will iterate again on all the messages it has already discarded to reach the new messages
* in the case of consumers without filters, I peek directly from the messageReferences list to deliver. There is no need to have an iterator to share between all the consumers without filters