static List<Xid> recoverXids(XAResource xaResource, XidSelector selector) throws XAException {
    List<Xid> ret = new ArrayList<Xid>();

    boolean done = false;
    int flags = XAResource.TMSTARTRSCAN;
    Xid[] xidsFromLastScan = null;
    List<Xid> allRecoveredXidsSoFar = new ArrayList<Xid>();
    do {
      xidsFromLastScan = xaResource.recover(flags);
      flags = XAResource.TMNOFLAGS;
      done = (xidsFromLastScan == null || xidsFromLastScan.length == 0);
      if (!done) {

        // TEMPTATIVELY SET done TO TRUE
        // TO TOLERATE ORACLE 8.1.7 INFINITE
        // LOOP (ALWAYS RETURNS SAME RECOVER
        // SET). IF A NEW SET OF XIDS IS RETURNED
        // THEN done WILL BE RESET TO FALSE

        done = true;
        for (int i = 0; i < xidsFromLastScan.length; i++) {
          Xid xid = new XID(xidsFromLastScan[i]);
          // our own XID implements equals and hashCode properly
          if (!allRecoveredXidsSoFar.contains(xid)) {
            // a new xid is returned -> we can not be in a recovery loop -> go on
            allRecoveredXidsSoFar.add(xid);
            done = false;
            if (selector.selects(xid)) {
              ret.add(xid);
            }
          }
        }
      }
    } while (!done);

    return ret;
  }
 @Override
 public Xid[] recover(int i) throws XAException {
   return xaResource.recover(i);
 }
 public void testRecoveryHandler() throws Exception {
   final XAResource xaResource = cache(0).getAdvancedCache().getXAResource();
   final Xid[] recover = xaResource.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);
   assert recover != null && recover.length == 0;
 }
Example #4
0
  /**
   * Tests that XA RECOVER works as expected.
   *
   * @throws Exception if test fails
   */
  public void testRecover() throws Exception {
    if (!versionMeetsMinimum(5, 0)) {
      return;
    }

    if (versionMeetsMinimum(5, 7) && !versionMeetsMinimum(5, 7, 5)) {
      // Test is broken in 5.7.0 - 5.7.4 after server bug#14670465 fix which changed the XA RECOVER
      // output format.
      // Fixed in 5.7.5 server version
      return;
    }

    // BUG#14670465 fix broke this functionality in 5.7.1 - 5.7.2
    if (versionMeetsMinimum(5, 7, 1) && !versionMeetsMinimum(5, 7, 3)) {
      return;
    }

    XAConnection xaConn = null, recoverConn = null;

    try {
      xaConn = getXAConnection();

      Connection c = xaConn.getConnection();
      Xid xid = createXid();

      XAResource xaRes = xaConn.getXAResource();
      xaRes.start(xid, XAResource.TMNOFLAGS);
      c.createStatement().executeQuery("SELECT 1");
      xaRes.end(xid, XAResource.TMSUCCESS);
      xaRes.prepare(xid);

      // Now try and recover
      recoverConn = getXAConnection();

      XAResource recoverRes = recoverConn.getXAResource();

      Xid[] recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);

      assertTrue(recoveredXids != null);
      assertTrue(recoveredXids.length > 0);

      boolean xidFound = false;

      for (int i = 0; i < recoveredXids.length; i++) {
        if (recoveredXids[i] != null && recoveredXids[i].equals(xid)) {
          xidFound = true;

          break;
        }
      }

      assertTrue(xidFound);

      recoverRes = recoverConn.getXAResource();

      recoveredXids = recoverRes.recover(XAResource.TMSTARTRSCAN);

      assertTrue(recoveredXids != null);
      assertTrue(recoveredXids.length > 0);

      xidFound = false;

      for (int i = 0; i < recoveredXids.length; i++) {
        if (recoveredXids[i] != null && recoveredXids[i].equals(xid)) {
          xidFound = true;

          break;
        }
      }

      assertTrue(xidFound);

      // Test flags
      recoverRes.recover(XAResource.TMSTARTRSCAN);
      recoverRes.recover(XAResource.TMENDRSCAN);
      recoverRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN);

      // This should fail
      try {
        recoverRes.recover(XAResource.TMSUCCESS);
        fail("XAException should have been thrown");
      } catch (XAException xaEx) {
        assertEquals(XAException.XAER_INVAL, xaEx.errorCode);
      }
    } finally {
      if (xaConn != null) {
        xaConn.close();
      }

      if (recoverConn != null) {
        recoverConn.close();
      }
    }
  }
 /** recover the transaction */
 public Xid[] recover(int flag) throws XAException {
   if (_isXATransaction) return _xaResource.recover(flag);
   else return null;
 }
 @Override
 public Xid[] recover(int flags) throws XAException {
   return resource.recover(flags);
 }
