docs: public void rollback(Xid xid) throws XAException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              Tr.entry(this, tc, "rollback", ivManagedConnection, AdapterUtil.toString(xid));
  
          // Reset so we can deferred enlist in a future global transaction. 
          ivManagedConnection.wasLazilyEnlistedInGlobalTran = false; 
  
          // if the MC marked Stale, it means the user requested a purge pool with an immediate option
          // so don't allow any work to continue.  In this case, we throw XAER_RMFAIL xa error
          // which indicates that the resource manager is not available
          if (ivManagedConnection._mcStale) {
              Tr.error(tc, "INVALID_CONNECTION");
              XAException x = new XAException(XAException.XAER_RMFAIL);
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) 
                  Tr.exit(this, tc, "rollback", new Object[] { "MC is stale throwing XAER_RMFAIL", ivManagedConnection });
              throw x;
          }
  
          if (ivXid == null) { 
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) 
                  Tr.debug(this, tc,
                           "XAResource.start was never issued; allowing rollback for recovery."); 
              try {
                  ivStateManager.setState(WSStateManager.XA_RECOVER);
              } catch (TransactionException te) {
                  //Exception means setState failed because it was invalid to set the state in this case
                  FFDCFilter.processException(te, "com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl.rollback", "614", this);
  
                  XAException xae = AdapterUtil.createXAException(
                                                                  "INVALID_TX_STATE",
                                                                  new Object[] { "XAResource.rollback", ivManagedConnection.getTransactionStateAsString() },
                                                                  XAException.XAER_PROTO); 
  
                  traceXAException(xae, currClass);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                      Tr.exit(this, tc, "rollback", xae);
                  throw xae;
              }
              ivXid = xid;
  
          } else if (!xid.equals(ivXid)) { 
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) 
                  Tr.debug(this, tc, "Xid does not match.", new Object[]
                  {
                   "XAResource.start:    ",
                   AdapterUtil.toString(ivXid), 
                   "XAResource.rollback: ",
                   AdapterUtil.toString(xid) 
                           });
  
              XAException xaX = AdapterUtil.createXAException(
                                                              "XID_MISMATCH",
                                                              new Object[] { AdapterUtil.toString(ivXid), "rollback", AdapterUtil.toString(xid) },
                                                              XAException.XAER_NOTA); 
  
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                  Tr.exit(this, tc, "rollback", xaX);
              throw xaX;
          }
  
          // Defer xa.rollback if a stale connection occurred and the data source property
          // oracleRACXARetryDelay is configured.
  
          WSManagedConnectionFactoryImpl mcf = ivManagedConnection.mcf;
          long oracleRACLastStale = mcf.oracleRACLastStale.get();
  
          if (oracleRACLastStale > 0l) {
              // Determine if the current time falls within the delay period from the latest
              // stale connection. If so, we need to defer commit/rollback.
  
              long timeSinceLastStale = System.currentTimeMillis() - oracleRACLastStale;
  
              if (timeSinceLastStale > mcf.oracleRACXARetryDelay // Current time exceeds the delay period 
                  && mcf.oracleRACLastStale.compareAndSet(oracleRACLastStale, 0l)) // Reset indicator as non-stale
              {
                  if (tc.isDebugEnabled())
                      Tr.debug(this, tc,
                               "Time since last stale, " + timeSinceLastStale +
                                               " ms, exceeds the oracleRACXARetryDelay. Allowing rollback.");
              } else {
                  // Current time falls with the delay period.
                  // Defer the xa.rollback operation by raising an XAException with
                  // error code of XA_RETRY. The transaction manager will retry the operation
                  // after a configurable delay.
  
                  if (tc.isDebugEnabled())
                      Tr.debug(this, tc,
                               "Time since last stale, " + timeSinceLastStale +
                                               " ms, falls within the oracleRACXARetryDelay. Deferring rollback.");
  
                  XAException x = AdapterUtil.createXAException(
                                                                "ORACLE_RAC_RETRY",
                                                                new Object[] { "XAResource.rollback", timeSinceLastStale, mcf.oracleRACXARetryDelay },
                                                                XAException.XA_RETRY);
  
                  if (tc.isEntryEnabled())
                      Tr.exit(this, tc, "rollback", x);
                  throw x;
              }
          }
  
          // The state should be changed back whether or not the rollback throws an exception,
          // unless it's a hueristic exception.
          boolean doChangeState = true;
  
          // Saved exception to throw later.
          XAException throwX = null;
  
          try {
              ivXaRes.rollback(xid);
          } catch (XAException xae) {
              FFDCFilter.processException(xae, "com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl.rollback", "524", this);
              traceXAException(xae, currClass);
              checkXAException(xae); 
              if (xae.errorCode == XAException.XA_HEURCOM ||
                  xae.errorCode == XAException.XA_HEURHAZ ||
                  xae.errorCode == XAException.XA_HEURMIX ||
                  xae.errorCode == XAException.XA_HEURRB) {
                  doChangeState = false;
  
                  try {
                      // we won't call forget() here, instead, we will forget the tran only when the TM manager calls it on us.
                      // this way if the server crashes after the adapter receives heuristic and before the TM logging it. TM could still
                      // as the database for the in doubt trans since its not forgotten yet
  
                      ivStateManager.setState(WSStateManager.HEURISTIC_END);
                  } catch (TransactionException te) {
                      FFDCFilter.processException(te, "com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl.rollback", "540", this);
                      Tr.warning(tc, "DSA_INTERNAL_WARNING", new Object[] { "Exception setting the transaction state to WSStateManager.HEURISTIC_END from ",
                                                                           ivManagedConnection.getTransactionStateAsString(), te });
                      //should never happen so just eat it
                  }
              } 
                // Throw the exception later.
              throwX = xae;
          }
  
          if (doChangeState && !ivManagedConnection.isAborted())
              try {
                  ivStateManager.setState(WSStateManager.XA_ROLLBACK);
              } catch (TransactionException te) {
                  //Exception means setState failed because it was invalid to set the state in this case
                  FFDCFilter.processException(te, "com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl.rollback", "510", this);
                  Tr.error(tc, "INVALID_TX_STATE", new Object[] { "XAResource.rollback()", ivManagedConnection.getTransactionStateAsString() });
  
                  XAException xae = AdapterUtil.createXAException(
                                                                  "INVALID_TX_STATE",
                                                                  new Object[] { "XAResource.rollback", ivManagedConnection.getTransactionStateAsString() },
                                                                  XAException.XAER_PROTO); 
  
                  traceXAException(xae, currClass);
  
                  if (throwX == null)
                      throwX = xae;
              }
          ivXid = null;
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) 
          {
              String cId = null;
              try {
                  cId = ivManagedConnection.mcf.getCorrelator(ivManagedConnection); 
              } catch (SQLException x) {
                  // will just log the exception here and ignore it since its in trace
                  Tr.debug(this, tc, "got an exception trying to get the correlator in rollback, exception is: ", x);
              }
              if (cId != null) {
                  StringBuffer stbuf = new StringBuffer(200);
                  stbuf.append("Correlator: DB2, ID: ");
                  stbuf.append(cId);
                  if (xid != null) {
                      stbuf.append("Transaction ID : ");
                      stbuf.append(xid);
                  }
                  stbuf.append(" ROLLBACK");
  
                  Tr.debug(this, tc, stbuf.toString());
              }
          }
          if (throwX != null) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
                  Tr.exit(this, tc, "rollback", throwX);
              throw throwX;
          }
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              Tr.exit(this, tc, "rollback");
      }