[jboss-svn-commits] JBL Code SVN: r38238 - in labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310: ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator and 4 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Tue Oct 30 14:19:26 EDT 2012


Author: mmusgrov
Date: 2012-10-30 14:19:25 -0400 (Tue, 30 Oct 2012)
New Revision: 38238

Added:
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCommitThreadPool.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/resources/jta/
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/resources/jta/XAResourceRecord.java
Modified:
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncCommit.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncPrepare.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/BasicAction.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/XAResourceRecord.java
   labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/TransactionImple.java
Log:
JBTM-1310 Performance improvements (asynchronous prepare and in-lined JTS participant records)

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -42,6 +42,8 @@
     private volatile boolean maintainHeuristics = true;
     private volatile boolean transactionLog = false; // rename to useTransactionLog ?
 
+    private volatile int maxTwoPhaseCommitThreads = 100;
+
     // public static final String TRANSACTION_LOG_REMOVAL_MARKER = "com.arjuna.ats.arjuna.coordinator.transactionLog.removalMarker";
     //private String removalMarker;
 
@@ -146,6 +148,14 @@
         this.asyncRollback = asyncRollback;
     }
 
+    public int getMaxTwoPhaseCommitThreads() {
+        return maxTwoPhaseCommitThreads;
+    }
+
+    public void setMaxTwoPhaseCommitThreads(int maxTwoPhaseCommitThreads) {
+        this.maxTwoPhaseCommitThreads = maxTwoPhaseCommitThreads;
+    }
+
     /**
      * Returns true if one phase commit optimization is to be used.
      *

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncCommit.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncCommit.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncCommit.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -33,6 +33,8 @@
 
 import com.arjuna.ats.internal.arjuna.thread.ThreadActionData;
 
+import java.util.concurrent.Callable;
+
 /**
  * This class is responsible for performing asynchronous termination of
  * a transaction. Despite its name, it is also able to perform
@@ -48,32 +50,10 @@
  * Default visibility.
  */
 
