Details
-
Bug
-
Resolution: Done
-
Major
-
5.10.3.Final
-
None
Description
XAResourceRecord.topLevelPrepare maps XA_RB* codes as PREPARE_NOTOK, which causes ArjunaCore to re-queue the record on the pending list and subsequently call topLevelAbort. This is incorrect from an XA spec perspective, as XA_RB at prepare indicates the RM has terminated and forgotten the tx, so a rollback thereafter may causes unexpected problems.
Whereas the elegant fix is probably a new TwoPhaseOutcome to distinguish 'NOTOK, don't call me again' from 'NOTOK, roll me back', that's a bit of a pain. The alternative is to leverage the mechanism we already have for employing this optimization in cases where we can, and extend it to cases where we should.
switch (e1.errorCode) { case XAException.XA_RBROLLBACK: case XAException.XA_RBEND: case XAException.XA_RBCOMMFAIL: case XAException.XA_RBDEADLOCK: case XAException.XA_RBINTEGRITY: case XAException.XA_RBOTHER: case XAException.XA_RBPROTO: case XAException.XA_RBTIMEOUT: // we may want to pull XAER_NOTA up here too? if (_theTransaction != null) { _theTransaction.setXAResourceState(_theXAResource, TxInfo.OPTIMIZED_ROLLBACK); // in a perfect word we'd call removeConnection here, but we probably need to do in in topLevelAbort instead, unless we change its implementation } // now fall through... case XAException.XAER_RMERR: case XAException.XAER_RMFAIL: case XAException.XAER_INVAL: case XAException.XAER_PROTO: case XAException.XAER_NOTA: // resource may have arbitrarily rolled back (shouldn't, but ...) return TwoPhaseOutcome.PREPARE_NOTOK; // will not call rollback [*cough*bullshit*cough*] default: return TwoPhaseOutcome.HEURISTIC_HAZARD; // we're not really sure (shouldn't get here though). }