[Mulgara-svn] r640 - branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver

andrae at mulgara.org andrae at mulgara.org
Mon Feb 11 13:28:03 UTC 2008


Author: andrae
Date: 2008-02-11 05:28:02 -0800 (Mon, 11 Feb 2008)
New Revision: 640

Modified:
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
   branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
Log:
Solves two problems:

1. Modifies the MulgaraXAResource so it correctly forgets transactions after a
non-heuristic commit or rollback.  This corrects a misunderstanding of the JTA
spec I had when writing this code.  Clearest specification of this behaviour is
in the state tables in section 6 of the XA spec.

2. Fixes a deadlock due to incorrect lock-ordering.  Ensures calls from MTM to
the factories in closeSession() are done without holding the MTM mutex.  Made
the factory fields final to guarantee their access does not require the mutex.



Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java	2008-02-11 11:54:20 UTC (rev 639)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraExternalTransaction.java	2008-02-11 13:28:02 UTC (rev 640)
@@ -218,6 +218,10 @@
     // status = PREPARED; ?
   }
 
+  /**
+   * Perform rollback.  Only throws exception if transaction is subject to
+   * Heuristic Completion.
+   */
   void rollback(Xid xid) throws XAException {
     report("rollback");
     try {

Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2008-02-11 11:54:20 UTC (rev 639)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java	2008-02-11 13:28:02 UTC (rev 640)
@@ -71,11 +71,11 @@
   private DatabaseSession sessionReservingWriteLock;
 
   // Used to synchronize access to other fields.
-  private ReentrantLock mutex;
-  private Condition writeLockCondition;
+  private final ReentrantLock mutex;
+  private final Condition writeLockCondition;
 
-  private MulgaraInternalTransactionFactory internalFactory;
-  private MulgaraExternalTransactionFactory externalFactory;
+  private final MulgaraInternalTransactionFactory internalFactory;
+  private final MulgaraExternalTransactionFactory externalFactory;
 
   public MulgaraTransactionManager(TransactionManagerFactory transactionManagerFactory) {
     this.sessionHoldingWriteLock = null;
@@ -228,23 +228,28 @@
   }
 
   public void closingSession(DatabaseSession session) throws MulgaraTransactionException {
-    acquireMutex();
+    // Calls to final fields do not require mutex.  As both of these calls
+    // potentially call back into the manager, calling these while holding the
+    // lock can invalidate lock-ordering and result in a deadlock.
+    Throwable error = null;
     try {
-      Throwable error = null;
-      try {
-        internalFactory.closingSession(session);
-      } catch (Throwable th) {
-        logger.error("Error signalling session-close to internal xa-factory", th);
-        error = (error == null) ? th : error;
-      }
+      internalFactory.closingSession(session);
+    } catch (Throwable th) {
+      logger.error("Error signalling session-close to internal xa-factory", th);
+      error = (error == null) ? th : error;
+    }
 
-      try {
-        externalFactory.closingSession(session);
-      } catch (Throwable th) {
-        logger.error("Error signalling session-close to external xa-factory", th);
-        error = (error == null) ? th : error;
-      }
+    try {
+      externalFactory.closingSession(session);
+    } catch (Throwable th) {
+      logger.error("Error signalling session-close to external xa-factory", th);
+      error = (error == null) ? th : error;
+    }
 
+    // This code should not be required, but is there to ensure the manager is
+    // reset regardless of errors in the factories.
+    acquireMutex();
+    try {
       if (writeLockReserved(session)) {
         try {
           releaseReserve(session);

Modified: branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java
===================================================================
--- branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java	2008-02-11 11:54:20 UTC (rev 639)
+++ branches/mgr-73/src/jar/resolver/java/org/mulgara/resolver/MulgaraXAResourceContext.java	2008-02-11 13:28:02 UTC (rev 640)
@@ -124,6 +124,10 @@
         } else if (xa.isHeuristicallyRollbacked()) {
           // HEURRB causes difficulties with JOTM - so throw the less precise
           // but still correct RBROLLBACK.
+          // Note: Found the problem here - The J2EE Connector Architecture
+          // 7.6.2.2 requires an XA_RB* exception in the case of 1PC and 7.6.2.5
+          // implies that HEURRB is not permitted during 2PC - this seems broken
+          // to me, but that's the spec.
 //          throw new XAException(XAException.XA_HEURRB);
           throw new XAException(XAException.XA_RBROLLBACK);
         } else if (xa.isHeuristicallyCommitted()) {
@@ -137,6 +141,10 @@
             if (ex.errorCode != XAException.XA_RDONLY) {
               doRollback(xa, xid);
             }
+            // Note: XA spec requires us to forget about transactions that fail
+            // during commit.  doRollback throws exception under Heuristic
+            // Completion - when we do want to remember transaction.
+            xa2xid.remove1(xa);
             throw ex;
           }
         }
@@ -311,12 +319,19 @@
         }
 
         doRollback(xa, xid);
+        // If we don't throw a Heuristic Exception we need to forget this
+        // transaction.  doRollback only throws Heuristic Exceptions.
+        xa2xid.remove1(xa);
       } finally {
         releaseMutex();
       }
     }
 
 
+    /**
+     * Performs rollback.  Only throws exception if transaction is subject to
+     * Heuristic Completion.
+     */
     private void doRollback(MulgaraExternalTransaction xa, Xid xid) throws XAException {
       if (xa.isHeuristicallyRollbacked()) {
         logger.warn("Attempted to rollback heuristically rollbacked transaction: " + xa.getHeuristicCode());




More information about the Mulgara-svn mailing list