-class AsyncCommit extends Thread
+class AsyncCommit implements Runnable
 {
-
-    /**
-     * Create a new instance, and give it the transaction to
-     * control. The commit parameter determines whether the thread
-     * should commit or rollback the transaction.
-     */
-
-public static AsyncCommit create (BasicAction toControl, boolean commit)
+ public void run() {
     {
-	AsyncCommit c = new AsyncCommit(toControl, commit);
-
-	c.start();
-
-	Thread.yield();
-
-	return c;
-    }
-
-    /**
-     * Overloads Thread.run
-     */
-    
-public void run ()
-    {
 	if (_theAction != null)
 	{
 	    /*
@@ -95,12 +75,15 @@
 	    ThreadActionData.popAction(false);
 	}
     }
+ }
 
+
     /**
-     * The actual constructor for a new instance.
+     * Create a new instance, and give it the transaction to
+     * control. The commit parameter determines whether the thread
+     * should commit or rollback the transaction.
      */
-
-protected AsyncCommit (BasicAction toControl, boolean commit)
+ AsyncCommit (BasicAction toControl, boolean commit)
     {
 	_theAction = toControl;
 	_commit = commit;
@@ -146,4 +129,4 @@
 private BasicAction _theAction;
 private boolean     _commit;
 
-};
+}

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncPrepare.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncPrepare.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/AsyncPrepare.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -33,6 +33,8 @@
 
 import com.arjuna.ats.internal.arjuna.thread.ThreadActionData;
 
+import java.util.concurrent.Callable;
+
 /**
  * Instances of this class are responsible for performing asynchronous
  * prepare on a specific AbstractRecord associated with a transaction.
@@ -45,56 +47,33 @@
 /*
  * Default visibility.
  */
+class AsyncPrepare implements Callable<Integer> {
+    public Integer call() throws Exception {
+        /*
+                   * This is a transient thread so we don't want to register it
+                   * with the action it is preparing, only change its notion of
+                   * the current transaction so that any abstract records that
+                   * need that information can still have it.
+                   */
 
-class AsyncPrepare extends Thread
-{
+        ThreadActionData.pushAction(_theAction, false);
 
-public static AsyncPrepare create (BasicAction act, boolean reportHeuristics,
-				   AbstractRecord rec)
-    {
-	return new AsyncPrepare(act, reportHeuristics, rec);
-    }
-    
-public void run ()
-    {
-	if (_theAction != null)
-	{
-	    /*
-	     * This is a transient thread so we don't
-	     * want to register it with the action it is
-	     * preparing, only change its notion of the
-	     * current transaction so that any abstract
-	     * records that need that information can still
-	     * have it.
-	     */
+        _outcome = _theAction.doPrepare(_reportHeuristics, _theRecord);
 
-	    ThreadActionData.pushAction(_theAction, false);
-	    
-	    _outcome = _theAction.doPrepare(_reportHeuristics, _theRecord);
+        ThreadActionData.popAction(false);
 
-	    ThreadActionData.popAction(false);
-	}
-
-	_theRecord = null;
-	_theAction = null;
+        return _outcome;
     }
 
-public int outcome ()
-    {
-	return _outcome;
+    protected AsyncPrepare(BasicAction act, boolean reportHeuristics, AbstractRecord rec) {
+        _theAction = act;
+        _outcome = TwoPhaseOutcome.PREPARE_NOTOK;
+        _reportHeuristics = reportHeuristics;
+        _theRecord = rec;
     }
-    
-protected AsyncPrepare (BasicAction act, boolean reportHeuristics, AbstractRecord rec)
-    {
-	_theAction = act;
-	_outcome = TwoPhaseOutcome.PREPARE_NOTOK;
-	_reportHeuristics = reportHeuristics;
-	_theRecord = rec;
-    }
 
-private BasicAction    _theAction;
-private int            _outcome;
-private boolean        _reportHeuristics;
-private AbstractRecord _theRecord;
-    
+    private BasicAction _theAction;
+    private int _outcome;
+    private boolean _reportHeuristics;
+    private AbstractRecord _theRecord;
 };

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/BasicAction.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/BasicAction.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/BasicAction.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -32,9 +32,13 @@
 package com.arjuna.ats.arjuna.coordinator;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 
 import com.arjuna.ats.arjuna.ObjectType;
 import com.arjuna.ats.arjuna.StateManager;
@@ -596,7 +600,7 @@
             if (actionStatus <= ActionStatus.ABORTING)
             {
                 if (_childThreads == null)
-                    _childThreads = new Hashtable();
+                    _childThreads = new Hashtable<String, Thread>();
 
                 _childThreads.put(ThreadUtil.getThreadId(t), t); // makes sure so we don't get
                 // duplicates
@@ -699,7 +703,7 @@
             if (actionStatus <= ActionStatus.ABORTING)
             {
                 if (_childActions == null)
-                    _childActions = new Hashtable();
+                    _childActions = new Hashtable<BasicAction, BasicAction>();
 
                 _childActions.put(act, act);
                 result = true;
@@ -1281,7 +1285,7 @@
 
         if (size > 0)
         {
-            Collection c = _childActions.values();
+            Collection<BasicAction> c = _childActions.values();
 
             return c.toArray();
         }
@@ -1482,7 +1486,7 @@
 
                     if (!reportHeuristics && TxControl.asyncCommit
                             && (parentAction == null)) {
-                        AsyncCommit.create(this, false);
+                        TwoPhaseCommitThreadPool.submitJob(new AsyncCommit(this, false));
                     } else
                         phase2Abort(reportHeuristics); /* first phase failed */
                 }
@@ -1491,7 +1495,7 @@
                     if (!reportHeuristics && TxControl.asyncCommit
                             && (parentAction == null))
                     {
-                        AsyncCommit.create(this, true);
+                        TwoPhaseCommitThreadPool.submitJob(new AsyncCommit(this, true));
                     }
                     else
                         phase2Commit(reportHeuristics); /* first phase succeeded */
@@ -1941,6 +1945,36 @@
         }
     }
 
+    protected int async_prepare(boolean reportHeuristics) {
+        int p = TwoPhaseOutcome.PREPARE_OK;
+        AbstractRecord lastRec = pendingList.getRear();
+        Collection<Future<Integer>> tasks = new ArrayList<Future<Integer>>();
+
+        while (pendingList.size() != 0)
+            tasks.add(TwoPhaseCommitThreadPool.submitJob(new AsyncPrepare(
+                    this, reportHeuristics, pendingList.getFront())));
+
+        // prepare the last (or only) participant on the callers thread
+        if (lastRec != null)
+            p = doPrepare(reportHeuristics, lastRec);
+
+        // get the results
+        for (Future<Integer> task : tasks) {
+            try {
+                int outcome = task.get();
+
+                if (p == TwoPhaseOutcome.PREPARE_OK)
+                    p = outcome;
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (ExecutionException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return p;
+    }
+
     /**
      * Phase one of a two phase commit protocol. This function returns the
      * ouctome of the prepare operation. If all goes well it will be PREPARE_OK,
@@ -2011,66 +2045,7 @@
 
         if ((actionType == ActionType.TOP_LEVEL) && (TxControl.asyncPrepare))
         {
-            int numberOfThreads = ((pendingList != null) ? pendingList.size()
-                    : 0);
-            Thread[] threads = new Thread[numberOfThreads];
-            int i;
-
-            /*
-                * First create them in a suspended way, so that we can purge the
-                * list before it is added to (in the event of failures!)
-                */
-
-            for (i = 0; i < numberOfThreads; i++)
-            {
-                threads[i] = AsyncPrepare.create(this, reportHeuristics, pendingList.getFront());
-            }
-
-            /*
-                * Now start the threads running.
-                */
-
-            for (i = 0; i < numberOfThreads; i++)
-            {
-                threads[i].start();
-                Thread.yield();
-            }
-
-            /*
-                * If one of these threads fails (PREPARE_NOTOK) do we terminate the
-                * others or simply let them finish? Currently we wait and let them
-                * all terminate regardless.
-                */
-
-            /*
-                * Now synchronise with the threads.
-                */
-
-            for (int j = 0; j < numberOfThreads; j++)
-            {
-                while (threads[j].isAlive())
-                {
-                    try
-                    {
-                        threads[j].join();
-                    }
-                    catch (Exception e)
-                    {
-                        tsLogger.logger.warn(e);
-
-                        p = TwoPhaseOutcome.PREPARE_NOTOK;
-                    }
-                }
-
-                /*
-                     * Only set the outcome if the current value is PREPARE_OK.
-                     */
-
-                if (p == TwoPhaseOutcome.PREPARE_OK)
-                    p = ((AsyncPrepare) threads[j]).outcome();
-
-                threads[j] = null;
-            }
+            p = async_prepare(reportHeuristics);
         }
         else
         {
@@ -3250,7 +3225,7 @@
         {
             problem = true;
 
-            Enumeration iter = _childActions.elements();
+            Enumeration<BasicAction> iter = _childActions.elements();
             BasicAction child = null;
             boolean printError = true;
 
@@ -3265,7 +3240,7 @@
 
             while (iter.hasMoreElements())
             {
-                child = (BasicAction) iter.nextElement();
+                child = iter.nextElement();
 
                 if (child.status() != ActionStatus.ABORTED) {
                     if (printError) {
@@ -3322,12 +3297,12 @@
                 * action.
                 */
 
-            Enumeration iter = _childThreads.elements();
+            Enumeration<Thread> iter = _childThreads.elements();
             Thread t = null;
 
             while (iter.hasMoreElements())
             {
-                t = (Thread) iter.nextElement();
+                t = iter.nextElement();
 
                 if (tsLogger.logger.isTraceEnabled()) {
                     tsLogger.logger.trace("BasicAction::removeAllChildThreads () action "+get_uid()+" removing "+t);
@@ -3565,8 +3540,8 @@
       * provide an explicit means of registering threads with an action.
       */
 
-    private Hashtable _childThreads;
-    private Hashtable _childActions;
+    private Hashtable<String, Thread> _childThreads;
+    private Hashtable<BasicAction, BasicAction> _childActions;
 
     private BasicActionFinalizer finalizerObject;
     private static final boolean finalizeBasicActions = arjPropertyManager.getCoordinatorEnvironmentBean().isFinalizeBasicActions();

Added: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCommitThreadPool.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCommitThreadPool.java	                        (rev 0)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/coordinator/TwoPhaseCommitThreadPool.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -0,0 +1,22 @@
+package com.arjuna.ats.arjuna.coordinator;
+
+import com.arjuna.ats.arjuna.common.arjPropertyManager;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class TwoPhaseCommitThreadPool {
+    private static final int poolSize = arjPropertyManager.getCoordinatorEnvironmentBean().
+            getMaxTwoPhaseCommitThreads();
+    private static final ExecutorService executor = Executors.newFixedThreadPool(poolSize);
+
+    public static Future<Integer> submitJob(Callable<Integer> job) {
+        return executor.submit(job);
+    }
+
+    public static void submitJob(Runnable job) {
+        executor.submit(job);
+    }
+}

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/XAResourceRecord.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/XAResourceRecord.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/XAResourceRecord.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -1195,7 +1195,7 @@
 	 * with the thread, i.e., has end already been called on it?
 	 */
 
-	private final boolean endAssociation()
+	protected boolean endAssociation()
 	{
 		boolean doEnd = true;
 

Added: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/resources/jta/XAResourceRecord.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/resources/jta/XAResourceRecord.java	                        (rev 0)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/resources/jta/XAResourceRecord.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -0,0 +1,59 @@
+package com.arjuna.ats.internal.jta.resources.jta;
+
+import com.arjuna.ats.internal.jta.transaction.jts.TransactionImple;
+import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
+import com.arjuna.ats.internal.jta.xa.TxInfo;
+import com.arjuna.ats.jta.logging.jtaLogger;
+
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+public class XAResourceRecord extends
+        com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord  {
+
+    private TransactionImple _tx;
+
+    public XAResourceRecord(TransactionImple tx, XAResource res, Xid xid,
+			Object[] params) {
+        super(null, res, xid, params);
+
+    }
+
+	public int topLevelAbort()
+	{
+		if (jtaLogger.logger.isTraceEnabled()) {
+            jtaLogger.logger.trace("XAResourceRecord.topLevelAbort for " + this);
+        }
+
+		if (_tx != null
+				&& _tx.getXAResourceState(_theXAResource) == TxInfo.OPTIMIZED_ROLLBACK)
+		{
+			/*
+			 * Already rolledback during delist.
+			 */
+
+			return TwoPhaseOutcome.FINISH_OK;
+		} else {
+            return super.topLevelAbort();
+        }
+    }
+
+ 	protected boolean endAssociation()
+	{
+		boolean doEnd = true;
+
+		if (_tx != null)
+		{
+			if (_tx.getXAResourceState(_theXAResource) == TxInfo.NOT_ASSOCIATED)
+			{
+				// end has been called so we don't need to do it again!
+
+				doEnd = false;
+			}
+		}
+		else
+			doEnd = false; // Recovery mode
+
+		return doEnd;
+	}
+}

Modified: labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/TransactionImple.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/TransactionImple.java	2012-10-30 15:10:36 UTC (rev 38237)
+++ labs/jbosstm/branches/JBOSSTS_4_16_4_Final_JBTM-1310/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/TransactionImple.java	2012-10-30 18:19:25 UTC (rev 38238)
@@ -45,6 +45,8 @@
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 
+import com.arjuna.ats.arjuna.coordinator.AddOutcome;
+import com.arjuna.ats.internal.jta.resources.arjunacore.XAOnePhaseResource;
 import org.omg.CORBA.INVALID_TRANSACTION;
 import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
 import org.omg.CORBA.TRANSACTION_UNAVAILABLE;
@@ -707,7 +709,8 @@
                                 }
                                 catch (XAException te)
                                 {
-                                    jtaxLogger.i18NLogger.warn_jtax_transaction_jts_timeouterror("TransactionImple.enlistResource",
+                                    jtaxLogger.i18NLogger.warn_jtax_transaction_jts_timeouterror(
+                                            "TransactionImple.enlistResource",
                                             XAHelper.printXAErrorCode(te), XAHelper.xidToString(xid), te);
                                 }
                             }
@@ -722,21 +725,47 @@
                         // The xid will change on each pass of the loop, so we need to create a new record on each pass.
                         // The registerResource will fail in the case of multiple last resources being disallowed.
                         // see JBTM-362 and JBTM-363
-                        XAResourceRecord xaResourceRecord = createRecord(xaRes, params, xid);
-                        if(xaResourceRecord != null) {
+                        TwoPhaseCoordinator theTx = (TwoPhaseCoordinator) BasicAction.Current();
+
+                        if (theTx != null) {
+                            int result;
+
                             xaRes.start(xid, XAResource.TMNOFLAGS);
-                            try {
-                                RecoveryCoordinator recCoord = _theTransaction.registerResource(xaResourceRecord.getResource());
-                                xaResourceRecord.setRecoveryCoordinator(recCoord);
-                            } catch(Exception e) {
-                                // we called start on the resource, but _theTransaction did not accept it.
-                                // we therefore have a mess which we must now clean up by ensuring the start is undone:
-                                xaResourceRecord.rollback();
-                                markRollbackOnly();
-                                return false;
+                            if ((xaRes instanceof LastResourceCommitOptimisation)
+                                    || ((LAST_RESOURCE_OPTIMISATION_INTERFACE != null) &&
+                                    LAST_RESOURCE_OPTIMISATION_INTERFACE.isInstance(xaRes))) {
+                                result = theTx.add(
+                                        new com.arjuna.ats.internal.arjuna.abstractrecords.LastResourceRecord(
+                                        new XAOnePhaseResource(xaRes, xid, params)));
+                            } else {
+                                result = theTx.add(new com.arjuna.ats.internal.jta.resources.jta.XAResourceRecord(
+                                        this, xaRes, xid, params));
                             }
-                            _resources.put(xaRes, new TxInfo(xid));
-                            return true; // dive out, no need to set associatedWork = true;
+
+                            if (result != AddOutcome.AR_ADDED) {
+                                    // we called start on the resource, but _theTransaction did not accept it. We
+                                    // therefore have a mess which we must now clean up by ensuring the start is undone:
+                                    xaRes.rollback(xid);
+                            } else {
+                                _resources.put(xaRes, new TxInfo(xid));
+                                return true; // dive out, no need to set associatedWork = true;
+                            }
+                        } else {
+                            XAResourceRecord xaResourceRecord = createRecord(xaRes, params, xid);
+                            if(xaResourceRecord != null) {
+                                xaRes.start(xid, XAResource.TMNOFLAGS);
+                                try {
+                                    RecoveryCoordinator recCoord = _theTransaction.registerResource(
+                                            xaResourceRecord.getResource());
+                                    xaResourceRecord.setRecoveryCoordinator(recCoord);
+                                    _resources.put(xaRes, new TxInfo(xid));
+                                    return true; // dive out, no need to set associatedWork = true;
+                                } catch(Exception e) {
+                                    // we called start on the resource, but _theTransaction did not accept it. We
+                                    // therefore have a mess which we must now clean up by ensuring the start is undone:
+                                    xaResourceRecord.rollback();
+                                }
+                            }
                         }
 
                         // if we get to here, something other than a failure of xaRes.start probably went wrong.
@@ -772,7 +801,8 @@
 								 * rollback only.
 								 */
 
-                                jtaxLogger.i18NLogger.warn_jtax_transaction_jts_starterror("TransactionImple.enlistResource - XAResource.start",
+                                jtaxLogger.i18NLogger.warn_jtax_transaction_jts_starterror(
+                                        "TransactionImple.enlistResource - XAResource.start",
                                         XAHelper.printXAErrorCode(e), XAHelper.xidToString(xid), e);
 
 								markRollbackOnly();
@@ -782,7 +812,8 @@
 
 						if (retry < 0)
 						{
-                            jtaxLogger.i18NLogger.warn_jtax_transaction_jts_starterror("TransactionImple.enlistResource - XAResource.start",
+                            jtaxLogger.i18NLogger.warn_jtax_transaction_jts_starterror(
+                                    "TransactionImple.enlistResource - XAResource.start",
                                     XAHelper.printXAErrorCode(e), XAHelper.xidToString(xid), e);
 
 							markRollbackOnly();
@@ -813,7 +844,8 @@
 				}
 				catch (XAException ex)
 				{
-                    jtaxLogger.i18NLogger.warn_jtax_transaction_jts_xaerror("TransactionImple.enlistResource - xa_start: ", XAHelper.printXAErrorCode(ex), ex);
+                    jtaxLogger.i18NLogger.warn_jtax_transaction_jts_xaerror(
+                            "TransactionImple.enlistResource - xa_start: ", XAHelper.printXAErrorCode(ex), ex);
 
 					markRollbackOnly();
 
@@ -1049,7 +1081,8 @@
 
 			markRollbackOnly();
 
-            jtaxLogger.i18NLogger.warn_jtax_transaction_jts_xaerror("TransactionImple.delistResource", XAHelper.printXAErrorCode(exp), exp);
+            jtaxLogger.i18NLogger.warn_jtax_transaction_jts_xaerror("TransactionImple.delistResource",
+                    XAHelper.printXAErrorCode(exp), exp);
 
 			return false;
 		}



More information about the jboss-svn-commits mailing list