Description of problem: Assume there are two bindings from a header exchange towards the same durable queue. Sending a durable message to the exchange and matching both the bindings raises below exception in queue's journal. Version-Release number of selected component (if applicable): qpid-cpp-server-0.18-14 qpid-cpp-server-store-0.18-14 How reproducible: 100% Steps to Reproduce: rm -rf /var/lib/qpidd/* /var/lib/qpidd/.* 2> /dev/null service qpidd restart qpid-config add queue MyQueue --durable qpid-config bind amq.match MyQueue SomeKey any property1=value1 qpid-config bind amq.match MyQueue OtherKey all property2=value2 qpid-send -a "amq.match" -m 1 -P property1=value1 -P property2=value2 --durable=true Actual results: 2013-03-01 10:15:54 [Client] warning Broker closed connection: 501, Queue MyQueue: MessageStoreImpl::store() failed: jexception 0x0b00 wmgr::enqueue() threw JERR_MAP_DUPLICATE: Attempted to insert record into map using duplicate key. (rid=0x1 _pfid=0x0) (MessageStoreImpl.cpp:1361) qpid-send: framing-error: Queue MyQueue: MessageStoreImpl::store() failed: jexception 0x0b00 wmgr::enqueue() threw JERR_MAP_DUPLICATE: Attempted to insert record into map using duplicate key. (rid=0x1 _pfid=0x0) (MessageStoreImpl.cpp:1361) Expected results: No such exception. Additional info: Curiously, when sending transient message (or to transient queue), one message sent triggers _two_ messages stored in the queue. Is that intentional? As this is inconsistency. Doing equivalent example but for topic exchange instead of headers, only _one_ message ends in the queue. Therefore it is a question what should be correct: - two messages should be kept in the queue, as simply following mathematical / logical rules, the exchange gets a message, and for each binding matched, it sends the message to the destination queue - the message should be kept in the queue only once, as there is no reason to enqueue there two copies of the same message - what a consumer would gain from two copies? That would be rather redundant than usefull.. Resolving the dilema above is prerequisite to resolving this bug.
Effective workaround: prevent having more bindings from a headers exchange to the same queue such that a message can match more bindings. Example: instead of having: $ qpid-config bind amq.match MyQueue MyQueue.1 all prop1=1 prop2=1 $ qpid-config bind amq.match MyQueue MyQueue.2 all prop1=1 prop3=1 where a message with properties prop1=1 and prop2=1 and prop3=1 matches both bindings, change the bindings to: $ qpid-config bind amq.match MyQueue MyQueue.1 all prop1=1 prop2=1 $ qpid-config bind amq.match MyQueue MyQueue.2 all prop1=1 prop3=1 prop2!=1 Now, with the new restriction on second binding, the bindings have mutually exclusive binding keys.
Created attachment 834835 [details] Patch proposal Patch proposal - simple but maybe not ideal. Root cause of the bug: HeadersExchange::route method generates BindingList that may contain multiple bindings to the same queue. That causes a message to be enqueued to the same queue more than once. The patch sorts+makes unique the BindingList by using std::map < Queue , Binding > (boost pointers in fact). Maybe there is more elegant way of doing so, anyway this patch fixes the problem (no automated tests run so far).
(In reply to Pavel Moravec from comment #3) > Created attachment 834835 [details] > Patch proposal > > Patch proposal - simple but maybe not ideal. > > Root cause of the bug: HeadersExchange::route method generates BindingList > that may contain multiple bindings to the same queue. That causes a message > to be enqueued to the same queue more than once. > > The patch sorts+makes unique the BindingList by using std::map < Queue , > Binding > (boost pointers in fact). Maybe there is more elegant way of doing > so, anyway this patch fixes the problem (no automated tests run so far). FYI the bug is _not_ in store but in broker itself. Per gsim, a message matching multiple bindings to same queue should be enqueued just once to the queue. That is now fixed by the patch for headers exchange.
Upstream review request: https://reviews.apache.org/r/17641/
Committed to upstream: r1563863.
This bug is UNABLE TO REPRODUCE with: qpid-cpp-server-0.18-14 and qpid-cpp-server-store-0.18-14 on RHEL x86_64 There is no such exception.
I managed to reproduce the issue with qpid-cpp-0.18-36 with use of our testing clients. Unfortunatelly I cannot find a reason why qpid-send do not cause the issue. Issue was tested on RHEL 6.6, RHEL 7.1 with following packages: python-qpid-0.30-6 python-qpid-qmf-0.30-6 qpid-tools-0.30-5 qpid-cpp-server-linearstore-0.30-8 qpid-proton-c-0.9-2 qpid-cpp-server-0.30-8 qpid-cpp-client-devel-0.30-8 qpid-qmf-0.30-6 qpid-java-common-0.30-5 qpid-java-example-0.30-5 qpid-cpp-server-rdma-0.30-8 qpid-cpp-server-ha-0.30-8 qpid-cpp-server-xml-0.30-8 qpid-cpp-client-devel-docs-0.30-8 qpid-cpp-client-0.30-8 qpid-cpp-client-rdma-0.30-8 qpid-java-client-0.30-5 qpid-cpp-server-devel-0.30-8 qpid-cpp-debuginfo-0.30-8 Bindings work as expected (Comment 9). -> VERIFIED
Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://rhn.redhat.com/errata/RHEA-2015-0805.html