/**
   * @param parent Parent entry.
   * @param nodeId Requesting node ID.
   * @param otherNodeId Near node ID.
   * @param otherVer Other version.
   * @param threadId Requesting thread ID.
   * @param ver Cache version.
   * @param timeout Maximum wait time.
   * @param loc {@code True} if the lock is local.
   * @param reentry {@code True} if candidate is for reentry.
   * @param tx Transaction flag.
   * @param singleImplicit Single-key-implicit-transaction flag.
   * @param nearLoc Near-local flag.
   * @param dhtLoc DHT local flag.
   */
  public GridCacheMvccCandidate(
      GridCacheEntryEx<K, ?> parent,
      UUID nodeId,
      @Nullable UUID otherNodeId,
      @Nullable GridCacheVersion otherVer,
      long threadId,
      GridCacheVersion ver,
      long timeout,
      boolean loc,
      boolean reentry,
      boolean tx,
      boolean singleImplicit,
      boolean nearLoc,
      boolean dhtLoc) {
    assert nodeId != null;
    assert ver != null;
    assert parent != null;

    this.parent = parent;
    this.nodeId = nodeId;
    this.otherNodeId = otherNodeId;
    this.otherVer = otherVer;
    this.threadId = threadId;
    this.ver = ver;
    this.timeout = timeout;

    mask(LOCAL, loc);
    mask(REENTRY, reentry);
    mask(TX, tx);
    mask(SINGLE_IMPLICIT, singleImplicit);
    mask(NEAR_LOCAL, nearLoc);
    mask(DHT_LOCAL, dhtLoc);

    ts = U.currentTimeMillis();

    id = IDGEN.incrementAndGet();
  }
    /**
     * @param entries Entries to submit.
     * @param curFut Current future.
     * @throws GridInterruptedException If interrupted.
     */
    private void submit(final List<Map.Entry<K, V>> entries, final GridFutureAdapter<Object> curFut)
        throws GridInterruptedException {
      assert entries != null;
      assert !entries.isEmpty();
      assert curFut != null;

      incrementActiveTasks();

      GridFuture<Object> fut;
      if (isLocNode) {
        fut =
            ctx.closure()
                .callLocalSafe(
                    new GridDataLoadUpdateJob<>(ctx, log, cacheName, entries, false, updater),
                    false);

        locFuts.add(fut);

        fut.listenAsync(
            new GridInClosure<GridFuture<Object>>() {
              @Override
              public void apply(GridFuture<Object> t) {
                try {
                  boolean rmv = locFuts.remove(t);

                  assert rmv;

                  curFut.onDone(t.get());
                } catch (GridException e) {
                  curFut.onDone(e);
                }
              }
            });
      } else {
        byte[] entriesBytes;

        try {
          entriesBytes = ctx.config().getMarshaller().marshal(entries);

          if (updaterBytes == null) {
            assert updater != null;

            updaterBytes = ctx.config().getMarshaller().marshal(updater);
          }

          if (topicBytes == null) topicBytes = ctx.config().getMarshaller().marshal(topic);
        } catch (GridException e) {
          U.error(log, "Failed to marshal (request will not be sent).", e);

          return;
        }

        GridDeployment dep = null;
        GridPeerDeployAware jobPda0 = null;

        if (ctx.deploy().enabled()) {
          try {
            jobPda0 = jobPda;

            assert jobPda0 != null;

            dep = ctx.deploy().deploy(jobPda0.deployClass(), jobPda0.classLoader());
          } catch (GridException e) {
            U.error(
                log,
                "Failed to deploy class (request will not be sent): " + jobPda0.deployClass(),
                e);

            return;
          }

          if (dep == null)
            U.warn(log, "Failed to deploy class (request will be sent): " + jobPda0.deployClass());
        }

        long reqId = idGen.incrementAndGet();

        fut = curFut;

        reqs.put(reqId, (GridFutureAdapter<Object>) fut);

        GridDataLoadRequest<Object, Object> req =
            new GridDataLoadRequest<>(
                reqId,
                topicBytes,
                cacheName,
                updaterBytes,
                entriesBytes,
                true,
                dep != null ? dep.deployMode() : null,
                dep != null ? jobPda0.deployClass().getName() : null,
                dep != null ? dep.userVersion() : null,
                dep != null ? dep.participants() : null,
                dep != null ? dep.classLoaderId() : null,
                dep == null);

        try {
          ctx.io().send(node, TOPIC_DATALOAD, req, PUBLIC_POOL);

          if (log.isDebugEnabled())
            log.debug("Sent request to node [nodeId=" + node.id() + ", req=" + req + ']');
        } catch (GridException e) {
          if (ctx.discovery().alive(node) && ctx.discovery().pingNode(node.id()))
            ((GridFutureAdapter<Object>) fut).onDone(e);
          else
            ((GridFutureAdapter<Object>) fut)
                .onDone(
                    new GridTopologyException(
                        "Failed to send " + "request (node has left): " + node.id()));
        }
      }
    }