Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 77445 invoked from network); 18 Oct 2010 20:00:06 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 18 Oct 2010 20:00:06 -0000 Received: (qmail 4658 invoked by uid 500); 18 Oct 2010 20:00:06 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 4588 invoked by uid 500); 18 Oct 2010 20:00:06 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 4581 invoked by uid 99); 18 Oct 2010 20:00:06 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 18 Oct 2010 20:00:06 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 18 Oct 2010 20:00:00 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 17B8423889E1; Mon, 18 Oct 2010 19:59:02 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1023970 - in /geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src: main/java/org/apache/geronimo/transaction/manager/ test/java/org/apache/geronimo/transaction/manager/ Date: Mon, 18 Oct 2010 19:59:01 -0000 To: scm@geronimo.apache.org From: djencks@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20101018195902.17B8423889E1@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: djencks Date: Mon Oct 18 19:59:01 2010 New Revision: 1023970 URL: http://svn.apache.org/viewvc?rev=1023970&view=rev Log: GERONIMO-452, GERONIMO-5648, GERONIMO-5649 add retry logic for rollback, add logic for commit and rollback response to XAER_RMFAIL, and set tx timeout on XAResource Added: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RollbackTask.java - copied, changed from r1002829, geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/TransactionManagerImplTest.java Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java Mon Oct 18 19:59:01 2010 @@ -20,13 +20,13 @@ package org.apache.geronimo.transaction.manager; -import java.util.Iterator; import java.util.List; 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.ReturnableTransactionBranch; import org.apache.geronimo.transaction.manager.TransactionImpl.TransactionBranch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,56 +39,81 @@ public class CommitTask implements Runna private final Xid xid; private final List rms; private final Object logMark; - private final RetryScheduler retryScheduler; - private final TransactionLog txLog; + private final TransactionManagerImpl txManager; private int count = 0; private int status; private XAException cause; private boolean evercommit; - public CommitTask(Xid xid, List rms, Object logMark, RetryScheduler retryScheduler, TransactionLog txLog) { + public CommitTask(Xid xid, List rms, Object logMark, TransactionManagerImpl txManager) { this.xid = xid; this.rms = rms; this.logMark = logMark; - this.retryScheduler = retryScheduler; - this.txLog = txLog; + this.txManager = txManager; } public void run() { synchronized (this) { status = Status.STATUS_COMMITTING; } - for (Iterator i = rms.iterator(); i.hasNext();) { - TransactionBranch manager = i.next(); + for (int index = 0; index < rms.size(); ) { + TransactionBranch manager = rms.get(index); try { try { manager.getCommitter().commit(manager.getBranchId(), false); - i.remove(); + remove(index); + evercommit = true; } catch (XAException e) { log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e); if (e.errorCode == XAException.XA_HEURRB) { - i.remove(); + remove(index); log.info("Transaction has been heuristically rolled back"); cause = e; manager.getCommitter().forget(manager.getBranchId()); } else if (e.errorCode == XAException.XA_HEURMIX) { - i.remove(); + remove(index); 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) { - i.remove(); + remove(index); // 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 if (e.errorCode == XAException.XA_RETRY) { // do nothing, retry later + index++; + } else if (e.errorCode == XAException.XAER_RMFAIL) { + //refresh the xa resource from the NamedXAResourceFactory + if (manager.getCommitter() instanceof NamedXAResource) { + String xaResourceName = ((NamedXAResource)manager.getCommitter()).getName(); + NamedXAResourceFactory namedXAResourceFactory = txManager.getNamedXAResourceFactory(xaResourceName); + if (namedXAResourceFactory != null) { + try { + TransactionBranch newManager = new ReturnableTransactionBranch(manager.getBranchXid(), namedXAResourceFactory); + remove(index); + rms.add(index, newManager); + //loop will try this one again immediately. + } catch (SystemException e1) { + //try again later + index++; + } + } else { + //else hope NamedXAResourceFactory reappears soon. + index++; + } + } else { + //no hope + remove(index); + cause = e; + } } else { + //at least RMERR, which we can do nothing about //nothing we can do about it.... keep trying - i.remove(); + remove(index); cause = e; } } @@ -104,7 +129,7 @@ public class CommitTask implements Runna if (rms.isEmpty()) { try { - txLog.commit(xid, logMark); + txManager.getTransactionLog().commit(xid, logMark); synchronized (this) { status = Status.STATUS_COMMITTED; } @@ -113,7 +138,17 @@ public class CommitTask implements Runna cause = (XAException) new XAException("Unexpected error logging commit completion for xid " + xid).initCause(e); } } else { - retryScheduler.retry(this, count++); + synchronized (this) { + status = Status.STATUS_UNKNOWN; + } + txManager.getRetryScheduler().retry(this, count++); + } + } + + private void remove(int index) { + TransactionBranch manager = rms.remove(index); + if (manager instanceof ReturnableTransactionBranch) { + ((ReturnableTransactionBranch)manager).returnXAResource(); } } @@ -128,4 +163,5 @@ public class CommitTask implements Runna public int getStatus() { return status; } + } Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java Mon Oct 18 19:59:01 2010 @@ -48,9 +48,8 @@ import org.slf4j.LoggerFactory; public class RecoveryImpl implements Recovery { private static final Logger log = LoggerFactory.getLogger("Recovery"); - private final TransactionLog txLog; - private final XidFactory xidFactory; - private final RetryScheduler retryScheduler; + + private final TransactionManagerImpl txManager; private final Map externalXids = new HashMap(); private final Map ourXids = new HashMap(); @@ -59,23 +58,21 @@ public class RecoveryImpl implements Rec private final List recoveryErrors = new ArrayList(); - public RecoveryImpl(final TransactionLog txLog, final XidFactory xidFactory, RetryScheduler retryScheduler) { - this.txLog = txLog; - this.xidFactory = xidFactory; - this.retryScheduler = retryScheduler; + public RecoveryImpl(TransactionManagerImpl txManager) { + this.txManager = txManager; } public synchronized void recoverLog() throws XAException { Collection preparedXids; try { - preparedXids = txLog.recover(xidFactory); + preparedXids = txManager.getTransactionLog().recover(txManager.getXidFactory()); } catch (LogException e) { throw (XAException) new XAException(XAException.XAER_RMERR).initCause(e); } for (XidBranchesPair xidBranchesPair : preparedXids) { Xid xid = xidBranchesPair.getXid(); log.trace("read prepared global xid from log: " + toString(xid)); - if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) { + if (txManager.getXidFactory().matchesGlobalId(xid.getGlobalTransactionId())) { ourXids.put(new ByteArrayWrapper(xid.getGlobalTransactionId()), xidBranchesPair); for (TransactionBranchInfo transactionBranchInfo : xidBranchesPair.getBranches()) { log.trace("read branch from log: " + transactionBranchInfo.toString()); @@ -89,7 +86,7 @@ public class RecoveryImpl implements Rec } } else { log.trace("read external prepared xid from log: " + toString(xid)); - TransactionImpl externalTx = new ExternalTransaction(xid, txLog, retryScheduler, xidBranchesPair.getBranches()); + TransactionImpl externalTx = new ExternalTransaction(xid, txManager, xidBranchesPair.getBranches()); externalXids.put(xid, externalTx); externalGlobalIdMap.put(xid.getGlobalTransactionId(), externalTx); } @@ -123,7 +120,7 @@ public class RecoveryImpl implements Rec } else { log.trace("This xid was prepared from another XAResource, ignoring"); } - } else if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) { + } else if (txManager.getXidFactory().matchesGlobalId(xid.getGlobalTransactionId())) { //ours, but prepare not logged log.trace("this xid was initiated from this tm but not prepared: rolling back"); try { @@ -132,7 +129,7 @@ public class RecoveryImpl implements Rec recoveryErrors.add(e); log.error("Could not roll back", e); } - } else if (xidFactory.matchesBranchId(xid.getBranchQualifier())) { + } else if (txManager.getXidFactory().matchesBranchId(xid.getBranchQualifier())) { //our branch, but we did not start this tx. TransactionImpl externalTx = externalGlobalIdMap.get(xid.getGlobalTransactionId()); if (externalTx == null) { @@ -190,7 +187,7 @@ public class RecoveryImpl implements Rec if (xidBranchesPair.getBranches().isEmpty() && 0 != removed ) { try { ourXids.remove(new ByteArrayWrapper(xidBranchesPair.getXid().getGlobalTransactionId())); - txLog.commit(xidBranchesPair.getXid(), xidBranchesPair.getMark()); + txManager.getTransactionLog().commit(xidBranchesPair.getXid(), xidBranchesPair.getMark()); } catch (LogException e) { recoveryErrors.add(e); log.error("Could not commit", e); @@ -273,8 +270,8 @@ public class RecoveryImpl implements Rec private static class ExternalTransaction extends TransactionImpl { private final Set resourceNames = new HashSet(); - public ExternalTransaction(Xid xid, TransactionLog txLog, RetryScheduler retryScheduler, Set resourceNames) { - super(xid, txLog, retryScheduler); + public ExternalTransaction(Xid xid, TransactionManagerImpl txManager, Set resourceNames) { + super(xid, txManager); for (TransactionBranchInfo info: resourceNames) { this.resourceNames.add(info.getResourceName()); } Copied: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RollbackTask.java (from r1002829, geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java) URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RollbackTask.java?p2=geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RollbackTask.java&p1=geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java&r1=1002829&r2=1023970&rev=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/CommitTask.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RollbackTask.java Mon Oct 18 19:59:01 2010 @@ -20,13 +20,13 @@ package org.apache.geronimo.transaction.manager; -import java.util.Iterator; import java.util.List; 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.ReturnableTransactionBranch; import org.apache.geronimo.transaction.manager.TransactionImpl.TransactionBranch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,61 +34,89 @@ import org.slf4j.LoggerFactory; /** * @version $Rev$ $Date$ */ -public class CommitTask implements Runnable { - private static final Logger log = LoggerFactory.getLogger(CommitTask.class); +public class RollbackTask implements Runnable { + private static final Logger log = LoggerFactory.getLogger(RollbackTask.class); private final Xid xid; private final List rms; private final Object logMark; - private final RetryScheduler retryScheduler; - private final TransactionLog txLog; + private final TransactionManagerImpl txManager; private int count = 0; private int status; private XAException cause; - private boolean evercommit; + private boolean everRolledBack; - public CommitTask(Xid xid, List rms, Object logMark, RetryScheduler retryScheduler, TransactionLog txLog) { + public RollbackTask(Xid xid, List rms, Object logMark, TransactionManagerImpl txManager) { this.xid = xid; this.rms = rms; this.logMark = logMark; - this.retryScheduler = retryScheduler; - this.txLog = txLog; + this.txManager = txManager; } public void run() { synchronized (this) { - status = Status.STATUS_COMMITTING; + status = Status.STATUS_ROLLING_BACK; } - for (Iterator i = rms.iterator(); i.hasNext();) { - TransactionBranch manager = i.next(); + for (int index = 0; index < rms.size(); ) { + TransactionBranch manager = rms.get(index); try { try { - manager.getCommitter().commit(manager.getBranchId(), false); - i.remove(); + manager.getCommitter().rollback(manager.getBranchId()); + remove(index); + everRolledBack = true; } catch (XAException e) { log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e); if (e.errorCode == XAException.XA_HEURRB) { - i.remove(); + remove(index); + // let's not throw an exception as the transaction has been rolled back log.info("Transaction has been heuristically rolled back"); - cause = e; + everRolledBack = true; manager.getCommitter().forget(manager.getBranchId()); } else if (e.errorCode == XAException.XA_HEURMIX) { - i.remove(); + remove(index); log.info("Transaction has been heuristically committed and rolled back"); + everRolledBack = true; cause = e; - evercommit = true; 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 + remove(index); log.info("Transaction has been heuristically committed"); - evercommit = true; + cause = e; manager.getCommitter().forget(manager.getBranchId()); } else if (e.errorCode == XAException.XA_RETRY) { // do nothing, retry later + index++; + } else if (e.errorCode == XAException.XAER_RMFAIL) { + //refresh the xa resource from the NamedXAResourceFactory + if (manager.getCommitter() instanceof NamedXAResource) { + String xaResourceName = ((NamedXAResource)manager.getCommitter()).getName(); + NamedXAResourceFactory namedXAResourceFactory = txManager.getNamedXAResourceFactory(xaResourceName); + if (namedXAResourceFactory != null) { + try { + TransactionBranch newManager = new ReturnableTransactionBranch(manager.getBranchXid(), namedXAResourceFactory); + remove(index); + rms.add(index, newManager); + //loop will try this one again immediately. + } catch (SystemException e1) { + //try again later + index++; + } + } else { + //else hope NamedXAResourceFactory reappears soon. + index++; + } + } else { + //no hope + remove(index); + cause = e; + } } else { - //nothing we can do about it.... keep trying - i.remove(); + //at least these error codes: + // XAException.XA_RMERR + // XAException.XA_RBROLLBACK + // XAException.XAER_NOTA + //nothing we can do about it + remove(index); cause = e; } } @@ -104,16 +132,28 @@ public class CommitTask implements Runna if (rms.isEmpty()) { try { - txLog.commit(xid, logMark); + if (logMark != null) { + txManager.getTransactionLog().rollback(xid, logMark); + } synchronized (this) { - status = Status.STATUS_COMMITTED; + status = Status.STATUS_ROLLEDBACK; } } 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++); + synchronized (this) { + status = Status.STATUS_UNKNOWN; + } + txManager.getRetryScheduler().retry(this, count++); + } + } + + private void remove(int index) { + TransactionBranch manager = rms.remove(index); + if (manager instanceof ReturnableTransactionBranch) { + ((ReturnableTransactionBranch)manager).returnXAResource(); } } @@ -121,8 +161,8 @@ public class CommitTask implements Runna return cause; } - public boolean isEvercommit() { - return evercommit; + public boolean isEverRolledBack() { + return everRolledBack; } public int getStatus() { Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionImpl.java Mon Oct 18 19:59:01 2010 @@ -48,10 +48,8 @@ import org.slf4j.LoggerFactory; public class TransactionImpl implements Transaction { private static final Logger log = LoggerFactory.getLogger("Transaction"); - private final XidFactory xidFactory; + private final TransactionManagerImpl txManager; 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); @@ -63,18 +61,16 @@ public class TransactionImpl implements private final Map resources = new HashMap(); - TransactionImpl(XidFactory xidFactory, TransactionLog txnLog, RetryScheduler retryScheduler, long transactionTimeoutMilliseconds) throws SystemException { - this(xidFactory.createXid(), xidFactory, txnLog, retryScheduler, transactionTimeoutMilliseconds); + TransactionImpl(TransactionManagerImpl txManager, long transactionTimeoutMilliseconds) throws SystemException { + this(txManager.getXidFactory().createXid(), txManager, transactionTimeoutMilliseconds); } - TransactionImpl(Xid xid, XidFactory xidFactory, TransactionLog txnLog, RetryScheduler retryScheduler, long transactionTimeoutMilliseconds) throws SystemException { - this.xidFactory = xidFactory; - this.txnLog = txnLog; - this.retryScheduler = retryScheduler; + TransactionImpl(Xid xid, TransactionManagerImpl txManager, long transactionTimeoutMilliseconds) throws SystemException { + this.txManager = txManager; this.xid = xid; this.timeout = transactionTimeoutMilliseconds + TransactionTimer.getCurrentTime(); try { - txnLog.begin(xid); + txManager.getTransactionLog().begin(xid); } catch (LogException e) { status = Status.STATUS_MARKED_ROLLBACK; SystemException ex = new SystemException("Error logging begin; transaction marked for roll back)"); @@ -85,11 +81,9 @@ public class TransactionImpl implements } //reconstruct a tx for an external tx found in recovery - public TransactionImpl(Xid xid, TransactionLog txLog, RetryScheduler retryScheduler) { - this.xidFactory = null; - this.txnLog = txLog; + public TransactionImpl(Xid xid, TransactionManagerImpl txManager) { + this.txManager = txManager; this.xid = xid; - this.retryScheduler = retryScheduler; status = Status.STATUS_PREPARED; //TODO is this a good idea? this.timeout = Long.MAX_VALUE; @@ -204,8 +198,10 @@ public class TransactionImpl implements } } //we know nothing about this XAResource or resource manager - Xid branchId = xidFactory.createBranch(xid, resourceManagers.size() + 1); + Xid branchId = txManager.getXidFactory().createBranch(xid, resourceManagers.size() + 1); xaRes.start(branchId, XAResource.TMNOFLAGS); + //Set the xaresource timeout in seconds to match the time left in this tx. + xaRes.setTransactionTimeout((int)(timeout - TransactionTimer.getCurrentTime())/1000); activeXaResources.put(xaRes, addBranchXid(xaRes, branchId)); return true; } catch (XAException e) { @@ -266,7 +262,7 @@ public class TransactionImpl implements } if (status == Status.STATUS_MARKED_ROLLBACK) { - rollbackResourcesDuringCommit(resourceManagers, false); + rollbackResources(resourceManagers, false); if (timedout) { throw new RollbackException("Unable to commit: Transaction timeout"); } else { @@ -309,7 +305,7 @@ public class TransactionImpl implements // two-phase willCommit = internalPrepare(); } catch (SystemException e) { - rollbackResources(resourceManagers); + rollbackResources(resourceManagers, false); throw e; } @@ -326,7 +322,8 @@ public class TransactionImpl implements } else { // set everRollback to true here because the rollback here is caused by // XAException during the above internalPrepare - rollbackResourcesDuringCommit(resourceManagers, true); + rollbackResources(resourceManagers, true); + throw new RollbackException("transaction rolled back due to problems in prepare"); } } finally { afterCompletion(); @@ -365,7 +362,11 @@ public class TransactionImpl implements result = XAResource.XA_OK; } } else { - rollbackResources(rms); + try { + rollbackResources(rms, false); + } catch (HeuristicMixedException e) { + throw (SystemException)new SystemException("Unable to commit and heuristic exception during rollback").initCause(e); + } throw new RollbackException("Unable to commit"); } } finally { @@ -456,10 +457,10 @@ public class TransactionImpl implements // log our decision if (willCommit && !resourceManagers.isEmpty()) { try { - logMark = txnLog.prepare(xid, resourceManagers); + logMark = txManager.getTransactionLog().prepare(xid, resourceManagers); } catch (LogException e) { try { - rollbackResources(resourceManagers); + rollbackResources(resourceManagers, false); } catch (Exception se) { log.error("Unable to rollback after failure to log prepare", se.getCause()); } @@ -486,19 +487,10 @@ public class TransactionImpl implements endResources(); try { - rollbackResources(rms); - //only write rollback record if we have already written prepare record. - if (logMark != null) { - try { - txnLog.rollback(xid, logMark); - } catch (LogException e) { - try { - rollbackResources(rms); - } catch (Exception se) { - log.error("Unable to rollback after failure to log decision", se.getCause()); - } - throw (SystemException) new SystemException("Error logging rollback").initCause(e); - } + try { + rollbackResources(rms, false); + } catch (HeuristicMixedException e) { + throw (SystemException)new SystemException("Unable to roll back due to heuristics").initCause(e); } } finally { afterCompletion(); @@ -584,98 +576,19 @@ public class TransactionImpl implements } } - private void rollbackResources(List rms) throws SystemException { - SystemException cause = null; - synchronized (this) { - status = Status.STATUS_ROLLING_BACK; - } - try { - for (Iterator i = rms.iterator(); i.hasNext();) { - TransactionBranch manager = (TransactionBranch) i.next(); - try { - manager.getCommitter().rollback(manager.getBranchId()); - } catch (XAException e) { - log.error("Unexpected exception rolling back " + manager.getCommitter() + "; continuing with rollback", e); - if (e.errorCode == XAException.XA_HEURRB) { - // let's not set the cause here - log.info("Transaction has been heuristically rolled back " + manager.getCommitter() + "; continuing with rollback", e); - manager.getCommitter().forget(manager.getBranchId()); - } else if (e.errorCode == XAException.XA_RBROLLBACK - || e.errorCode == XAException.XAER_RMERR - || e.errorCode == XAException.XAER_NOTA - || e.errorCode == XAException.XAER_RMFAIL) { - // let's not set the cause here because we expect the transaction to be rolled back eventually - // TODO: for RMFAIL, it means resource unavailable temporarily. - // do we need keep sending request to resource to make sure the roll back completes? - } else if (cause == null) { - cause = new SystemException(e.errorCode); - } - } - } - } catch (XAException e) { - throw (SystemException) new SystemException("Error during rolling back").initCause(e); - } - - synchronized (this) { - status = Status.STATUS_ROLLEDBACK; - } - if (cause != null) { - throw cause; - } - } - - private void rollbackResourcesDuringCommit(List rms, boolean everRb) throws HeuristicMixedException, RollbackException, SystemException { - XAException cause = null; - boolean everRolledback = everRb; + private void rollbackResources(List rms, boolean everRb) throws HeuristicMixedException, SystemException { + RollbackTask rollbackTask = new RollbackTask(xid, rms, logMark, txManager); synchronized (this) { status = Status.STATUS_ROLLING_BACK; } - try { - for (Iterator i = rms.iterator(); i.hasNext();) { - TransactionBranch manager = (TransactionBranch) i.next(); - try { - manager.getCommitter().rollback(manager.getBranchId()); - everRolledback = true; - } catch (XAException e) { - if (e.errorCode == XAException.XA_HEURRB) { - // let's not set the cause here as the resulting behavior is same as requested behavior - log.error("Transaction has been heuristically rolled back " + manager.getCommitter() + "; continuing with rollback", e); - everRolledback = true; - manager.getCommitter().forget(manager.getBranchId()); - } else if (e.errorCode == XAException.XA_HEURMIX) { - log.error("Transaction has been heuristically committed and rolled back " + manager.getCommitter() + "; continuing with rollback", e); - cause = e; - everRolledback = true; - manager.getCommitter().forget(manager.getBranchId()); - } else if (e.errorCode == XAException.XA_HEURCOM) { - log.error("Transaction has been heuristically committed " + manager.getCommitter() + "; continuing with rollback", e); - cause = e; - manager.getCommitter().forget(manager.getBranchId()); - } else if (e.errorCode == XAException.XA_RBROLLBACK - || e.errorCode == XAException.XAER_RMERR - || e.errorCode == XAException.XAER_NOTA - || e.errorCode == XAException.XAER_RMFAIL) { - // XAException.XA_RBROLLBACK during commit/rollback, thus RollbackException is expected - // XAException.XAER_RMERR means transaction branch error and transaction has been rolled back - // let's not set the cause here because we expect the transaction to be rolled back eventually - // TODO: for RMFAIL, it means resource unavailable temporarily. - // do we need keep sending request to resource to make sure the roll back completes? - } else if (cause == null) { - cause = e; - } - } - } - } catch (XAException e) { - throw (SystemException) new SystemException("System error during commit/rolling back").initCause(e); - } - + rollbackTask.run(); synchronized (this) { - status = Status.STATUS_ROLLEDBACK; + status = rollbackTask.getStatus(); } + XAException cause = rollbackTask.getCause(); + boolean everRolledback = everRb || rollbackTask.isEverRolledBack(); - if (cause == null) { - throw (RollbackException) new RollbackException("Unable to commit: transaction marked for rollback").initCause(cause); - } else { + if (cause != null) { if (cause.errorCode == XAException.XA_HEURCOM && everRolledback) { throw (HeuristicMixedException) new HeuristicMixedException("HeuristicMixed error during commit/rolling back").initCause(cause); } else if (cause.errorCode == XAException.XA_HEURMIX) { @@ -753,7 +666,7 @@ public class TransactionImpl implements } private void commitResources(List rms) throws HeuristicRollbackException, HeuristicMixedException, SystemException { - CommitTask commitTask = new CommitTask(xid, rms, logMark, retryScheduler, txnLog); + CommitTask commitTask = new CommitTask(xid, rms, logMark, txManager); synchronized (this) { status = Status.STATUS_COMMITTING; } @@ -855,5 +768,16 @@ public class TransactionImpl implements } } + static class ReturnableTransactionBranch extends TransactionBranch { + private final NamedXAResourceFactory namedXAResourceFactory; + + ReturnableTransactionBranch(Xid branchId, NamedXAResourceFactory namedXAResourceFactory) throws SystemException { + super(namedXAResourceFactory.getNamedXAResource(), branchId); + this.namedXAResourceFactory = namedXAResourceFactory; + } + public void returnXAResource() { + namedXAResourceFactory.returnNamedXAResource((NamedXAResource) getCommitter()); + } + } } Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java Mon Oct 18 19:59:01 2010 @@ -45,8 +45,8 @@ public class TransactionManagerImpl impl protected static final int DEFAULT_TIMEOUT = 600; protected static final byte[] DEFAULT_TM_ID = new byte[] {71,84,77,73,68}; - final TransactionLog transactionLog; - final XidFactory xidFactory; + private final TransactionLog transactionLog; + private final XidFactory xidFactory; private final int defaultTransactionTimeoutMilliseconds; private final ThreadLocal transactionTimeoutMilliseconds = new ThreadLocal(); private final ThreadLocal threadTx = new ThreadLocal(); @@ -100,7 +100,7 @@ public class TransactionManagerImpl impl this.xidFactory = new XidFactoryImpl(DEFAULT_TM_ID); } - recovery = new RecoveryImpl(this.transactionLog, this.xidFactory, retryScheduler); + recovery = new RecoveryImpl(this); recovery.recoverLog(); } @@ -156,7 +156,7 @@ public class TransactionManagerImpl impl if (getStatus() != Status.STATUS_NO_TRANSACTION) { throw new NotSupportedException("Nested Transactions are not supported"); } - TransactionImpl tx = new TransactionImpl(xidFactory, transactionLog, retryScheduler, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds)); + TransactionImpl tx = new TransactionImpl(this, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds)); // timeoutTimer.schedule(tx, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds)); try { associate(tx); @@ -274,7 +274,7 @@ public class TransactionManagerImpl impl if (transactionTimeoutMilliseconds < 0) { throw new SystemException("transaction timeout must be positive or 0 to reset to default"); } - return new TransactionImpl(xid, xidFactory, transactionLog, retryScheduler, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds)); + return new TransactionImpl(xid, this, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds)); } public void commit(Transaction tx, boolean onePhase) throws XAException { @@ -357,6 +357,22 @@ public class TransactionManagerImpl impl namedXAResourceFactories.remove(namedXAResourceFactoryName); } + NamedXAResourceFactory getNamedXAResourceFactory(String xaResourceName) { + return namedXAResourceFactories.get(xaResourceName); + } + + XidFactory getXidFactory() { + return xidFactory; + } + + TransactionLog getTransactionLog() { + return transactionLog; + } + + RetryScheduler getRetryScheduler() { + return retryScheduler; + } + public Map getExternalXids() { return new HashMap(recovery.getExternalXids()); } Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java Mon Oct 18 19:59:01 2010 @@ -38,14 +38,17 @@ public abstract class AbstractRecoveryTe protected TransactionLog txLog; protected final XidFactory xidFactory = new XidFactoryImpl(); - protected final RetryScheduler retryScheduler = new ExponentialtIntervalRetryScheduler(); + protected TransactionManagerImpl txManager; private static final String RM1 = "rm1"; private static final String RM2 = "rm2"; private static final String RM3 = "rm3"; private static final int XID_COUNT = 3; private int branchCounter; - public void testDummy() throws Exception {} + @Override + protected void setUp() throws Exception { + txManager = new TransactionManagerImpl(1, xidFactory, txLog); + } public void test2ResOnlineAfterRecoveryStart() throws Exception { Xid[] xids = getXidArray(XID_COUNT); @@ -56,8 +59,7 @@ public abstract class AbstractRecoveryTe addBranch(txInfos, xares2); prepareLog(txLog, txInfos); prepareForReplay(); - Recovery recovery = new RecoveryImpl(txLog, xidFactory, retryScheduler); - recovery.recoverLog(); + Recovery recovery = txManager.recovery; assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); assertTrue(!recovery.localRecoveryComplete()); @@ -105,8 +107,7 @@ public abstract class AbstractRecoveryTe addBranch(txInfos23, xares3); prepareLog(txLog, txInfos23); prepareForReplay(); - Recovery recovery = new RecoveryImpl(txLog, xidFactory, retryScheduler); - recovery.recoverLog(); + Recovery recovery = txManager.recovery; assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); assertEquals(XID_COUNT * 3, recovery.localUnrecoveredCount()); Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java Mon Oct 18 19:59:01 2010 @@ -54,6 +54,7 @@ public class HOWLLogRecoveryTest extends } } setUpHowlLog(); + super.setUp(); } private void setUpHowlLog() throws Exception { @@ -86,6 +87,7 @@ public class HOWLLogRecoveryTest extends protected void prepareForReplay() throws Exception { tearDown(); setUpHowlLog(); + super.setUp(); } public static Test suite() { Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java Mon Oct 18 19:59:01 2010 @@ -27,6 +27,7 @@ public class MockLogRecoveryTest extends protected void setUp() throws Exception { txLog = new MockLog(); + super.setUp(); } protected void tearDown() throws Exception { @@ -34,5 +35,6 @@ public class MockLogRecoveryTest extends } protected void prepareForReplay() throws Exception { + txManager.recovery.recoverLog(); } } Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/RecoveryTest.java Mon Oct 18 19:59:01 2010 @@ -36,14 +36,19 @@ import junit.framework.TestCase; public class RecoveryTest extends TestCase { XidFactory xidFactory = new XidFactoryImpl(); - protected final RetryScheduler retryScheduler = new ExponentialtIntervalRetryScheduler(); + MockLog mockLog = new MockLog(); + protected TransactionManagerImpl txManager; private final String RM1 = "rm1"; private final String RM2 = "rm2"; private final String RM3 = "rm3"; private int count = 0; + @Override + protected void setUp() throws Exception { + txManager = new TransactionManagerImpl(1, xidFactory, mockLog); + } + public void testCommittedRMToBeRecovered() throws Exception { - MockLog mockLog = new MockLog(); Xid[] xids = getXidArray(1); // specifies an empty Xid array such that this XAResource has nothing // to recover. This means that the presumed abort protocol has failed @@ -53,7 +58,7 @@ public class RecoveryTest extends TestCa MockTransactionInfo[] txInfos = makeTxInfos(xids); addBranch(txInfos, xares1); prepareLog(mockLog, txInfos); - Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler); + Recovery recovery = new RecoveryImpl(txManager); recovery.recoverLog(); assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); @@ -65,7 +70,6 @@ public class RecoveryTest extends TestCa } public void test2ResOnlineAfterRecoveryStart() throws Exception { - MockLog mockLog = new MockLog(); Xid[] xids = getXidArray(3); MockXAResource xares1 = new MockXAResource(RM1); MockXAResource xares2 = new MockXAResource(RM2); @@ -73,7 +77,7 @@ public class RecoveryTest extends TestCa addBranch(txInfos, xares1); addBranch(txInfos, xares2); prepareLog(mockLog, txInfos); - Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler); + Recovery recovery = new RecoveryImpl(txManager); recovery.recoverLog(); assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); @@ -106,7 +110,6 @@ public class RecoveryTest extends TestCa } public void test3ResOnlineAfterRecoveryStart() throws Exception { - MockLog mockLog = new MockLog(); Xid[] xids12 = getXidArray(3); List xids12List = Arrays.asList(xids12); Xid[] xids13 = getXidArray(3); @@ -141,7 +144,7 @@ public class RecoveryTest extends TestCa addBranch(txInfos23, xares2); addBranch(txInfos23, xares3); prepareLog(mockLog, txInfos23); - Recovery recovery = new RecoveryImpl(mockLog, xidFactory, retryScheduler); + Recovery recovery = new RecoveryImpl(txManager); recovery.recoverLog(); assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); Modified: geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/TransactionManagerImplTest.java URL: http://svn.apache.org/viewvc/geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/TransactionManagerImplTest.java?rev=1023970&r1=1023969&r2=1023970&view=diff ============================================================================== --- geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/TransactionManagerImplTest.java (original) +++ geronimo/components/txmanager/branches/geronimo-txmanager-parent-2.2/geronimo-transaction/src/test/java/org/apache/geronimo/transaction/manager/TransactionManagerImplTest.java Mon Oct 18 19:59:01 2010 @@ -244,7 +244,7 @@ public class TransactionManagerImplTest //This test depends on using the resource that will be recovered by the resource manager. public void testSimpleRecovery() throws Exception { //create a transaction in our own transaction manager - Xid xid = tm.xidFactory.createXid(); + Xid xid = tm.getXidFactory().createXid(); Transaction tx = tm.importXid(xid, 0); tm.resume(tx); assertSame(tx, tm.getTransaction());