User: osh
Date: 00/10/18 07:28:53
Modified: src/main/org/jboss/tm TxCapsule.java
Log:
Fix for possible race on instance reuse.
More trace information.
Still outstanding: A problem with invalid XA resource state during
XA resource calls.
Revision Changes Path
1.15 +132 -36 jboss/src/main/org/jboss/tm/TxCapsule.java
Index: TxCapsule.java
===================================================================
RCS file: /products/cvs/ejboss/jboss/src/main/org/jboss/tm/TxCapsule.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- TxCapsule.java 2000/10/15 19:05:07 1.14
+++ TxCapsule.java 2000/10/18 14:28:53 1.15
@@ -43,7 +43,7 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Ole Husgaard</a>
*
- * @version $Revision: 1.14 $
+ * @version $Revision: 1.15 $
*/
class TxCapsule implements TimeoutTarget
{
@@ -87,6 +87,9 @@
{
xid = new XidImpl();
this.tm = tm;
+
+ if (trace)
+ Logger.debug("TxCapsule: Created new instance for tx=" + toString());
}
/**
@@ -118,6 +121,9 @@
start = System.currentTimeMillis();
this.timeout = TimeoutFactory.createTimeout(start+timeout, this);
+
+ if (trace)
+ Logger.debug("TxCapsule: Reused instance for tx=" + toString());
}
// Public --------------------------------------------------------
@@ -130,7 +136,8 @@
try {
lock();
- Logger.warning("Transaction " + toString() + " timed out.");
+ Logger.warning("Transaction " + toString() + " timed out." +
+ " status=" + getStringStatus(status));
if (this.timeout == null)
return; // Don't race with timeout cancellation.
@@ -167,6 +174,7 @@
rollbackResources();
doAfterCompletion();
gotHeuristic(null, XAException.XA_HEURRB);
+ instanceDone();
return;
case Status.STATUS_PREPARING:
@@ -174,7 +182,8 @@
return; // commit will fail
default:
- Logger.warning("TxCapsule: Unknown status at timeout.");
+ Logger.warning("TxCapsule: Unknown status at timeout, tx=" +
+ toString());
return;
}
} finally {
@@ -225,8 +234,8 @@
lock();
if (trace)
- Logger.debug("TxCapsule.commit(): Entered, status=" +
- getStringStatus(status));
+ Logger.debug("TxCapsule.commit(): Entered, tx=" + toString() +
+ " status=" + getStringStatus(status));
switch (status) {
case Status.STATUS_PREPARING:
@@ -268,7 +277,8 @@
if (trace)
Logger.debug("TxCapsule.commit(): Before completion done, " +
- "status=" + getStringStatus(status));
+ "tx=" + toString() +
+ " status=" + getStringStatus(status));
endResources();
@@ -309,8 +319,8 @@
doAfterCompletion();
cancelTimeout();
instanceDone();
- throw new RollbackException("Unable to commit, status=" +
- getStringStatus(status));
+ throw new RollbackException("Unable to commit, tx=" + toString() +
+ " status=" + getStringStatus(status));
}
cancelTimeout();
@@ -319,7 +329,8 @@
checkHeuristics();
if (trace)
- Logger.debug("TxCapsule.commit(): Committed OK.");
+ Logger.debug("TxCapsule.commit(): Transaction " + toString() +
+ " committed OK.");
} finally {
unlock();
@@ -340,8 +351,8 @@
lock();
if (trace)
- Logger.debug("TxCapsule.rollback(): Entered, status=" +
- getStringStatus(status));
+ Logger.debug("TxCapsule.rollback(): Entered, tx=" + toString() +
+ " status=" + getStringStatus(status));
switch (status) {
case Status.STATUS_ACTIVE:
@@ -361,7 +372,9 @@
status = Status.STATUS_MARKED_ROLLBACK;
return; // commit() will do rollback.
default:
- throw new IllegalStateException("Cannot rollback(), status=" +
+ throw new IllegalStateException("Cannot rollback(), " +
+ "tx=" + toString() +
+ " status=" +
getStringStatus(status));
}
} finally {
@@ -383,8 +396,8 @@
lock();
if (trace)
- Logger.debug("TxCapsule.setRollbackOnly(): Entered, status=" +
- getStringStatus(status));
+ Logger.debug("TxCapsule.setRollbackOnly(): Entered, tx=" +
+ toString() + " status=" + getStringStatus(status));
switch (status) {
case Status.STATUS_ACTIVE:
@@ -438,8 +451,8 @@
lock();
if (trace)
- Logger.debug("TxCapsule.delistResource(): Entered, status=" +
- getStringStatus(status));
+ Logger.debug("TxCapsule.delistResource(): Entered, tx=" +
+ toString() + " status=" + getStringStatus(status));
int idx = findResource(xaRes);
@@ -481,6 +494,8 @@
}
return true;
} catch(XAException e) {
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
status = Status.STATUS_MARKED_ROLLBACK;
return false;
@@ -509,8 +524,8 @@
lock();
if (trace)
- Logger.debug("TxCapsule.enlistResource(): Entered, status=" +
- getStringStatus(status));
+ Logger.debug("TxCapsule.enlistResource(): Entered, tx=" +
+ toString() + " status=" + getStringStatus(status));
switch (status) {
case Status.STATUS_ACTIVE:
@@ -569,6 +584,8 @@
addResource(xaRes);
return true;
} catch(XAException e) {
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
return false;
}
@@ -603,7 +620,8 @@
if (trace)
Logger.debug("TxCapsule.registerSynchronization(): Entered, " +
- "status=" + getStringStatus(status));
+ "tx=" + toString() +
+ " status=" + getStringStatus(status));
switch (status) {
case Status.STATUS_ACTIVE:
@@ -796,15 +814,76 @@
}
/**
+ * Return a string representation of the given XA error code.
+ */
+ private String getStringXAErrorCode(int errorCode) {
+ switch (errorCode) {
+ case XAException.XA_HEURCOM:
+ return "XA_HEURCOM";
+ case XAException.XA_HEURHAZ:
+ return "XA_HEURHAZ";
+ case XAException.XA_HEURMIX:
+ return "XA_HEURMIX";
+ case XAException.XA_HEURRB:
+ return "XA_HEURRB";
+
+ case XAException.XA_NOMIGRATE:
+ return "XA_NOMIGRATE";
+
+ case XAException.XA_RBCOMMFAIL:
+ return "XA_RBCOMMFAIL";
+ case XAException.XA_RBDEADLOCK:
+ return "XA_RBDEADLOCK";
+ case XAException.XA_RBINTEGRITY:
+ return "XA_RBINTEGRITY";
+ case XAException.XA_RBOTHER:
+ return "XA_RBOTHER";
+ case XAException.XA_RBPROTO:
+ return "XA_RBPROTO";
+ case XAException.XA_RBROLLBACK:
+ return "XA_RBROLLBACK";
+ case XAException.XA_RBTIMEOUT:
+ return "XA_RBTIMEOUT";
+ case XAException.XA_RBTRANSIENT:
+ return "XA_RBTRANSIENT";
+
+ case XAException.XA_RDONLY:
+ return "XA_RDONLY";
+ case XAException.XA_RETRY:
+ return "XA_RETRY";
+
+ case XAException.XAER_ASYNC:
+ return "XAER_ASYNC";
+ case XAException.XAER_DUPID:
+ return "XAER_DUPID";
+ case XAException.XAER_INVAL:
+ return "XAER_INVAL";
+ case XAException.XAER_NOTA:
+ return "XAER_NOTA";
+ case XAException.XAER_OUTSIDE:
+ return "XAER_OUTSIDE";
+ case XAException.XAER_PROTO:
+ return "XAER_PROTO";
+ case XAException.XAER_RMERR:
+ return "XAER_RMERR";
+ case XAException.XAER_RMFAIL:
+ return "XAER_RMFAIL";
+
+ default:
+ return "XA_UNKNOWN(" + errorCode + ")";
+ }
+ }
+
+ /**
* Lock this instance.
*/
private synchronized void lock()
{
if (done)
- throw new IllegalStateException("No transaction");
+ throw new IllegalStateException("Transaction has terminated");
if (locked) {
- Logger.warning("TxCapsule: Lock contention."); // Good for debugging.
+ Logger.warning("TxCapsule: Lock contention, tx=" + toString());
Thread.currentThread().dumpStack();
long myIncarnation = incarnationCount;
@@ -813,11 +892,15 @@
try {
wait();
} catch (InterruptedException ex) {}
+
+ // MF FIXME: don't we need a notify() in this case?
+ // we need to release all the thread waiting on this lock
- // MF FIXME: don't we need a notify() in this case?
- // we need to release all the thread waiting on this lock
+ // OSH: notifyAll() is done in instanceDone()
+ // and notify() is done in unlock().
+
if (done || myIncarnation != incarnationCount)
- throw new IllegalStateException("No transaction");
+ throw new IllegalStateException("Transaction has now terminated");
}
}
@@ -829,8 +912,11 @@
*/
private synchronized void unlock()
{
- if (!locked)
- Logger.warning("TxCapsule: Unlocking, but not locked.");
+ if (!locked) {
+ Logger.warning("TxCapsule: Unlocking, but not locked, tx=" +
+ toString());
+ Logger.exception(new Exception("[Stack trace]"));
+ }
locked = false;
@@ -918,6 +1004,7 @@
") entered: " + xaRes.toString() +
" flags=" + flags);
unlock();
+ // OSH FIXME: resourceState could be incorrect during this callout.
try {
xaRes.start(xid, flags);
} finally {
@@ -935,17 +1022,18 @@
private void endResource(XAResource xaRes, int flag)
throws XAException
{
- Logger.debug("TxCapsule.endResource(" + xid.toString() +
+ Logger.debug("TxCapsule.endResource(" + xid.toString() +
") entered: " + xaRes.toString() +
" flag=" + flag);
unlock();
+ // OSH FIXME: resourceState could be incorrect during this callout.
try {
xaRes.end(xid, flag);
} finally {
lock();
- Logger.debug("TxCapsule.endResource(" + xid.toString() +
- ") leaving: " + xaRes.toString() +
- " flag=" + flag);
+ Logger.debug("TxCapsule.endResource(" + xid.toString() +
+ ") leaving: " + xaRes.toString() +
+ " flag=" + flag);
}
}
@@ -978,8 +1066,8 @@
resourceState[i] = RS_ENDED;
}
} catch(XAException e) {
- Logger.debug("endresources: XAException: " + e);
- Logger.debug("endresources: XAException: errorCode=" + e.errorCode);
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
status = Status.STATUS_MARKED_ROLLBACK;
}
@@ -1061,6 +1149,8 @@
unlock();
resource.forget(xid);
} catch (XAException e) {
+ Logger.warning("XAException at forget(): errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
} finally {
lock();
@@ -1107,6 +1197,10 @@
*/
private void instanceDone()
{
+ // Notify transaction fronts that we are done.
+ for (int i = 0; i < transactionCount; ++i)
+ transactions[i].setDone();
+
synchronized (this) {
// Done with this incarnation.
++incarnationCount;
@@ -1119,10 +1213,6 @@
notifyAll();
}
- // Notify transaction fronts that we are done.
- for (int i = 0; i < transactionCount; ++i)
- transactions[i].setDone();
-
// Clear content of collections.
syncCount = 0;
transactionCount = 0;
@@ -1193,6 +1283,8 @@
status = Status.STATUS_MARKED_ROLLBACK;
break;
default:
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
if (status == Status.STATUS_PREPARING)
status = Status.STATUS_MARKED_ROLLBACK;
@@ -1240,6 +1332,8 @@
gotHeuristic(resources[i], e.errorCode);
break;
default:
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
break;
}
@@ -1281,6 +1375,8 @@
gotHeuristic(resources[i], e.errorCode);
break;
default:
+ Logger.warning("XAException: tx=" + toString() + " errorCode=" +
+ getStringXAErrorCode(e.errorCode));
Logger.exception(e);
break;
}