7 Replies Latest reply on May 30, 2008 11:36 AM by Adrian Brock

    XA Recovery of messages sent  to a Topic

    Michael Musgrove Master

      I am testing/enabling XA transaction recovery for JBossMQs on version 4.2.3.GA of the app server and version 4_2_3_GA_SP of jbossts. When I send a message to a queue I see that the JBossMQ code saves the transaction id and message in its recovery tables. If I kill the AS just before running phase 2 of the commit then on restart the TM recovery code successfully recovers the XID for the failed branch by calling recover on the XAResource (associated with the XAQueueSession) and successfully replays the transaction.

      However, if do the same steps on a Topic, then calling recover on the XAResource (associated with the XATopicSession) does not return any XID.

      My question is, should JBossMQ support recovery of messages sent to a Topic within an XA transaction.

        • 1. Re: XA Recovery of messages sent  to a Topic
          Michael Musgrove Master

          Actually, I did not install any durable subscribers for the Topic and consequently there was nothing to recover. When I added a durable subscriber and retested then the recovery system did indeed recover the message published to the topic.

          So the JBossMQ recovery support is working provided we register the appropriate JMS recovery provider (as per JIRA issue http://jira.jboss.org/jira/browse/JBTM-279).

          • 2. Re: XA Recovery of messages sent  to a Topic
            Michael Musgrove Master

            The remaining issue, then, is to do with how the JBossMQ XAResource handles non-durable subscriptions:

            If there are durable subscriptions for a topic then published messgages are put on a peristent queue otherwise a temporary queue is used (see method JMSTopic.addMessage(...)). It appears that only messages put on a peristent queue are recoverable.

            However, all messages are associated with the transaction (see SpyXAResourceManager.addMessage(...)) and the SpyXAResourceManager.prepare(...) method will only return XAResource.XA_RDONLYif there are no messages associated with the transaction (see TXState.isReadOnly()). The correct behaviour should be to check if there are any messages on any persistent queues associated with the transaction when determining whether this particular transaction branch is read only.

            This is a problem for TM recovery since the XAResource a for temporary topic queue does not return XAResource.XA_RDONLY for the prepare phase. Thus when the TM calls recover on the resource no xids are returned and hence the transaction can never be recovered.

            Could anyone hazzard a guess as to how much effort would be involved in resolving this issue.

            • 3. Re: XA Recovery of messages sent  to a Topic
              Michael Musgrove Master

              The XAResource should not return XA_RDONLY because the Resource needs to see the commit, otherwise any temporary subscribers would miss any messages published to the topic within the transaction. I'm not sure what the correct solution should be but I have raised a JIRA task (JBMESSAGING-1282) to test whether JBoss Messaging has the same issues.

              • 4. Re: XA Recovery of messages sent  to a Topic
                Adrian Brock Master

                 

                "mmusgrov" wrote:

                This is a problem for TM recovery since the XAResource a for temporary topic queue does not return XAResource.XA_RDONLY for the prepare phase. Thus when the TM calls recover on the resource no xids are returned and hence the transaction can never be recovered.


                I don't understand this? If JBossMQ doesn't return the XID then the TM
                must assume it was committed.


                Could anyone hazzard a guess as to how much effort would be involved in resolving this issue.


                It would however be a good optimization to return read only in this case.
                (Read Only i s an optimization which is why the behaviour you describe is not a bug).

                The PersistenceManager knows whether
                it wrote anything to the transaction log (database).
                i.e. it could do org.jboss.mq.pm.Tx.checkPersisted()
                but unfortunately the ServerIL has no way to return this information to the client.

                • 5. Re: XA Recovery of messages sent  to a Topic
                  Michael Musgrove Master

                  I seem to be having trouble posting to this forum - here's another go (sorry if it comes through multiple times):

                  I don't understand this? If JBossMQ doesn't return the XID then the TM
                  must assume it was committed.


                  If the JBossMQ unilaterally rolls the transaction forward after the prepare it should remember its decision - the spec says "The RM cannot discard its knowledge of such a branch until the TM permits this by calling xa_forget () for each branch."

                  This problem only arises with temporary subscriptions since the PersistenceManager does not write anything to the transaction log in this case. Perhaps this is the real issue - shouldn't the PersistenceManager write recovery information during prepare even for temporary subscriptions, otherwise it cannot fulfill the contract specified in the XA spec.

                  • 6. Re: XA Recovery of messages sent  to a Topic
                    Adrian Brock Master

                    Ok, I see the problem. So there's two ways to fix it.

                    1) We come up with some mechanism where the ServerIL's transact() request
                    can vote READONLY in this case.

                    This would require a mixin interface like the Recovery interface
                    such that newer clients can take advantage of it.

                    i.e. something like

                    public interface NewTxProtocol
                    {
                     TransactionResult transact2(ConnectionToken dc, TransactionRequest t) throws Exception;
                    }
                    
                    with the necessary knock on changes throughout the Invoker layer.
                    
                    Then have the client side can use it (if the server side supports it)
                    
                    org.jboss.mq.Connection;
                     protected TransactionResult send(TransactionRequest transaction) throws JMSException
                     {
                     checkClosed();
                     if (trace)
                     log.trace("Transact request=" + transaction + " " + this);
                    
                     try
                     {
                     if (serverIL instanceof NewTxProtocol)
                     {
                     return serverIL.transact2(connectionToken, transaction);
                     }
                     else
                     {
                     serverIL.transact2(connectionToken, transaction);
                     return null;
                     }
                     }
                     catch (Throwable t)
                     {
                     SpyJMSException.rethrowAsJMSException("Cannot process a transaction", t);
                     }
                     }
                    
                    


                    2) We disable the lazy insert of the tx record in the jdbc2 persistence manager
                    when it is a real XID.

                    (2) is obviously easier, but it is not as efficient as (1).

                    I'll do (2) but do you want to have a go at trying to do (1) ?