[GERONIMO-6543] Aries/Geronimo XA transaction recovery not working for heuristically completed transactions
git-svn-id: https://svn.apache.org/repos/asf/geronimo/components/txmanager/trunk@1684215 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java b/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java
index caa691d..0f5da05 100644
--- a/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java
+++ b/geronimo-transaction/src/main/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java
@@ -114,12 +114,7 @@
// This is a bit wasteful, but given our management of XAResources by "name", is about the best we can do.
if (isNameInTransaction(xidNamesPair, name, xid)) {
log.trace("This xid was prepared from this XAResource: committing");
- try {
- xaResource.commit(xid, false);
- } catch(XAException e) {
- recoveryErrors.add(e);
- log.error("Recovery error", e);
- }
+ commit(xaResource, xid);
removeNameFromTransaction(xidNamesPair, name, true);
} else {
log.trace("This xid was prepared from another XAResource, ignoring");
@@ -127,24 +122,14 @@
} 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 {
- xaResource.rollback(xid);
- } catch (XAException e) {
- recoveryErrors.add(e);
- log.error("Could not roll back", e);
- }
+ rollback(xaResource, xid);
} 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) {
//we did not prepare this branch, rollback.
log.trace("this xid is from an external transaction and was not prepared: rolling back");
- try {
- xaResource.rollback(xid);
- } catch (XAException e) {
- recoveryErrors.add(e);
- log.error("Could not roll back", e);
- }
+ rollback(xaResource, xid);
} else {
log.trace("this xid is from an external transaction and was prepared in this tm. Waiting for instructions from transaction originator");
//we prepared this branch, must wait for commit/rollback command.
@@ -161,6 +146,48 @@
}
}
+ private void commit(NamedXAResource xaResource, Xid xid) {
+ doCommitOrRollback(xaResource, xid, true);
+ }
+
+ private void rollback(NamedXAResource xaResource, Xid xid) {
+ doCommitOrRollback(xaResource, xid, false);
+ }
+
+ private void doCommitOrRollback(NamedXAResource xaResource, Xid xid, boolean commit) {
+ try {
+ if (commit) {
+ xaResource.commit(xid, false);
+ } else {
+ xaResource.rollback(xid);
+ }
+ } catch (XAException e) {
+ try {
+ if (e.errorCode == XAException.XA_HEURRB) {
+ log.info("Transaction has been heuristically rolled back");
+ xaResource.forget(xid);
+ } else if (e.errorCode == XAException.XA_HEURMIX) {
+ log.info("Transaction has been heuristically committed and rolled back");
+ xaResource.forget(xid);
+ } else if (e.errorCode == XAException.XA_HEURCOM) {
+ log.info("Transaction has been heuristically committed");
+ xaResource.forget(xid);
+ } else {
+ recoveryErrors.add(e);
+ log.error("Could not roll back", e);
+ }
+ } catch (XAException e2) {
+ if (e2.errorCode == XAException.XAER_NOTA) {
+ // NOTA in response to forget, means the resource already forgot the transaction
+ // ignore
+ } else {
+ recoveryErrors.add(e);
+ log.error("Could not roll back", e);
+ }
+ }
+ }
+ }
+
private boolean isNameInTransaction(XidBranchesPair xidBranchesPair, String name, Xid xid) {
for (TransactionBranchInfo transactionBranchInfo : xidBranchesPair.getBranches()) {
if (name.equals(transactionBranchInfo.getResourceName()) && equals(xid, transactionBranchInfo.getBranchXid())) {