Skip to content
Permalink
Browse files
merge rev 727474(GERONIMO-4471), rev 727065 (GERONIMO-4461 GERONIMO-4…
…466) from branch 2.1

git-svn-id: https://svn.apache.org/repos/asf/geronimo/components/txmanager/trunk@727489 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Lin Sun committed Dec 17, 2008
1 parent af10721 commit 9c835870a057352782965e250298e52fde900f80
Showing 3 changed files with 132 additions and 19 deletions.
@@ -28,6 +28,8 @@
import java.util.HashSet;
import java.util.Collection;

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.SystemException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
@@ -247,7 +249,7 @@ public void removeName(String name) {
resourceNames.remove(name);
}

public void preparedCommit() throws SystemException {
public void preparedCommit() throws HeuristicRollbackException, HeuristicMixedException, SystemException {
if (!resourceNames.isEmpty()) {
throw new SystemException("This tx does not have all resource managers online, commit not allowed yet");
}
@@ -265,7 +265,7 @@ public void commit() throws HeuristicMixedException, HeuristicRollbackException,
}

if (status == Status.STATUS_MARKED_ROLLBACK) {
rollbackResources(resourceManagers);
rollbackResourcesDuringCommit(resourceManagers, false);
if (timedout) {
throw new RollbackException("Transaction timeout");
} else {
@@ -309,7 +309,20 @@ public void commit() throws HeuristicMixedException, HeuristicRollbackException,
synchronized (this) {
status = Status.STATUS_ROLLEDBACK;
}
throw (RollbackException) new RollbackException("Error during one-phase commit").initCause(e);

if (e.errorCode == XAException.XA_HEURRB) {
manager.getCommitter().forget(manager.getBranchId());
throw (HeuristicRollbackException) new HeuristicRollbackException("Error during one-phase commit").initCause(e);
} else if (e.errorCode == XAException.XA_HEURMIX) {
manager.getCommitter().forget(manager.getBranchId());
throw (HeuristicMixedException) new HeuristicMixedException("Error during one-phase commit").initCause(e);
} 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");
manager.getCommitter().forget(manager.getBranchId());
} else {
throw (RollbackException) new RollbackException("Error during one-phase commit").initCause(e);
}
}
}

@@ -320,9 +333,12 @@ public void commit() throws HeuristicMixedException, HeuristicRollbackException,
if (willCommit) {
commitResources(resourceManagers);
} else {
rollbackResources(resourceManagers);
throw new RollbackException("Unable to commit");
// set everRollback to true here because the rollback here is caused by
// XAException during the above internalPrepare
rollbackResourcesDuringCommit(resourceManagers, true);
}
} catch (XAException e) {
throw (SystemException) new SystemException("Error during commit").initCause(e);
} finally {
afterCompletion();
synchronized (this) {
@@ -375,7 +391,7 @@ int prepare() throws SystemException, RollbackException {
}

//used from XATerminator for commit phase of non-readonly remotely controlled tx.
void preparedCommit() throws SystemException {
void preparedCommit() throws HeuristicRollbackException, HeuristicMixedException, SystemException {
try {
commitResources(resourceManagers);
} finally {
@@ -423,8 +439,13 @@ private boolean internalPrepare() throws SystemException {
} catch (XAException e) {
synchronized (this) {
status = Status.STATUS_MARKED_ROLLBACK;
//TODO document why this is true from the spec.
//XAException during prepare means we can assume resource is rolled back.
/* Per JTA spec, If the resource manager wants to roll back the transaction,
it should do so by throwing an appropriate XAException in the prepare method.
Also per OTS spec:
The resource can return VoteRollback under any circumstances, including not having
any knowledge about the transaction (which might happen after a crash). If this
response is returned, the transaction must be rolled back. Furthermore, the Transaction
Service is not required to perform any additional operations on this resource.*/
rms.remove();
break;
}
@@ -586,6 +607,7 @@ private void rollbackResources(List rms) throws SystemException {
}
}
}

synchronized (this) {
status = Status.STATUS_ROLLEDBACK;
}
@@ -594,21 +616,96 @@ private void rollbackResources(List rms) throws SystemException {
}
}

private void commitResources(List rms) throws SystemException {
SystemException cause = null;
private void rollbackResourcesDuringCommit(List rms, boolean everRb) throws HeuristicMixedException, RollbackException, SystemException {
XAException cause = null;
boolean everRolledback = everRb;
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
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 (cause == null) {
cause = e;
}
}
}
} catch (XAException e) {
throw (SystemException) new SystemException("Error during rolling back").initCause(e);
}

synchronized (this) {
status = Status.STATUS_ROLLEDBACK;
}

if (cause == null) {
throw (RollbackException) new RollbackException("Error during two phase commit").initCause(cause);
} else {
if (cause.errorCode == XAException.XA_HEURCOM && everRolledback) {
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 void commitResources(List rms) throws HeuristicRollbackException, HeuristicMixedException, SystemException {
XAException cause = null;
boolean evercommit = false;
synchronized (this) {
status = Status.STATUS_COMMITTING;
}
for (Iterator i = rms.iterator(); i.hasNext();) {
TransactionBranch manager = (TransactionBranch) i.next();
try {
manager.getCommitter().commit(manager.getBranchId(), false);
} catch (XAException e) {
log.error("Unexpected exception committing" + manager.getCommitter() + "; continuing to commit other RMs", e);
if (cause == null) {
cause = new SystemException(e.errorCode);
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) {
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()) {
@@ -623,7 +720,17 @@ private void commitResources(List rms) throws SystemException {
status = Status.STATUS_COMMITTED;
}
if (cause != null) {
throw cause;
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 if (cause.errorCode == XAException.XA_HEURCOM) {
// ignore don't need to inform the tx originator
} else {
throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
}
}
}

@@ -294,6 +294,10 @@ public void commit(Transaction tx, boolean onePhase) throws XAException {
} else {
try {
((TransactionImpl) tx).preparedCommit();
} catch (HeuristicMixedException e) {
throw (XAException) new XAException().initCause(e);
} catch (HeuristicRollbackException e) {
throw (XAException) new XAException().initCause(e);
} catch (SystemException e) {
throw (XAException) new XAException().initCause(e);
}

0 comments on commit 9c83587

Please sign in to comment.