Here is the description of the problem.

tx -- javax.transactins.Transaction interface
tm -- javax.transaction.TransactionManager interface

First differences between Tyrex and JBossTM
                        JBossTM                 |Tyrex
tm.resume(null)         ok                      |throws exception
-------------------------------------------------------------------
tx.commit()             same as tm.commit()     |only commits the tx
                        i.e. drops the thread   |does not drop thread
                        association with tx     |association
same goes for tx.rollback()

1. When a thread comes in into TxInterceptorCMT the threadTx is suspended
and then resumed [b]_only_[/b] if it is not null (in 'finally' block).
(Note: we must check for it not to be null, because Tyrex throws
exception, actually the current code checks for this problem in some but
not all places, see the last paragraph).

2. In TX_REQUIRED, if the method invocation came w/o transaction
(oldTransaction == null) we start a new transaction. Then, in 'finally'
block we try to commit this transaction through Transaction.commit(). I
understand why we don't use TransactionManager.commit(), because our
thread may no longer be associated with the newTransaction. 

Problem arises with Tyrex when

(This happened when a servlet in Jetty was calling 2 methods of a bean
consequently)
Thread T calls a bean 2 times, both methods have TX_REQUIRED. Initially
thread T is not associated with a transaction (i.e. threadTx is null)

invocation 1
GenericProxy gets current thread transaction (null) and invokes the bean.
oldTransaction is null, thus according to (2) newTransaction
(Tx1) is started and then committed through Transaction.commit(). Thread T
is still associated with Tx1 if Tyrex is the TM. When we reach 'finally'
block that has to reinstate the threadTx, nothing happens because threadTx
is null, so T leaves the interceptor associated with Tx1 which is
committed.

invocation 2
GenericProxy gets the transaction associated with the current thread, i.e.
Tx1 and calls the bean with this tx context. oldTransaction == Tx1, the
transaction manager tries to resume the transaction ---> Exception, the
transaction is already committed.

So, the lesson is, the thread has to leave the interceptor with exactly
the same tx association it came in. Because threadTx can be null, we don't
always resume threadTx, so if threadTx was null when the thread came in,
it must be null when the thread leaves, so if the transaction manager does
not clean tx thread association through Transaction.commit() and
Transaction.rollback(), it must be cleaned by the interceptor through
tm.suspend() to make threadTx null again.  

The changes to the interceptor are trivial (always call tm.suspend, even
if committing or rolling back the new transcation). Also, in
TX_SUPPORTS, there has to be 
if (oldTransaction != null)
guard befor tm.resume(oldTransaction) is called, otherwise Tyrex is pissed
off :)

Hope the explanation is clear.

-------------------------------------------------------------------------
Anatoly Akkerman
Computer Science Dept.
Courant Institute of Mathematical Sciences, NYU
715 Broadway, #719                      Tel: 212 998-3493
New York, NY 10003                      Fax: 212 995-4123
-------------------------------------------------------------------------



_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to