private void registerRemoteTransaction(GlobalTransaction gtx, RemoteTransaction rtx) {
    RemoteTransaction transaction = remoteTransactions.put(gtx, rtx);
    if (transaction != null) {
      log.remoteTxAlreadyRegistered();
      throw new IllegalStateException(
          "A remote transaction with the given id was already registered!!!");
    }

    log.tracef("Created and registered remote transaction %s", rtx);
    if (rtx.getTopologyId() < minTxTopologyId) {
      log.tracef(
          "Changing minimum topology ID from %d to %d", minTxTopologyId, rtx.getTopologyId());
      minTxTopologyId = rtx.getTopologyId();
    }
  }
  public void cleanupStaleTransactions(CacheTopology cacheTopology) {
    int topologyId = cacheTopology.getTopologyId();
    List<Address> members = cacheTopology.getMembers();

    // We only care about transactions originated before this topology update
    if (getMinTopologyId() >= topologyId) return;

    log.tracef(
        "Checking for transactions originated on leavers. Current members are %s, remote transactions: %d",
        members, remoteTransactions.size());
    Set<GlobalTransaction> toKill = new HashSet<GlobalTransaction>();
    for (Map.Entry<GlobalTransaction, RemoteTransaction> e : remoteTransactions.entrySet()) {
      GlobalTransaction gt = e.getKey();
      RemoteTransaction remoteTx = e.getValue();
      log.tracef("Checking transaction %s", gt);
      // The topology id check is needed for joiners
      if (remoteTx.getTopologyId() < topologyId && !members.contains(gt.getAddress())) {
        toKill.add(gt);
      }
    }

    if (toKill.isEmpty()) {
      log.tracef("No global transactions pertain to originator(s) who have left the cluster.");
    } else {
      log.tracef("%s global transactions pertain to leavers and need to be killed", toKill.size());
    }

    for (GlobalTransaction gtx : toKill) {
      log.tracef("Killing remote transaction originating on leaver %s", gtx);
      RollbackCommand rc = new RollbackCommand(cacheName, gtx);
      rc.init(invoker, icc, TransactionTable.this);
      try {
        rc.perform(null);
        log.tracef("Rollback of transaction %s complete.", gtx);
      } catch (Throwable e) {
        log.unableToRollbackGlobalTx(gtx, e);
      }
    }

    log.tracef(
        "Completed cleaning transactions originating on leavers. Remote transactions remaining: %d",
        remoteTransactions.size());
  }
 private RemoteTransaction getOrCreateRemoteTransaction(
     GlobalTransaction globalTx, WriteCommand[] modifications, int topologyId) {
   RemoteTransaction remoteTransaction = remoteTransactions.get(globalTx);
   if (remoteTransaction != null) return remoteTransaction;
   remoteTransaction =
       modifications == null
           ? txFactory.newRemoteTransaction(globalTx, topologyId)
           : txFactory.newRemoteTransaction(modifications, globalTx, topologyId);
   RemoteTransaction existing = remoteTransactions.putIfAbsent(globalTx, remoteTransaction);
   if (existing != null) {
     log.tracef("Remote transaction already registered: %s", existing);
     return existing;
   } else {
     log.tracef("Created and registered remote transaction %s", remoteTransaction);
     if (remoteTransaction.getTopologyId() < minTxTopologyId) {
       log.tracef(
           "Changing minimum topology ID from %d to %d",
           minTxTopologyId, remoteTransaction.getTopologyId());
       minTxTopologyId = remoteTransaction.getTopologyId();
     }
     return remoteTransaction;
   }
 }
 public Set<Object> getLockedKeysForRemoteTransaction(GlobalTransaction gtx) {
   RemoteTransaction transaction = remoteTransactions.get(gtx);
   if (transaction == null) return InfinispanCollections.emptySet();
   return transaction.getLockedKeys();
 }