Re: XA end then join fix for WebLogic - Mailing list pgsql-jdbc

From ludovic orban
Subject Re: XA end then join fix for WebLogic
Date
Msg-id c016d00b0611010202m3438da13t4035164c822f1b78@mail.gmail.com
Whole thread Raw
In response to XA end then join fix for WebLogic  (Heikki Linnakangas <heikki@enterprisedb.com>)
List pgsql-jdbc
Heikki,

You wondered why Weblogic calls XAResource.start(TMJOIN) in this post:
http://archives.postgresql.org/pgsql-jdbc/2006-10/msg00011.php

I'm going to try to explain you why that's happening in this email.
Please note that this explanation is solely based on my personal
observations of multiple transaction managers/app servers. I'm writing
this from the top of my head so I may have done a few mistakes.


*** deep breathe, this is long and complex ***


The transaction manager is not the masterpiece of this puzzle, the
XADataSource wrapper (that usually provides pooling and exposes a
(non-XA) DataSource interface) is. The way resources are
enlisted/delisted depends on a chosen enlistment policy. Unfortunately
the JTA spec leaves much to desire on this subject: there is not a
single line describing how enlistment should be performed nor any kind
of recommendation.

Implementors are left on their own to choose an implementation and you
basically have two major enlistment policies: on statement creation
and on connection acquirement. Websphere and Atomikos
TransactionsEssentials implement the second policy. Weblogic and
Bitronix TM implement the first one.

The biggest advantage of the 'on connection acquirement' one is that
it's much (much, much, much !) easier to implement and works plain
fine 9 times out of 10. This one calls XAResource.start(TMNOFLAGS)
when XADataSource.getConnection() is called and
XAResource.end(TMSUCCESS) when TransactionManager.commit() is called.

The 'on statement creation' one, while more complex to write is more
flexible (end-user wise) and is generally more performant when used
with databases fully supporting transaction interleaving. This one
calls XAResource.start(TMNOFLAGS) when Connection.createStatement() or
prepareStatement() or prepareCall() is called and
XAResource.end(TMSUCCESS) when Connection.close() is called.

For a good example of the increased flexibility you get with the 'on
statement creation' policy has been discussed by Dmitri Maximovich:
 http://www.jroller.com/page/maximdim?entry=is_xa_transaction_support_broken
Basically only implementations using 'on statement creation'
enlistment policy can support this special case.


Now what would be the difference between the two in terms of
XAResource calls ? Let's assume we have this small example:

 1 public void transactionalMethod() {
 2     tm.begin();
 3
 4     executeSQL();
 5     executeSQL();
 6
 7     tm.commit();
 8 }
 9
10 private void executeSQL() {
11     Connection c = getXADataSource().getConnection();
12     c.createStatement().executeUpdate("some SQL");
13     c.close();
14 }

With 'on connection acquirement':

line 11 (called by line 4): get a physical connection out of the
connection pool and call XAResource.start(TMNOFLAGS).
line 13 (called by line 4): mark the connection as 'not accessible'
and keep it out of the connection pool.
line 11 (called by line 5): get back the connection previously maked
as 'not accessible'.
line 13 (called by line 5): mark again the connection as 'not
accessible' but don't do anything else.
line 7: call XAResource.end(TMSUCCESS) on the connection's XAResource.
Requeue the connection into the pool.

How can line 11 (called by 5) get back the same connection that was
previously acquired ? Simply by looking at all the connections marked
as 'not accessible' and picking the one that has called
XAResource.start() with a XID that has the same GTRID as the current
global transaction's GTRID. If it can't find any this just means a new
connection should be acquired from the pool but in this example that
will never happen.


With 'on statement creation':

line 11 (called by line 4): nothing happens enlistment/delistment wise.
line 12 (called by line 4): XAResource.start(TMNOFLAGS) is called.
line 13 (called by line 4): XAResource.end(TMSUCCESS) is called and
the connection is requeued.
line 11 (called by line 5): nothing happens enlistment/delistment wise.
line 12 (called by line 5): XAResource.start(TMJOIN) is called.
line 13 (called by line 5): XAResource.end(TMSUCCESS) is called and
the connection is requeued.
line 7: nothing happens enlistment/delistment wise.

How can line 12 (called by 5) knows it should call XAResource.start()
with TMJOIN instead of TMNOFLAGS ? The TM must keep a list of
resources enlisted in the current transaction (-> XAConnections which
XAResource.start() has been called) and call
XAResource.isSameRm(currentXAResource) on all of them with
currentXAResource being the XAResource of the Connection acquired on
line 11 (called by 5). If isSameRm() returns true,
XAResource.start(TMJOIN) can be called but if it returns false
XAResource.start(TMNOFLAGS) should be called instead. TMJOIN is much
more performant as the database does not have to create a new
transaction branch and isolate work done on both connections: it just
works like if you called both executeUpdate() in the same local
transaction while with TMNOFLAGS the database has to create a new
branch and apply ACID semantics between the two executeUpdate() calls
since it has to treat the two branches as two unrelated local
transactions.


Of course, subtle variations can happen depending on a lot of
implementation-specific choices and potential configuration parameters
but this gives you the basic idea of what's happening under the cover.

Cheers,
Ludovic

pgsql-jdbc by date:

Previous
From: Heikki Linnakangas
Date:
Subject: Re: XA end then join fix for WebLogic
Next
From: "ludovic orban"
Date:
Subject: Re: XA end then join fix for WebLogic