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();
}