3 Replies Latest reply on Feb 19, 2009 8:14 AM by Jonathan Halliday

    Help with TxControl.readonlyOptimisation

    Mauro Molinari Novice

      I'm using JBoss-JTA 4.5.0GA (just migrated from 4.4.0GA because of the following problem) and I'm facing a problem.

      We are managing two different datasources with JBossTS.
      The problem arises when we open a transaction which involves two resources.

      When committing this transaction the following happens:
      - UserTransactionImple.commit() is called
      - it then calls TransactionImple.commitAndDisassociate()
      - this calls commit(boolean) which immediately calls super.end(boolean)
      - parent() returns null (we are at top level) and, after beforeCompletion, super.End(boolean) is called
      - actionStatus is RUNNING, so we reach line 1775
      - pendingList contains two resource records, one for each of the resource involved (I'm working with a Postgres DBMS and with an Oracle DBMS); this is correct!
      - doOnePhase() of course returns false, so we go to BasicAction.prepare(boolean)
      - we are allowed to commit and actionType is TOP_LEVEL, while store() is not null, so we can get to BasicAction.createPreparedLists(), then we reach line 2419 where BasicAction.doPrepare(boolean) is called
      - we iterate over the pendingList: on the first one, doPrepare(boolean, AbstractRecord) returns TwoPhaseOutcome.PREPARE_READONLY and the record is inserted into readonlyList, while on the second one the prepare phase returns TwoPhaseOutcome.PREPARE_OK and the record is inserted into preparedList (always passing through XAResourceRecord.topLevelPrepare()); in other words, for one resource the prepare phase returns a READONLY, for the other it returns OK
      - when we get back to End(boolean) we have that the overall outcome is TwoPhaseOutcome.PREPARE_OK (determined by line 2608 of BasicAction)
      - we are now ready to call BasicAction.phase2Commit(boolean) at line 1826
      - in phase2Commit the record lists are examined
      - the pendingList is empty
      - doCommit on the preparedList is called (line 2131) and this is fine
      - then, the readonlyList is checked
      - HERE is the problem: if TxControl.readonlyOptimisation is true (and this seems to be the default: in 4.4.0GA this check wasn't even done, due to bug JBTM-426) doCommit is not called on the readonlyList; but in this case, it happens that the following actions are not taken:

      XAResourceRecord.topLevelCommit() => XAResourceRecord.removeConnection() => DirectRecoverableConnection.close() => DirectRecoverableConnection.reset()

      In other words, the _theTransaction field of DirectRecoverableConnection related to the readonly resource is not reset to null after transaction completion. This means that that connection won't be usable anymore by other transactions, because the DirectRecoverableConnection.validTransaction(Transaction) will always return false and JBossTS will always throw the following exception:

      java.sql.SQLException: [com.arjuna.ats.internal.jdbc.alreadyassociatedcheck] Checking transaction and found that this connection is already associated with a different transaction! Obtain a new connection for this transaction.

      So, my question is this: even if I can disable the readonly optimisation, is this a bug? I think an optimisation should not break some basic functionality like this... am I missing something?

      I'm using JBossTS TransactionalDriver managed by a DBCP data source on a Spring JTA TransactionManager infrastructure.

      Thanks in advance for any help.