You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by "Pill, Juergen" <Ju...@softwareag.com> on 2001/01/19 17:02:57 UTC

XA transactions in a multi threaded environment

Hello Remy,

I have found a problem in an environment, where the client has multiple
threads, which accesses the same store. In this case we get following error:

Enlist error(Transaction 24 in Thread-10) = -9
com.softwareag.xdav.taminoStore.TaminoContentStore   Branch:
979917531812-0.5779716928292569-1 Flag: 0

And in sequence a exception at the commit.

I believe the problem lies in following fact:

The class ServiceImpl contains the method start with following code:

    public synchronized void start(Xid xid, int flags)
        throws XAException {
        
	if (xid == null)
	    throw new XAException(XAException.XAER_INVAL);
        if ( (currentContext != null) &&
             (currentContext.getGlobalTransactionId()
              != xid.getGlobalTransactionId()) )
            throw new XAException(XAException.XAER_OUTSIDE);

If the XID has been already set by a different thread (with a different TA
ID) this Exception will be thrown.

What do you think about following change:

The ServiceImpl class maintains a variable currentContexts, which is a
hashTable with as key the Thread (name). All the compares are based on that
hashTable entry. In this case the ServiceImpl class would handle multiple
TAs at one time. 

By the way, I think the start method should be synchronized.
What do you think about making the XIDs globalTAId based on the threads
name:


    public SlideTransaction() {
        // Generate the transaction id
        String idstr = System.currentTimeMillis() + "-" + Math.random();
        xid = new SlideXid(currentThreadName.getBytes(), 0, new byte[0]);
		globalCreatedTransactions++;
		currentTransactionNumber  = globalCreatedTransactions;
		currentThreadName         =
Thread.currentThread().getName();
    }


best regards

Juergen Pill

Re: XA transactions in a multi threaded environment

Posted by Remy Maucherat <re...@apache.org>.
> I have found a problem in an environment, where the client has multiple
> threads, which accesses the same store. In this case we get following
error:
>
> Enlist error(Transaction 24 in Thread-10) = -9
> com.softwareag.xdav.taminoStore.TaminoContentStore   Branch:
> 979917531812-0.5779716928292569-1 Flag: 0
>
> And in sequence a exception at the commit.
>
> I believe the problem lies in following fact:
>
> The class ServiceImpl contains the method start with following code:
>
>     public synchronized void start(Xid xid, int flags)
>         throws XAException {
>
> if (xid == null)
>     throw new XAException(XAException.XAER_INVAL);
>         if ( (currentContext != null) &&
>              (currentContext.getGlobalTransactionId()
>               != xid.getGlobalTransactionId()) )
>             throw new XAException(XAException.XAER_OUTSIDE);
>
> If the XID has been already set by a different thread (with a different TA
> ID) this Exception will be thrown.

It's normal that the service refuses to switch here (I wonder if the
exception you say is thrown is normal OTOH).
The ServiceImpl class (which is now gone) is meant to help implement simple
stores, where having to rollback is already hard enough to implement (the
file content store is a good example of this). That's why here I refuse to
switch a context to a new transaction until the first transaction is
complete. Of course, that doesn't scale.

On the other hand, with a real backend the context switch should definitely
switch the context.

To address all this I did the following :
- The old ServiceImpl has been renamed to AbstractSimpleService.
- Your new abstract implementation of Service is AbstractService.
- A third one has been added : AbstractXAService, which can be used when
implementing a store on top of a XA compliant resource manager, and doesn't
actually do anything since the XA calls will be forwarded to the underlying
resource manager.

> By the way, I think the start method should be synchronized.

Probably.

> What do you think about making the XIDs globalTAId based on the threads
> name:
>
>
>     public SlideTransaction() {
>         // Generate the transaction id
>         String idstr = System.currentTimeMillis() + "-" + Math.random();
>         xid = new SlideXid(currentThreadName.getBytes(), 0, new byte[0]);
> globalCreatedTransactions++;
> currentTransactionNumber  = globalCreatedTransactions;
> currentThreadName         =
> Thread.currentThread().getName();
>     }

I think the id should be as global and unique as possible, so it is now
constructed in the following way :
Id = threadName-timestamp-currentTransactionNumber

Is it ok ?

Remy