5 Replies Latest reply on Aug 30, 2005 2:27 PM by Adrian Brock

    Transaction manager question

    Tim Fox Master

      Currently each JMS server peer uses the services of a javax.transaction.TransactionManager to co-ordinate work in the transaction, including the database resources and sending/acking messages. This differs from JBossMQ where the transaction manager used in the jms server org.jboss.mq.pm.TxManager was not an a subtype of javax.transaction.TransactionManager, i.e. it's a roll-your-own.

      When we run the new JMS server peer inside a JBoss AS instance, currently we are using the *same* instance of javax.transaction.TransactionManager as used by other parts of JBoss (i.e. we look it up from JNDI), so when we need to do some work inside a tx in the JMS server, it's quite likely there's already a tx associated to the current thread, e.g. if some messages were sent/acked from a transacted session in a transacted ejb method.

      Currently I've dealt with this inside the JMS server by suspending the current tx if there is one on the thread, and resuming it after work has been done on the JMS tx.

      This seems to work fine, but I was thinking perhaps the suspend/resume overhead might be something we could avoid if the JMS server used it's own instance of the JBoss transaction manager rather than sharing one.

      Which approach do you think is best? Or maybe there's some other better way to do this?

        • 1. Re: Transaction manager question
          Scott Stark Master

          What about the tx logging/recovery being developed in head? If you want to participate in that you would want to use the server tm. The legacy approach can be used by developing an alternate TxManager that is based on the JTA version and allowing the TxManager to be plugged in.

          • 2. Re: Transaction manager question
            Adrian Brock Master

            The name TxManager in JBossMQ is misleading.
            It should be TxRepository or something like it.

            I don't understand why you are using a JTA transaction manager?
            Is this intended to support things like bridging where you need 2PC?
            Are you trying to become a sub-coordinater?

            JMS is a "local" branch of a JTA transaction.
            i.e. it exposes an XAResource which is driven by an external JTA transaction.

            JTA Transaction -> JMSXAResource -> local branch prepare/commit logging

            You should be writing what the spec calls a ResourceManager not a TransactionManager.

            A resource manager does keep track of transactions
            (to hold the association: xid->data)
            it doesn't control the transaction or keep track of thread association, etc.

            It is a "slave", unless it is doing heuristics. :-)

            • 3. Re: Transaction manager question
              Ovidiu Feodorov Master

              I am using the JT API. The TransactionManager doesn't necessarily have to be the JBoss TransactionManager. It is just a mechanism to associate something with the current thread and a way to start, commit or rollback a transaction.

              • 4. Re: Transaction manager question
                Tim Fox Master

                Interesting discussion.

                We don't really *need* a JTA transaction manager on the server side, as Adrian has pointed out.

                However it does provide some usefuly hooks via the Synchronization interface so we can do the stuff that we need to do at prepare and commit time, rather than rolling our own.

                (The XA resource transaction logging is currently not implemented for prepare and commit so I've added a JIRA task for that.)

                We're not currently enrolling any XAResources into this transaction manager instance, so it's role for us is really just as a way of managing what we have to do at prepare and commit time in order to satisfy the XA protocol from the resources point of view.

                Currently we are actually using the same *instance* of the transaction manager as used by jboss as. (we're looking it up from the well known JNDI name)

                I think perhaps it would be better for the jms server to have it's own private instance so we can avoid suspend and resume calls as mentioned previously.

                Tim

                • 5. Re: Transaction manager question
                  Adrian Brock Master

                  But a JTA transation manager is overkill for what you are doing.
                  The logging is very different for a start.

                  All you need is an xid -> resource/synchronization map like JBossMQ.
                  Where resource is local tx state (logically added and acknowledged messages).

                  This is the one piece of JBossMQ that is actually done well,
                  although it is missing any sort of management exposure.

                  I don't like the idea of passing tx context in a thread local.
                  They serve different purposes.

                  JTA Transaction = Logical unit of work that holds links to the real resources + other things
                  It is a thread local such that it can pass under application interfaces.

                  Local Transaction = Real state
                  This should be passed explicitly in the ResourceManager protocol's. Its never "in context"
                  during the application. In fact, the TM can invoke on the ResourceManager in
                  fairly complicated ways.

                  tm.begin();
                  Transaction tx1 = tm.getTransaction();
                  tx1.enlistResource(jms1);
                  tx1.delistResource(jms1);
                  tx1.enlistResource(jms2); // Two jms xaresources for the same transaction
                  tx1.delistResource(jms2);
                  tm.suspend(); // No thread local transaction
                  tm.begin();
                  Transation tx2 = tm.getTransaction();
                  tx2.enlistResource(jms1); // Resource is now associated with a different tx
                  tx1.commit(); // But can still commit with the old XID