0 Replies Latest reply on Aug 7, 2002 10:02 AM by Hari Rajapakshe

    Handling XAResource prepare failures in the Oracle XA driver

    Hari Rajapakshe Newbie

      Hi,

      My question relates to the JBoss tx management module class, org.jboss.tm.TxCapsule, and I have a question regarding the DTP behaviour in a failing XA resource.

      I see that, the return value (vote) of prepareing an XAResource is checked against only, XA_OK, meaning that otherwise XA_READONLY state is assumed. Also the only XAException handled here are heuristic failures, but not exceptions resulted from any communication failures with the resource manager. (for example, if the network goes down or the database goes down for a SHORTER PERIOD -i.e. it would be back soon enough to perform an XA recovery operation.) Or would you catch such comm failures in the following "Throwable" clause, and mark the tx for rolling back..? (see APPENDIX A)

      The reason Im wondering about this is, that a test I have been doing with Oracle 8.1.7 and 9.0 (NOT WITH JBOSS, BUT A SIMPLE JDBC CLIENT DIRECTLY CALLING THE ORACLE XA DRIVER) to explicitly look at XA failure recovery methods, suggested me that even if I were to temporarily disconnect the database LAN connection, the call to XAREsource.prepare() SUCCEEDS, returning 0..!! (XA_OK..?) Here I exepcted an XAException, suggesting that there is a connection failure. Oracle driver, however, dumps the stack trace indicating a network failure, but still the call to prepare() succeeds, as shown in the exception trace below. (APPENDIX B)

      So Im wondering whether Im missing something here, also looking at the JBoss code in TxCapsule, on the bahaviour of XAResource.prepare() when there SHOULD be a connection failure, and how I should handle this in terms of calling XAResource.recover() etc..?

      thanks in advance
      -hari


      APPENDIX A: source code of TxCapsule on XAResource.prepare()
      ============================================================

      private boolean prepareResources()
      {
      boolean readOnly = true;

      status = Status.STATUS_PREPARING;

      for (int i = 0; i < resourceCount; i++)
      {
      // Abort prepare on state change.
      if (status != Status.STATUS_PREPARING)
      return false;

      if (resourceSameRM != -1)
      continue; // This RM already prepared.

      XAResource resource = resources
      ;

      try
      {
      int vote;

      unlock();
      try
      {
      vote = resources.prepare(resourceXids);
      } finally
      {
      lock();
      }

      if (vote == XAResource.XA_OK)
      {
      readOnly = false;
      resourceState = RS_VOTE_OK;
      } else if (vote == XAResource.XA_RDONLY)
      resourceState
      = RS_VOTE_READONLY;
      else
      {
      // Illegal vote: rollback.
      if (trace)
      {
      log.trace("illegal vote in prepare resources", new Exception());
      } // end of if ()
      status = Status.STATUS_MARKED_ROLLBACK;
      return false;
      }
      } catch (XAException e)
      {
      readOnly = false;

      switch (e.errorCode)
      {
      case XAException.XA_HEURCOM:
      // Heuristic commit is not that bad when preparing.
      // But it means trouble if we have to rollback.
      gotHeuristic(i, e.errorCode);
      break;
      case XAException.XA_HEURRB:
      case XAException.XA_HEURMIX:
      case XAException.XA_HEURHAZ:
      gotHeuristic(i, e.errorCode);
      if (status == Status.STATUS_PREPARING)
      status = Status.STATUS_MARKED_ROLLBACK;
      break;
      default:
      log.warn("XAException: tx=" + toString() + " errorCode=" +
      getStringXAErrorCode(e.errorCode), e);
      if (status == Status.STATUS_PREPARING)
      status = Status.STATUS_MARKED_ROLLBACK;
      break;
      }
      } catch (Throwable t)
      {
      if (trace)
      {
      log.trace("unhandled throwable in prepareResources", t);
      }
      if (status == Status.STATUS_PREPARING)
      status = Status.STATUS_MARKED_ROLLBACK;
      }
      }

      if (status == Status.STATUS_PREPARING)
      status = Status.STATUS_PREPARED;

      return readOnly;
      }



      APPENDIX B: Oracle exception trace on connection failure within prepare() call, WHICH SUCCEED.
      ==============================================================================================

      setting Java1.3 env...
      --- Do Work #1
      --- Do Work #2
      --- END xid1
      --- prepare XA#1..
      --- waiting before preparing XA#2..
      --- prepare XA#2..
      java.sql.SQLException: Io exception: Connection reset by peer: JVM_recv in socke
      t input stream read
      at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:180)
      at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:222)
      at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:335)
      at oracle.jdbc.driver.OracleStatement.(OracleStatement.java:503)
      at oracle.jdbc.driver.OracleStatement.(OracleStatement.java:518)
      at oracle.jdbc.driver.OraclePreparedStatement.(OraclePreparedState
      ment.java:210)
      at oracle.jdbc.driver.OracleCallableStatement.(OracleCallableState
      ment.java:111)
      at oracle.jdbc.driver.OracleCallableStatement.(OracleCallableState
      ment.java:95)
      at oracle.jdbc.driver.OracleConnection.privatePrepareCall(OracleConnecti
      on.java:1055)
      at oracle.jdbc.driver.OracleConnection.prepareCall(OracleConnection.java
      :893)
      at oracle.jdbc.xa.client.OracleXAResource.prepare(OracleXAResource.java:
      465)
      at jdbctest.client.OracleXATest.main(OracleXATest.java:159)
      --- prepare XA#2 done. ret =0
      Return value of prepare 1 is 0
      Return value of prepare 2 is 0
      wait before committing...
      Proceeding...
      do_commit is true