Example #7
0
  /** Recover all datasources */
  public void recover(Iterator<List<TxLog.Record>> knownDanglingRecordList) {
    // contains NonCompletedTransaction that needs to be committed
    List<NonCompletedTransaction> commitList = new ArrayList<NonCompletedTransaction>();

    // contains Xids that should be rolledback
    final List<Xid> rollbackList = new LinkedList<Xid>();

    // key = Resource(branchId) value = XAResource
    final Map<Resource, XaDataSource> resourceMap = new HashMap<Resource, XaDataSource>();
    buildRecoveryInfo(commitList, rollbackList, resourceMap, knownDanglingRecordList);
    // invoke recover on all xa resources found
    final List<Xid> recoveredXidsList = new LinkedList<Xid>();

    try {

      for (XaDataSource xaDataSource : dataSources.values()) {
        XAResource xaRes = xaDataSource.getXaConnection().getXaResource();
        Xid xids[] = xaRes.recover(XAResource.TMNOFLAGS);

        for (Xid xid : xids) {
          if (XidImpl.isThisTm(xid.getGlobalTransactionId())) {
            // linear search
            if (rollbackList.contains(xid)) {
              msgLog.logMessage("TM: Found pre commit " + xid + " rolling back ... ", true);
              rollbackList.remove(xid);
              xaRes.rollback(xid);
            } else {
              Resource resource = new Resource(xid.getBranchQualifier());
              if (!resourceMap.containsKey(resource)) {
                resourceMap.put(resource, xaDataSource);
              }
              recoveredXidsList.add(xid);
            }
          } else {
            msgLog.warn("Unknown xid: " + xid);
          }
        }
      }

      // sort the commit list after sequence number
      Collections.sort(commitList);

      // go through and commit
      for (NonCompletedTransaction nct : commitList) {
        int seq = nct.getSequenceNumber();
        Xid xids[] = nct.getXids();
        msgLog.debug("Marked as commit tx-seq[" + seq + "] branch length: " + xids.length);
        for (Xid xid : xids) {
          if (!recoveredXidsList.contains(xid)) {
            msgLog.debug(
                "Tx-seq["
                    + seq
                    + "]["
                    + xid
                    + "] not found in recovered xid list, "
                    + "assuming already committed");
            continue;
          }
          recoveredXidsList.remove(xid);
          Resource resource = new Resource(xid.getBranchQualifier());
          if (!resourceMap.containsKey(resource)) {
            final TransactionFailureException ex =
                new TransactionFailureException("Couldn't find XAResource for " + xid);
            throw logAndReturn("TM: recovery error", ex);
          }
          msgLog.debug("TM: Committing tx " + xid);
          resourceMap.get(resource).getXaConnection().getXaResource().commit(xid, false);
        }
      }

      // rollback the rest
      for (Xid xid : recoveredXidsList) {
        Resource resource = new Resource(xid.getBranchQualifier());
        if (!resourceMap.containsKey(resource)) {
          final TransactionFailureException ex =
              new TransactionFailureException("Couldn't find XAResource for " + xid);
          throw logAndReturn("TM: recovery error", ex);
        }
        msgLog.debug("TM: no match found for " + xid + " removing");
        resourceMap.get(resource).getXaConnection().getXaResource().rollback(xid);
      }
      if (rollbackList.size() > 0) {
        msgLog.debug(
            "TxLog contained unresolved "
                + "xids that needed rollback. They couldn't be matched to "
                + "any of the XAResources recover list. "
                + "Assuming "
                + rollbackList.size()
                + " transactions already rolled back.");
      }

      // Rotate the logs of the participated data sources, making sure that
      // done-records are written so that even if the tm log gets truncated,
      // which it will be after this recovery, that transaction information
      // doesn't get lost.
      for (XaDataSource participant : MapUtil.reverse(resourceMap).keySet()) {
        participant.rotateLogicalLog();
      }
    } catch (IOException | XAException e) {
      throw logAndReturn(
          "TM: recovery failed", new TransactionFailureException("Recovery failed.", e));
    }
  }