You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by dj...@apache.org on 2010/02/20 02:34:14 UTC

svn commit: r912058 - in /geronimo/components/txmanager/trunk/geronimo-transaction/src: main/java/org/apache/geronimo/transaction/log/ main/java/org/apache/geronimo/transaction/manager/ test/java/org/apache/geronimo/transaction/manager/

Author: djencks
Date: Sat Feb 20 01:34:14 2010
New Revision: 912058

URL: http://svn.apache.org/viewvc?rev=912058&view=rev
Log:
GERONIMO-5152 Add retry tasks for recovery and retry errors on commit

Added:
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java   (with props)
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java   (with props)
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java   (with props)
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java   (with props)
Modified:
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/HOWLLog.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionLog.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLog.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java
    geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/XATransactionTester.java

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/HOWLLog.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/HOWLLog.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/HOWLLog.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/HOWLLog.java Sat Feb 20 01:34:14 2010
@@ -241,7 +241,7 @@
     public void begin(Xid xid) throws LogException {
     }
 
-    public Object prepare(Xid xid, List<TransactionBranchInfo> branches) throws LogException {
+    public Object prepare(Xid xid, List<? extends TransactionBranchInfo> branches) throws LogException {
         int branchCount = branches.size();
         byte[][] data = new byte[3 + 2 * branchCount][];
         data[0] = intToBytes(xid.getFormatId());

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java Sat Feb 20 01:34:14 2010
@@ -24,6 +24,7 @@
 import javax.transaction.xa.Xid;
 
 import org.apache.geronimo.transaction.manager.LogException;
+import org.apache.geronimo.transaction.manager.TransactionBranchInfo;
 import org.apache.geronimo.transaction.manager.TransactionLog;
 import org.apache.geronimo.transaction.manager.XidFactory;
 
@@ -38,7 +39,7 @@
     public void begin(Xid xid) throws LogException {
     }
 
-    public Object prepare(Xid xid, List branches) throws LogException {
+    public Object prepare(Xid xid, List<? extends TransactionBranchInfo> branches) throws LogException {
         return null;
     }
 

Added: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java?rev=912058&view=auto
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java (added)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java Sat Feb 20 01:34:14 2010
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.geronimo.transaction.manager;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.TimerTask;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.Xid;
+
+import org.apache.geronimo.transaction.manager.TransactionImpl.TransactionBranch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class CommitTask extends TimerTask {
+    private static final Logger log = LoggerFactory.getLogger(CommitTask.class);
+    private final Xid xid;
+    private final List<TransactionBranch> rms;
+    private final Object logMark;
+    private final RetryScheduler retryScheduler;
+    private final TransactionLog txLog;
+    private int count = 0;
+    private int status;
+    private XAException cause;
+
+    public CommitTask(Xid xid, List<TransactionBranch> rms, Object logMark, RetryScheduler retryScheduler, TransactionLog txLog) {
+        this.xid = xid;
+        this.rms = rms;
+        this.logMark = logMark;
+        this.retryScheduler = retryScheduler;
+        this.txLog = txLog;
+    }
+
+    @Override
+    public void run() {
+        synchronized (this) {
+            status = Status.STATUS_COMMITTING;
+        }
+        for (Iterator i = rms.iterator(); i.hasNext();) {
+            TransactionBranch manager = (TransactionBranch) i.next();
+            try {
+                try {
+                    manager.getCommitter().commit(manager.getBranchId(), false);
+                    i.remove();
+                } catch (XAException e) {
+                    log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e);
+
+                    if (e.errorCode == XAException.XA_HEURRB) {
+                        i.remove();
+                        log.info("Transaction has been heuristically rolled back");
+                        cause = e;
+                        manager.getCommitter().forget(manager.getBranchId());
+                    } else if (e.errorCode == XAException.XA_HEURMIX) {
+                        i.remove();
+                        log.info("Transaction has been heuristically committed and rolled back");
+                        cause = e;
+                        manager.getCommitter().forget(manager.getBranchId());
+                    } else if (e.errorCode == XAException.XA_HEURCOM) {
+                        i.remove();
+                        // let's not throw an exception as the transaction has been committed
+                        log.info("Transaction has been heuristically committed");
+                        manager.getCommitter().forget(manager.getBranchId());
+                    } else if (e.errorCode == XAException.XA_RETRY) {
+                        // do nothing, retry later
+                    } else {
+                        //nothing we can do about it.... keep trying
+                        i.remove();
+                        cause = e;
+                    }
+                }
+            } catch (XAException e) {
+                if (e.errorCode == XAException.XAER_NOTA) {
+                    // NOTA in response to forget, means the resource already forgot the transaction
+                    // ignore
+                } else {
+                    cause = e;
+                }
+            }
+        }
+        //if all resources were read only, we didn't write a prepare record.
+        if (rms.isEmpty() && status == Status.STATUS_COMMITTED) {
+            try {
+                txLog.commit(xid, logMark);
+                synchronized (this) {
+                    status = Status.STATUS_COMMITTED;
+                }
+            } catch (LogException e) {
+                log.error("Unexpected exception logging commit completion for xid " + xid, e);
+                cause = (XAException) new XAException("Unexpected error logging commit completion for xid " + xid).initCause(e);
+            }
+        } else {
+            retryScheduler.retry(this, count++);
+        }
+//        if (cause != null) {
+//            if (cause.errorCode == XAException.XA_HEURRB && !evercommit) {
+//                throw (HeuristicRollbackException) new HeuristicRollbackException("Error during two phase commit").initCause(cause);
+//            } else if (cause.errorCode == XAException.XA_HEURRB && evercommit) {
+//                throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
+//            } else if (cause.errorCode == XAException.XA_HEURMIX) {
+//                throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
+//            } else {
+//                throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
+//            }
+//        }
+    }
+
+    public XAException getCause() {
+        return cause;
+    }
+
+    public int getStatus() {
+        return status;
+    }
+}

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java?rev=912058&view=auto
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java (added)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java Sat Feb 20 01:34:14 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.geronimo.transaction.manager;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ExponentialtIntervalRetryScheduler implements RetryScheduler{
+
+    private final Timer timer = new Timer();
+
+    private final int base = 2;
+
+    public void retry(TimerTask task, int count) {
+        long interval = Math.round(Math.pow(base, count)) * 1000;
+        timer.schedule(task, interval);
+    }
+}

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/ExponentialtIntervalRetryScheduler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java?rev=912058&view=auto
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java (added)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java Sat Feb 20 01:34:14 2010
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.geronimo.transaction.manager;
+
+import java.util.TimerTask;
+
+import javax.transaction.SystemException;
+import javax.transaction.xa.XAException;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class RecoverTask extends TimerTask {
+
+    private final RetryScheduler retryScheduler;
+    private final NamedXAResourceFactory namedXAResourceFactory;
+    private final Recovery recovery;
+    private final RecoverableTransactionManager recoverableTransactionManager;
+    private int count = 0;
+
+    public RecoverTask(RetryScheduler retryScheduler, NamedXAResourceFactory namedXAResourceFactory, Recovery recovery, RecoverableTransactionManager recoverableTransactionManager) {
+        this.retryScheduler = retryScheduler;
+        this.namedXAResourceFactory = namedXAResourceFactory;
+        this.recovery = recovery;
+        this.recoverableTransactionManager = recoverableTransactionManager;
+    }
+
+    @Override
+    public void run() {
+        try {
+            NamedXAResource namedXAResource = namedXAResourceFactory.getNamedXAResource();
+            try {
+                recovery.recoverResourceManager(namedXAResource);
+            } finally {
+                namedXAResourceFactory.returnNamedXAResource(namedXAResource);
+            }
+            return;
+        } catch (XAException e) {
+            recoverableTransactionManager.recoveryError(e);
+        } catch (SystemException e) {
+            recoverableTransactionManager.recoveryError(e);
+        }
+        retryScheduler.retry(this, count++);
+    }
+}

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoverTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java Sat Feb 20 01:34:14 2010
@@ -50,6 +50,7 @@
 
     private final TransactionLog txLog;
     private final XidFactory xidFactory;
+    private final RetryScheduler retryScheduler;
 
     private final Map<Xid, TransactionImpl> externalXids = new HashMap<Xid, TransactionImpl>();
     private final Map<ByteArrayWrapper, XidBranchesPair> ourXids = new HashMap<ByteArrayWrapper, XidBranchesPair>();
@@ -58,9 +59,10 @@
 
     private final List<Exception> recoveryErrors = new ArrayList<Exception>();
 
-    public RecoveryImpl(final TransactionLog txLog, final XidFactory xidFactory) {
+    public RecoveryImpl(final TransactionLog txLog, final XidFactory xidFactory, RetryScheduler retryScheduler) {
         this.txLog = txLog;
         this.xidFactory = xidFactory;
+        this.retryScheduler = retryScheduler;
     }
 
     public synchronized void recoverLog() throws XAException {
@@ -84,7 +86,7 @@
                     transactionsForName.add(xidBranchesPair);
                 }
             } else {
-                TransactionImpl externalTx = new ExternalTransaction(xid, txLog, xidBranchesPair.getBranches());
+                TransactionImpl externalTx = new ExternalTransaction(xid, txLog, retryScheduler, xidBranchesPair.getBranches());
                 externalXids.put(xid, externalTx);
                 externalGlobalIdMap.put(xid.getGlobalTransactionId(), externalTx);
             }
@@ -233,8 +235,8 @@
     private static class ExternalTransaction extends TransactionImpl {
         private final Set<String> resourceNames = new HashSet<String>();
 
-        public ExternalTransaction(Xid xid, TransactionLog txLog, Set<TransactionBranchInfo> resourceNames) {
-            super(xid, txLog);
+        public ExternalTransaction(Xid xid, TransactionLog txLog, RetryScheduler retryScheduler, Set<TransactionBranchInfo> resourceNames) {
+            super(xid, txLog, retryScheduler);
             for (TransactionBranchInfo info: resourceNames) {
                 this.resourceNames.add(info.getResourceName());
             }

Added: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java?rev=912058&view=auto
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java (added)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java Sat Feb 20 01:34:14 2010
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.geronimo.transaction.manager;
+
+import java.util.TimerTask;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface RetryScheduler {
+
+    void retry(TimerTask task, int count);
+}

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RetryScheduler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java Sat Feb 20 01:34:14 2010
@@ -17,9 +17,6 @@
 
 package org.apache.geronimo.transaction.manager;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
@@ -39,7 +36,6 @@
 import javax.transaction.xa.XAException;
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,24 +51,26 @@
     private final XidFactory xidFactory;
     private final Xid xid;
     private final TransactionLog txnLog;
+    private final RetryScheduler retryScheduler;
     private final long timeout;
-    private final List syncList = new ArrayList(5);
-    private final List interposedSyncList = new ArrayList(3);
-    private final LinkedList resourceManagers = new LinkedList();
-    private final IdentityHashMap activeXaResources = new IdentityHashMap(3);
-    private final IdentityHashMap suspendedXaResources = new IdentityHashMap(3);
+    private final List<Synchronization> syncList = new ArrayList<Synchronization>(5);
+    private final List<Synchronization> interposedSyncList = new ArrayList<Synchronization>(3);
+    private final LinkedList<TransactionBranch> resourceManagers = new LinkedList<TransactionBranch>();
+    private final IdentityHashMap<XAResource, TransactionBranch> activeXaResources = new IdentityHashMap<XAResource, TransactionBranch>(3);
+    private final IdentityHashMap<XAResource, TransactionBranch> suspendedXaResources = new IdentityHashMap<XAResource, TransactionBranch>(3);
     private int status = Status.STATUS_NO_TRANSACTION;
     private Object logMark;
 
-    private final Map resources = new HashMap();
+    private final Map<Object, Object> resources = new HashMap<Object, Object>();
 
-    TransactionImpl(XidFactory xidFactory, TransactionLog txnLog, long transactionTimeoutMilliseconds) throws SystemException {
-        this(xidFactory.createXid(), xidFactory, txnLog, transactionTimeoutMilliseconds);
+    TransactionImpl(XidFactory xidFactory, TransactionLog txnLog, RetryScheduler retryScheduler, long transactionTimeoutMilliseconds) throws SystemException {
+        this(xidFactory.createXid(), xidFactory, txnLog, retryScheduler, transactionTimeoutMilliseconds);
     }
 
-    TransactionImpl(Xid xid, XidFactory xidFactory, TransactionLog txnLog, long transactionTimeoutMilliseconds) throws SystemException {
+    TransactionImpl(Xid xid, XidFactory xidFactory, TransactionLog txnLog, RetryScheduler retryScheduler, long transactionTimeoutMilliseconds) throws SystemException {
         this.xidFactory = xidFactory;
         this.txnLog = txnLog;
+        this.retryScheduler = retryScheduler;
         this.xid = xid;
         this.timeout = transactionTimeoutMilliseconds + TransactionTimer.getCurrentTime();
         try {
@@ -87,10 +85,11 @@
     }
 
     //reconstruct a tx for an external tx found in recovery
-    public TransactionImpl(Xid xid, TransactionLog txLog) {
+    public TransactionImpl(Xid xid, TransactionLog txLog, RetryScheduler retryScheduler) {
         this.xidFactory = null;
         this.txnLog = txLog;
         this.xid = xid;
+        this.retryScheduler = retryScheduler;
         status = Status.STATUS_PREPARED;
         //TODO is this a good idea?
         this.timeout = Long.MAX_VALUE;
@@ -551,7 +550,7 @@
         endResources(suspendedXaResources);
     }
 
-    private void endResources(IdentityHashMap resourceMap) {
+    private void endResources(IdentityHashMap<XAResource, TransactionBranch> resourceMap) {
         while (true) {
             XAResource xaRes;
             TransactionBranch manager;
@@ -578,7 +577,7 @@
         }
     }
 
-    private void rollbackResources(List rms) throws SystemException {
+    private void rollbackResources(List<TransactionBranch> rms) throws SystemException {
         SystemException cause = null;
         synchronized (this) {
             status = Status.STATUS_ROLLING_BACK;
@@ -618,7 +617,7 @@
         }
     }
 
-    private void rollbackResourcesDuringCommit(List rms, boolean everRb) throws HeuristicMixedException, RollbackException, SystemException {
+    private void rollbackResourcesDuringCommit(List<TransactionBranch> rms, boolean everRb) throws HeuristicMixedException, RollbackException, SystemException {
         XAException cause = null;
         boolean everRolledback = everRb;
         synchronized (this) {
@@ -746,71 +745,91 @@
         }
     }
     
-    private void commitResources(List rms) throws HeuristicRollbackException, HeuristicMixedException, SystemException {
-        XAException cause = null;
-        boolean evercommit = false;
+    private void commitResources(List<TransactionBranch> rms) throws HeuristicRollbackException, HeuristicMixedException, SystemException {
+        //TODO there's some logic removed about dealing with a heuristic rollback on the first resource.
+        CommitTask commitTask = new CommitTask(xid, rms, logMark, retryScheduler, txnLog);
         synchronized (this) {
             status = Status.STATUS_COMMITTING;
         }
-        try {
-            for (Iterator i = rms.iterator(); i.hasNext();) {
-                TransactionBranch manager = (TransactionBranch) i.next();
-                try {
-                    manager.getCommitter().commit(manager.getBranchId(), false);
-                    evercommit = true;
-                } catch (XAException e) {
-                    log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e);
-                    
-                    if (e.errorCode == XAException.XA_HEURRB) {
-                        log.info("Transaction has been heuristically rolled back");
-                        cause = e;
-                        manager.getCommitter().forget(manager.getBranchId());
-                    } else if (e.errorCode == XAException.XA_HEURMIX) {
-                        log.info("Transaction has been heuristically committed and rolled back");
-                        cause = e;
-                        evercommit = true;
-                        manager.getCommitter().forget(manager.getBranchId());
-                    } else if (e.errorCode == XAException.XA_HEURCOM) {
-                        // let's not throw an exception as the transaction has been committed
-                        log.info("Transaction has been heuristically committed");
-                        evercommit = true;
-                        manager.getCommitter().forget(manager.getBranchId());
-                    } else {
-                        cause = e;
-                    }
-                }
-            }
-        } catch (XAException e) {
-            if (e.errorCode == XAException.XAER_NOTA) {
-                // NOTA in response to forget, means the resource already forgot the transaction
-                // ignore
-            } else {
-                throw (SystemException) new SystemException("Error during two phase commit").initCause(e);
-            }
-        }
-        //if all resources were read only, we didn't write a prepare record.
-        if (!rms.isEmpty()) {
-            try {
-                txnLog.commit(xid, logMark);
-            } catch (LogException e) {
-                log.error("Unexpected exception logging commit completion for xid " + xid, e);
-                throw (SystemException) new SystemException("Unexpected error logging commit completion for xid " + xid).initCause(e);
-            }
-        }
+        commitTask.run();
         synchronized (this) {
-            status = Status.STATUS_COMMITTED;
+            status = commitTask.getStatus();
         }
+        XAException cause = commitTask.getCause();
         if (cause != null) {
-            if (cause.errorCode == XAException.XA_HEURRB && !evercommit) {
+            if (cause.errorCode == XAException.XA_HEURRB) {
                 throw (HeuristicRollbackException) new HeuristicRollbackException("Error during two phase commit").initCause(cause);
-            } else if (cause.errorCode == XAException.XA_HEURRB && evercommit) {
+            } else if (cause.errorCode == XAException.XA_HEURRB) {
                 throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
             } else if (cause.errorCode == XAException.XA_HEURMIX) {
                 throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
             } else {
                 throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
-            } 
+            }
         }
+
+
+//        XAException cause = null;
+//        boolean evercommit = false;
+//        try {
+//            for (Iterator i = rms.iterator(); i.hasNext();) {
+//                TransactionBranch manager = (TransactionBranch) i.next();
+//                try {
+//                    manager.getCommitter().commit(manager.getBranchId(), false);
+//                    evercommit = true;
+//                } catch (XAException e) {
+//                    log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e);
+//
+//                    if (e.errorCode == XAException.XA_HEURRB) {
+//                        log.info("Transaction has been heuristically rolled back");
+//                        cause = e;
+//                        manager.getCommitter().forget(manager.getBranchId());
+//                    } else if (e.errorCode == XAException.XA_HEURMIX) {
+//                        log.info("Transaction has been heuristically committed and rolled back");
+//                        cause = e;
+//                        evercommit = true;
+//                        manager.getCommitter().forget(manager.getBranchId());
+//                    } else if (e.errorCode == XAException.XA_HEURCOM) {
+//                        // let's not throw an exception as the transaction has been committed
+//                        log.info("Transaction has been heuristically committed");
+//                        evercommit = true;
+//                        manager.getCommitter().forget(manager.getBranchId());
+//                    } else {
+//                        cause = e;
+//                    }
+//                }
+//            }
+//        } catch (XAException e) {
+//            if (e.errorCode == XAException.XAER_NOTA) {
+//                // NOTA in response to forget, means the resource already forgot the transaction
+//                // ignore
+//            } else {
+//                throw (SystemException) new SystemException("Error during two phase commit").initCause(e);
+//            }
+//        }
+//        //if all resources were read only, we didn't write a prepare record.
+//        if (!rms.isEmpty()) {
+//            try {
+//                txnLog.commit(xid, logMark);
+//            } catch (LogException e) {
+//                log.error("Unexpected exception logging commit completion for xid " + xid, e);
+//                throw (SystemException) new SystemException("Unexpected error logging commit completion for xid " + xid).initCause(e);
+//            }
+//        }
+//        synchronized (this) {
+//            status = Status.STATUS_COMMITTED;
+//        }
+//        if (cause != null) {
+//            if (cause.errorCode == XAException.XA_HEURRB && !evercommit) {
+//                throw (HeuristicRollbackException) new HeuristicRollbackException("Error during two phase commit").initCause(cause);
+//            } else if (cause.errorCode == XAException.XA_HEURRB && evercommit) {
+//                throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
+//            } else if (cause.errorCode == XAException.XA_HEURMIX) {
+//                throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
+//            } else {
+//                throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
+//            }
+//        }
     }
 
     private static String getStateString(int status) {
@@ -857,7 +876,7 @@
         return manager;
     }
 
-    private static class TransactionBranch implements TransactionBranchInfo {
+    static class TransactionBranch implements TransactionBranchInfo {
         private final XAResource committer;
         private final Xid branchId;
 

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionLog.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionLog.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionLog.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionLog.java Sat Feb 20 01:34:14 2010
@@ -39,7 +39,7 @@
      * @return log mark to use in commit/rollback calls.
      * @throws LogException on error
      */
-    Object prepare(Xid xid, List<TransactionBranchInfo> branches) throws LogException;
+    Object prepare(Xid xid, List<? extends TransactionBranchInfo> branches) throws LogException;
 
     void commit(Xid xid, Object logMark) throws LogException;
 

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java Sat Feb 20 01:34:14 2010
@@ -54,7 +54,8 @@
     final Recovery recovery;
     private final Map<String, NamedXAResourceFactory> namedXAResourceFactories = new ConcurrentHashMap<String, NamedXAResourceFactory>();
     private final CopyOnWriteArrayList<TransactionManagerMonitor> transactionAssociationListeners = new CopyOnWriteArrayList<TransactionManagerMonitor>();
-    private List<Exception> recoveryErrors = new ArrayList<Exception>();
+    private final List<Exception> recoveryErrors = new ArrayList<Exception>();
+    private final RetryScheduler retryScheduler = new ExponentialtIntervalRetryScheduler();
     // statistics
     private AtomicLong totalCommits = new AtomicLong(0);
     private AtomicLong totalRollBacks = new AtomicLong(0);
@@ -99,7 +100,7 @@
             this.xidFactory = new XidFactoryImpl(DEFAULT_TM_ID);
         }
 
-        recovery = new RecoveryImpl(this.transactionLog, this.xidFactory);
+        recovery = new RecoveryImpl(this.transactionLog, this.xidFactory, retryScheduler);
         recovery.recoverLog();
     }
 
@@ -155,7 +156,7 @@
         if (getStatus() != Status.STATUS_NO_TRANSACTION) {
             throw new NotSupportedException("Nested Transactions are not supported");
         }
-        TransactionImpl tx = new TransactionImpl(xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
+        TransactionImpl tx = new TransactionImpl(xidFactory, transactionLog, retryScheduler, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
 //        timeoutTimer.schedule(tx, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
         try {
             associate(tx);
@@ -273,7 +274,7 @@
         if (transactionTimeoutMilliseconds < 0) {
             throw new SystemException("transaction timeout must be positive or 0 to reset to default");
         }
-        return new TransactionImpl(xid, xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
+        return new TransactionImpl(xid, xidFactory, transactionLog, retryScheduler, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
     }
 
     public void commit(Transaction tx, boolean onePhase) throws XAException {
@@ -349,18 +350,7 @@
 
     public void registerNamedXAResourceFactory(NamedXAResourceFactory namedXAResourceFactory) {
         namedXAResourceFactories.put(namedXAResourceFactory.getName(), namedXAResourceFactory);
-        try {
-            NamedXAResource namedXAResource = namedXAResourceFactory.getNamedXAResource();
-            try {
-                recovery.recoverResourceManager(namedXAResource);
-            } finally {
-                namedXAResourceFactory.returnNamedXAResource(namedXAResource);
-            }
-        } catch (XAException e) {
-            recoveryError(e);
-        } catch (SystemException e) {
-            recoveryError(e);
-        }
+        new RecoverTask(retryScheduler, namedXAResourceFactory, recovery, this).run();
     }
 
     public void unregisterNamedXAResourceFactory(String namedXAResourceFactoryName) {

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java Sat Feb 20 01:34:14 2010
@@ -38,6 +38,7 @@
     protected TransactionLog txLog;
 
     protected final XidFactory xidFactory = new XidFactoryImpl();
+    protected final RetryScheduler retryScheduler = new ExponentialtIntervalRetryScheduler();
     private static final String RM1 = "rm1";
     private static final String RM2 = "rm2";
     private static final String RM3 = "rm3";
@@ -55,7 +56,7 @@
         addBranch(txInfos, xares2);
         prepareLog(txLog, txInfos);
         prepareForReplay();
-        Recovery recovery = new RecoveryImpl(txLog, xidFactory);
+        Recovery recovery = new RecoveryImpl(txLog, xidFactory, retryScheduler);
         recovery.recoverLog();
         assertTrue(!recovery.hasRecoveryErrors());
         assertTrue(recovery.getExternalXids().isEmpty());
@@ -104,7 +105,7 @@
         addBranch(txInfos23, xares3);
         prepareLog(txLog, txInfos23);
         prepareForReplay();
-        Recovery recovery = new RecoveryImpl(txLog, xidFactory);
+        Recovery recovery = new RecoveryImpl(txLog, xidFactory, retryScheduler);
         recovery.recoverLog();
         assertTrue(!recovery.hasRecoveryErrors());
         assertTrue(recovery.getExternalXids().isEmpty());

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLog.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLog.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLog.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLog.java Sat Feb 20 01:34:14 2010
@@ -40,7 +40,7 @@
     public void begin(Xid xid) throws LogException {
     }
 
-    public Object prepare(Xid xid, List<TransactionBranchInfo> branches) throws LogException {
+    public Object prepare(Xid xid, List<? extends TransactionBranchInfo> branches) throws LogException {
         Object mark = new Object();
         Recovery.XidBranchesPair xidBranchesPair = new Recovery.XidBranchesPair(xid, mark);
         xidBranchesPair.getBranches().addAll(branches);

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java Sat Feb 20 01:34:14 2010
@@ -36,6 +36,7 @@
 public class RecoveryTest extends TestCase {
 
     XidFactory xidFactory = new XidFactoryImpl();
+    protected final RetryScheduler retryScheduler = new ExponentialtIntervalRetryScheduler();
     private final String RM1 = "rm1";
     private final String RM2 = "rm2";
     private final String RM3 = "rm3";
@@ -51,7 +52,7 @@
         MockTransactionInfo[] txInfos = makeTxInfos(xids);
         addBranch(txInfos, xares1);
         prepareLog(mockLog, txInfos);
-        Recovery recovery = new RecoveryImpl(mockLog, xidFactory);
+        Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler);
         recovery.recoverLog();
         assertTrue(!recovery.hasRecoveryErrors());
         assertTrue(recovery.getExternalXids().isEmpty());
@@ -71,7 +72,7 @@
         addBranch(txInfos, xares1);
         addBranch(txInfos, xares2);
         prepareLog(mockLog, txInfos);
-        Recovery recovery = new RecoveryImpl(mockLog, xidFactory);
+        Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler);
         recovery.recoverLog();
         assertTrue(!recovery.hasRecoveryErrors());
         assertTrue(recovery.getExternalXids().isEmpty());
@@ -137,7 +138,7 @@
         addBranch(txInfos23, xares2);
         addBranch(txInfos23, xares3);
         prepareLog(mockLog, txInfos23);
-        Recovery recovery = new RecoveryImpl(mockLog, xidFactory);
+        Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler);
         recovery.recoverLog();
         assertTrue(!recovery.hasRecoveryErrors());
         assertTrue(recovery.getExternalXids().isEmpty());

Modified: geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/XATransactionTester.java
URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/XATransactionTester.java?rev=912058&r1=912057&r2=912058&view=diff
==============================================================================
--- geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/XATransactionTester.java (original)
+++ geronimo/components/txmanager/trunk/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/XATransactionTester.java Sat Feb 20 01:34:14 2010
@@ -103,7 +103,7 @@
             XATransactionTester.this.xid = xid;
         }
 
-        public Object prepare(Xid xid, List<TransactionBranchInfo> branches) throws LogException {
+        public Object prepare(Xid xid, List<? extends TransactionBranchInfo> branches) throws LogException {
             return new Object();
         }