private EntryVersionsMap totalOrderCreateNewVersionsAndCheckForWriteSkews(
        VersionGenerator versionGenerator,
        TxInvocationContext context,
        VersionedPrepareCommand prepareCommand) {
      if (context.isOriginLocal()) {
        throw new IllegalStateException("This must not be reached");
      }

      EntryVersionsMap updatedVersionMap = new EntryVersionsMap();

      if (!((TotalOrderPrepareCommand) prepareCommand).skipWriteSkewCheck()) {
        updatedVersionMap =
            performTotalOrderWriteSkewCheckAndReturnNewVersions(
                prepareCommand,
                dataContainer,
                persistenceManager,
                versionGenerator,
                context,
                keySpecificLogic,
                timeService);
      }

      for (WriteCommand c : prepareCommand.getModifications()) {
        for (Object k : c.getAffectedKeys()) {
          if (keySpecificLogic.performCheckOnKey(k)) {
            if (!updatedVersionMap.containsKey(k)) {
              updatedVersionMap.put(k, null);
            }
          }
        }
      }

      context.getCacheTransaction().setUpdatedEntryVersions(updatedVersionMap);
      return updatedVersionMap;
    }
  @Override
  public final CompletableFuture<Void> visitPrepareCommand(
      TxInvocationContext ctx, PrepareCommand command) throws Throwable {
    if (ctx.isOriginLocal()) {
      ((VersionedPrepareCommand) command)
          .setVersionsSeen(ctx.getCacheTransaction().getVersionsRead());
      // for local mode keys
      ctx.getCacheTransaction().setUpdatedEntryVersions(EMPTY_VERSION_MAP);
      return ctx.onReturn(
          (rCtx, rCommand, rv, throwable) -> {
            if (throwable == null && shouldCommitDuringPrepare((PrepareCommand) rCommand, ctx)) {
              commitContextEntries(ctx, null, null);
            }
            return null;
          });
    }

    // Remote context, delivered in total order

    wrapEntriesForPrepare(ctx, command);

    return ctx.onReturn(
        (rCtx, rCommand, rv, throwable) -> {
          if (throwable != null) throw throwable;

          TxInvocationContext txInvocationContext = (TxInvocationContext) rCtx;
          VersionedPrepareCommand prepareCommand = (VersionedPrepareCommand) rCommand;
          EntryVersionsMap versionsMap =
              cdl.createNewVersionsAndCheckForWriteSkews(
                  versionGenerator, txInvocationContext, prepareCommand);

          if (prepareCommand.isOnePhaseCommit()) {
            commitContextEntries(txInvocationContext, null, null);
          } else {
            if (trace)
              log.tracef(
                  "Transaction %s will be committed in the 2nd phase",
                  txInvocationContext.getGlobalTransaction().globalId());
          }

          return CompletableFuture.completedFuture(
              versionsMap == null ? rv : new ArrayList<Object>(versionsMap.keySet()));
        });
  }
    private EntryVersionsMap clusteredCreateNewVersionsAndCheckForWriteSkews(
        VersionGenerator versionGenerator,
        TxInvocationContext context,
        VersionedPrepareCommand prepareCommand) {
      // Perform a write skew check on mapped entries.
      EntryVersionsMap uv =
          performWriteSkewCheckAndReturnNewVersions(
              prepareCommand,
              dataContainer,
              persistenceManager,
              versionGenerator,
              context,
              keySpecificLogic,
              timeService);

      CacheTransaction cacheTransaction = context.getCacheTransaction();
      EntryVersionsMap uvOld = cacheTransaction.getUpdatedEntryVersions();
      if (uvOld != null && !uvOld.isEmpty()) {
        uvOld.putAll(uv);
        uv = uvOld;
      }
      cacheTransaction.setUpdatedEntryVersions(uv);
      return (uv.isEmpty()) ? null : uv;
    }