Mantis - Resin
Viewing Issue Advanced Details
180 minor always 05-17-05 00:00 11-30-05 14:42
sam  
 
urgent  
closed 3.0.13  
3.0.13 fixed  
none    
none 3.0.15  
0000180: distributed xa oracle
RSN-180
(rep by P Ross)

In attempting to migrate some sample code from
weblogic to resin, I'm running into some problems
associating with distributed transaction handling. In
weblogic I create a pair of XA datasources and have a
small servlet that attempts to open one connection
from each XA datasource, enlist them in a user
transaction, execute a simple jdbc query on each
connection (a select statement), then commit the user
transaction.

My initial tests with this fairly simple scenario
failed with exceptions being thrown when simply
opening the second XAConnection. I removed the
querying parts altogether and simplified the scenario
down to simply looking up the user transaction,
beginning the transaction, getting the first
connection from the first xa datasource (which
succeeds), then getting the second connection, which
fails. Looking at the causes for he exception drills
down to the following hierachy:
java.lang.IllegalStateException
javax.transactions.SystemException
oracle.jdbc.xa.OracleXAException

I wrote some extra exception handling code to inspect
the oracle xa exception and found the following:
XAException error code --> -3
OracleXAException oracle error --> 24774
OracleXAException oracle sql error --> 0
OracleXAException xa error --> -3

When looking at the oracle error, I find this:
oerr ora 24774
24774, 00000, "cannot switch to specified transaction"
// *Cause: The transaction specified in the call
refers to a transaction
// created by a different user.
// *Action: Create transactions with the same
authentication so that they
// can be switched.


Researching this error, I found some Oracle
information discussing the difference between
tightly-coupled and loosely-coupled distributed
transactions, and only in the context of trying to
handle xa transactions across two different schemas in
the same oracle instance. This is exactly the
scenario I'm trying. The info in the oracle
documentation was sparse, but mentioned that forcing
loosely coupled transactions was required when using
distributed transactions across separate schemas in
the same instance, which can be done via a connection
property or an extra flag in the start method of the
XAResource class. I attempted to set the connection
in the datasource but could not figure out how to
accomplish this with Resin's datasource
configuration... so I decided to write thin wrappers
for XADataSource, XAConnection, and XAResource with
the intent of slipping in the flag Oracle mentions for
enabling loosely coupled transactions. The odd thing
is, simply wrapping these and configuring the
datasource to use the wrappers... the problem goes
away. Looking up both connections works, and adding
the querying back in gets a little further in the
tests case. Both queries execute and result sets can
be obtained, but a different exception is thrown on
the commit of the transaction:

com.caucho.transaction.RollbackExceptionWrapper
oracle.jdbc.xa.OracleXAException
XAException error code --> -4
OracleXAException oracle error --> 24756
OracleXAException oracle sql error --> 0
OracleXAException xa error --> -4

This time the Oracle error says the following:

oerr ora 24756
24756, 00000, "transaction does not exist"
// *Cause: An invalid transaction identifier or
context was used or the
// transaction has completed.
// *Action: Supply a valid identifier if the
transaction has not completed
// and retry the call.

I've done little to troubleshoot this, but I wonder if
this coule be happening because when doing selects,
there is nothing to update?

I'm wondering, why would using the wrappers act
differently. Is there maybe some introspection done
by Resin during transaction handling that looks to see
what the actual concrete implementations it is using
for datasource, connection, or xaresource objects?

<database>
        <jndi-name>jdbc/OracleXATest1</jndi-name>
        <xa>true</xa>
        <driver>

<!--<type>oracle.jdbc.xa.client.OracleXADataSource</type>-->

<type>com.pross.utils.j2ee.appsrv.OracleXADataSourceWrapper</type>

<url>jdbc:oracle:thin:@localhost:1521:db1</url>
            <user>xatest1</user>
            <password>xatest1</password>
        </driver>
        <ping-table>DUAL</ping-table>
        <ping>true</ping>

<prepared-statement-cache-size>256</prepared-statement-cache-size>
    </database>
    <database>
        <jndi-name>jdbc/OracleXATest2</jndi-name>
        <xa>true</xa>
        <driver>

<!--<type>oracle.jdbc.xa.client.OracleXADataSource</type>-->

<type>com.pross.utils.j2ee.appsrv.OracleXADataSourceWrapper</type>

<url>jdbc:oracle:thin:@localhost:1521:db1</url>
            <user>xatest2</user>
            <password>xatest2</password>
        </driver>
        <ping-table>DUAL</ping-table>
        <ping>true</ping>

<prepared-statement-cache-size>256</prepared-statement-cache-size>
    </database>


Notes
(0000207)
sam   
05-17-05 00:00   
(rep by P Ross)

A test that I did and forgot to mention in the
original report... having the two xa datasources in
Resin pointing to two different oracle instances seems
to work fine. The connection lookup and commit both
work fine. Only the scenario where two schemas of the
same instance fail.

After a good bit of testing with other app
servers, I've uncovered more interesting details, but
no conclusions. It seems that Orion server acts
almost the same way as Resin in that opening up a
second xa connection from a second xa datasource
throws the same exact error, but ONLY when not
wrapping the datasource with my simple wrapper. When
I use the wrapped versions, getting the second
connection works fine, and the final commit completes
OK. In Resin however, the final commit throws a
rollback exception, which is caused by an Oracle error
stating that the transaction does not exist.


Interestingly, I attempted the same tests on Jboss
4.0.2 and all cases work perfectly. Both wrapped and
unwrapped xadatasource/xaconnection/xaresource configs
work perfectly, both looking up the second connection
from the second datasource and committing the
transactions. I also did a little more testing to
make sure jboss was actually implementing the
transactions correctly, writing a little more test
code to do inserts and updates against both
datasources, and killing both the app server and
database with kill -9 type of commands. In every case
the transactions commited/rolledback/recovered
correctly and the data remained consistent. Although
I've noticed that Jboss does not implement xa recovery
so transactions are never rolled forward according to
what was in flight at the time of failure, but oracle
rolls the in-flight transactions back and keeps things
consistent.

An interesting thing I've seen in Jboss
configurations, there seems to be an outdated comment
talking about a special XA XID factory to use with
Oracle that "pads" the xid to a long format that
Oracle accepts. I've yet to look at Resin's XID
format but I'm thinking this might be a clue as to how
to get Resin to work with Oracle's XA as well.

And a final detail I uncovered... I mentioned earlier
about the loosely coupled transactions detail. Since
the xa handling seems to work ok in weblogic and
jboss, I decided to look at how Oraacle views the
transactions internally, and it appears that the
v$global_transaction view (where Oracle stores info
about in flight distributed transactions) always
reports that the transactions are tightly coupled.
That along with the bug report about jdbc loosely
coupled transaction states that the bug was resolved
in 10g. It might be the case that the loose versus
tight coupling is an issue in 10g (which is the
version we are using).
(0000208)
ferg   
05-17-05 00:00   
server/16f0,1,2,3