public void commit(Xid xid, boolean isOnePhase) throws XAException {
   // always call prepare() - even if this is just a 1PC!
   if (isOnePhase) prepare(xid);
   if (trace) log.trace("committing TransactionXaAdapter: " + globalTx);
   try {
     LocalTxInvocationContext ctx = icc.createTxInvocationContext();
     ctx.setXaCache(this);
     if (configuration.isOnePhaseCommit()) {
       checkMarkedForRollback();
       if (trace) log.trace("Doing an 1PC prepare call on the interceptor chain");
       PrepareCommand command = commandsFactory.buildPrepareCommand(globalTx, modifications, true);
       try {
         invoker.invoke(ctx, command);
       } catch (Throwable e) {
         log.error("Error while processing 1PC PrepareCommand", e);
         throw new XAException(XAException.XAER_RMERR);
       }
     } else {
       CommitCommand commitCommand = commandsFactory.buildCommitCommand(globalTx);
       try {
         invoker.invoke(ctx, commitCommand);
       } catch (Throwable e) {
         log.error("Error while processing 1PC PrepareCommand", e);
         throw new XAException(XAException.XAER_RMERR);
       }
     }
   } finally {
     txTable.removeLocalTransaction(transaction);
     this.modifications = null;
   }
 }
 public void rollback(Xid xid) throws XAException {
   RollbackCommand rollbackCommand = commandsFactory.buildRollbackCommand(globalTx);
   LocalTxInvocationContext ctx = icc.createTxInvocationContext();
   ctx.setXaCache(this);
   try {
     invoker.invoke(ctx, rollbackCommand);
   } catch (Throwable e) {
     log.error("Exception while rollback", e);
     throw new XAException(XAException.XA_HEURHAZ);
   } finally {
     txTable.removeLocalTransaction(transaction);
     this.modifications = null;
   }
 }
  @Override
  public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command)
      throws Throwable {
    Object retVal = invokeNextInterceptor(ctx, command);

    boolean sync = isSynchronous(ctx);

    if (shouldInvokeRemoteTxCommand(ctx)) {
      int newCacheViewId = -1;
      stateTransferLock.waitForStateTransferToEnd(ctx, command, newCacheViewId);

      if (command.isOnePhaseCommit())
        flushL1Caches(ctx); // if we are one-phase, don't block on this future.

      Collection<Address> recipients = dm.getAffectedNodes(ctx.getAffectedKeys());
      prepareOnAffectedNodes(ctx, command, recipients, sync);

      ((LocalTxInvocationContext) ctx).remoteLocksAcquired(recipients);
    } else if (isL1CacheEnabled
        && command.isOnePhaseCommit()
        && !ctx.isOriginLocal()
        && !ctx.getLockedKeys().isEmpty()) {
      // We fall into this block if we are a remote node, happen to be the primary data owner and
      // have locked keys.
      // it is still our responsibility to invalidate L1 caches in the cluster.
      flushL1Caches(ctx);
    }
    return retVal;
  }
 @Override
 public Object visitLockControlCommand(TxInvocationContext ctx, LockControlCommand command)
     throws Throwable {
   Object retVal = invokeNextInterceptor(ctx, command);
   if (ctx.isOriginLocal()) {
     // unlock will happen async as it is a best effort
     boolean sync = !command.isUnlock();
     ((LocalTxInvocationContext) ctx).remoteLocksAcquired(rpcManager.getTransport().getMembers());
     rpcManager.invokeRemotely(null, command, rpcManager.getDefaultRpcOptions(sync));
   }
   return retVal;
 }
 @Override
 public Object visitLockControlCommand(TxInvocationContext ctx, LockControlCommand command)
     throws Throwable {
   if (ctx.isOriginLocal()) {
     int newCacheViewId = -1;
     stateTransferLock.waitForStateTransferToEnd(ctx, command, newCacheViewId);
     final Collection<Address> affectedNodes = dm.getAffectedNodes(command.getKeys());
     ((LocalTxInvocationContext) ctx).remoteLocksAcquired(affectedNodes);
     rpcManager.invokeRemotely(affectedNodes, command, true, true);
   }
   return invokeNextInterceptor(ctx, command);
 }
  public int prepare(Xid xid) throws XAException {
    checkMarkedForRollback();
    if (configuration.isOnePhaseCommit()) {
      if (trace)
        log.trace("Received prepare for tx: " + xid + " . Skipping call as 1PC will be used.");
      return XA_OK;
    }

    PrepareCommand prepareCommand =
        commandsFactory.buildPrepareCommand(
            globalTx, modifications, configuration.isOnePhaseCommit());
    if (trace) log.trace("Sending prepare command through the chain: " + prepareCommand);

    LocalTxInvocationContext ctx = icc.createTxInvocationContext();
    ctx.setXaCache(this);
    try {
      invoker.invoke(ctx, prepareCommand);
      return XA_OK;
    } catch (Throwable e) {
      log.error("Error while processing PrepareCommand", e);
      throw new XAException(XAException.XAER_RMERR);
    }
  }
 Map<Integer, Set<K>> contextToMap(LocalTxInvocationContext ctx, ConsistentHash hash) {
   Map<Integer, Set<K>> contextMap = new HashMap<>();
   ctx.getLookedUpEntries()
       .forEach(
           (k, v) -> {
             Integer segment = hash.getSegment(k);
             Set<K> innerSet = contextMap.get(segment);
             if (innerSet == null) {
               innerSet = new HashSet<K>();
               contextMap.put(segment, innerSet);
             }
             innerSet.add((K) k);
           });
   return contextMap;
 }