Question about XAResourceManager code

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Question about XAResourceManager code

Frugoletto
Hi all,

I've started to enjoy BTM, which I found very good, until I run into a strange problem with Postgresql.
Sometimes I got an exception from the PG driver wich states 'Transaction interleaving not supported'. Digging into the source I found that this is thrown when the driver is asked to join on a xid which is not the same passed when was asked to start.
A little bit digging in the trunk source of btm and I found this snippet in XAResourceManager...

    private XAResourceHolderState getManagedResourceWithSameRM(XAResourceHolderState xaResourceHolderState) throws XAException {
        if (!xaResourceHolderState.getUseTmJoin()) {
            if (log.isDebugEnabled()) log.debug("join disabled on resource " + xaResourceHolderState);
            return null;
        }

        Iterator it = resources.iterator();
        while (it.hasNext()) {
            XAResourceHolderState alreadyEnlistedHolderState = (XAResourceHolderState) it.next();

            if (log.isDebugEnabled()) log.debug("checking joinability of " + alreadyEnlistedHolderState + " with " + alreadyEnlistedHolderState);
            if (alreadyEnlistedHolderState.getXAResource().isSameRM(alreadyEnlistedHolderState.getXAResource()) && alreadyEnlistedHolderState.isEnded()) {
                if (log.isDebugEnabled()) log.debug("resources are joinable");
                return alreadyEnlistedHolderState;
            }
            if (log.isDebugEnabled()) log.debug("resources are not joinable");
        }
       
        if (log.isDebugEnabled()) log.debug("no joinable resource found for " + xaResourceHolderState);
        return null;
    }


now the question is: should not the check

if (alreadyEnlistedHolderState.getXAResource().isSameRM(alreadyEnlistedHolderState.getXAResource()) && alreadyEnlistedHolderState.isEnded()) {

read

if (alreadyEnlistedHolderState.getXAResource().isSameRM(xaResourceHolderState.getXAResource()) && alreadyEnlistedHolderState.isEnded()) {

? Patching the code and rebuilding make my strange PG errors disappear... Are my assumption correct or I am breaking something?

Cheers, R.
Reply | Threaded
Open this post in threaded view
|

Re: Question about XAResourceManager code

Ludovic Orban
Administrator
Hi,

Indeed you've found a bug and you're right about how the logic should work, thanks for reporting it. Could you please open a JIRA issue so I can keep track of it ?

Now I wonder how you could have found this bug using Postgresql. The alreadyEnlistedHolderState.isEnded() call returns true only when transaction interleaving is enabled on a resource (ie: when deferConnectionRelease is set to false) which you should not enable with Postgresql.

I'm a bit worried about the way things are working in your use case so I'd be grateful if you could send me a debug trace so I can check in details if something else is wrong in BTM, the Postgresql driver or in your application / configuration.

Thanks,
Ludovic
Reply | Threaded
Open this post in threaded view
|

Re: Question about XAResourceManager code

Frugoletto
Ok, no problem.

Here it is:

http://jira.codehaus.org/browse/BTM-20

may the "strangeness" of my use case be related to the fact that I use lots of beans which needs to be run in JTA and non-JTA cases and so wrapped with "required" spring's tx advices?

Thank you very much,

R.


Ludovic Orban wrote
Hi,

Indeed you've found a bug and you're right about how the logic should work, thanks for reporting it. Could you please open a JIRA issue so I can keep track of it ?

Now I wonder how you could have found this bug using Postgresql. The alreadyEnlistedHolderState.isEnded() call returns true only when transaction interleaving is enabled on a resource (ie: when deferConnectionRelease is set to false) which you should not enable with Postgresql.

I'm a bit worried about the way things are working in your use case so I'd be grateful if you could send me a debug trace so I can check in details if something else is wrong in BTM, the Postgresql driver or in your application / configuration.

Thanks,
Ludovic
Reply | Threaded
Open this post in threaded view
|

Re: Question about XAResourceManager code

Ludovic Orban
Administrator
Hi,

This bug is now fixed. Indeed, you were right: the incorrect isSameRM() call was the cause.

I've spent some time analyzing your logs to try to understand how this problem can happen and why it did not pop up earlier. I've managed to figure it out and create a test that reproduces the problem.

The only way to run into it is to follow this flow:

tm.begin()

c1 = ds1.getConnection();
// some SQL
c1.close();

c2 = ds2.getConnection();
// some SQL
c2.close();

tx = tm.suspend();
...
tm.resume(tx);

c3 = ds2.getConnection();
// some SQL
c3.close();

c4 = ds1.getConnection();
// some SQL
c4.close();

commit();


You must first acquire a connection from two different pools, then suspend the current connection then reacquire connections from the exact same pool but in reverse order, only then can you run into that bug.

This explains why it's been lying in the code for so long as this is not a very common case.

You can either build from the sources to get the fix or download a pre-built version here: http://snapshots.repository.codehaus.org/org/codehaus/btm/btm/1.3-beta3-20080527/

Thanks for the report,
Ludovic