/** {@inheritDoc} */
  @Override
  public GridFuture<Map<K, V>> getAllAsync(
      @Nullable Collection<? extends K> keys,
      @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    ctx.denyOnFlag(LOCAL);

    if (F.isEmpty(keys))
      return new GridFinishedFuture<Map<K, V>>(ctx.kernalContext(), Collections.<K, V>emptyMap());

    GridCacheTxLocalAdapter<K, V> tx = ctx.tm().threadLocalTx();

    if (tx != null && !tx.implicit()) return ctx.wrapCloneMap(tx.getAllAsync(keys, filter));

    return loadAsync(keys, false, filter);
  }
  /**
   * @param ldr Loader.
   * @param nodeId Sender node ID.
   * @param req Request.
   * @return Remote transaction.
   * @throws GridException If failed.
   */
  @Nullable
  public GridNearTxRemote<K, V> startRemoteTx(
      ClassLoader ldr, UUID nodeId, GridDhtTxPrepareRequest<K, V> req) throws GridException {
    if (!F.isEmpty(req.nearWrites())) {
      GridNearTxRemote<K, V> tx =
          new GridNearTxRemote<K, V>(
              ldr,
              nodeId,
              req.nearNodeId(),
              req.threadId(),
              req.version(),
              req.commitVersion(),
              req.concurrency(),
              req.isolation(),
              req.isInvalidate(),
              req.timeout(),
              req.nearWrites(),
              ctx);

      if (!tx.empty()) {
        tx = ctx.tm().onCreated(tx);

        if (tx == null || !ctx.tm().onStarted(tx))
          throw new GridCacheTxRollbackException("Attempt to start a completed transaction: " + tx);

        // Prepare prior to reordering, so the pending locks added
        // in prepare phase will get properly ordered as well.
        tx.prepare();

        // Add remote candidates and reorder completed and uncompleted versions.
        tx.addRemoteCandidates(
            req.candidatesByKey(), req.committedVersions(), req.rolledbackVersions());

        if (req.concurrency() == EVENTUALLY_CONSISTENT) {
          if (log.isDebugEnabled())
            log.debug("Committing transaction during remote prepare: " + tx);

          tx.commit();

          if (log.isDebugEnabled()) log.debug("Committed transaction during remote prepare: " + tx);
        }
      }

      return tx;
    }

    return null;
  }
  /**
   * @param keys Keys to load.
   * @param reload Reload flag.
   * @param filter Filter.
   * @return Loaded values.
   */
  public GridFuture<Map<K, V>> loadAsync(
      @Nullable Collection<? extends K> keys,
      boolean reload,
      @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    if (F.isEmpty(keys))
      return new GridFinishedFuture<Map<K, V>>(ctx.kernalContext(), Collections.<K, V>emptyMap());

    GridNearGetFuture<K, V> fut = new GridNearGetFuture<K, V>(ctx, keys, reload, null, filter);

    // Register future for responses.
    ctx.mvcc().addFuture(fut);

    fut.init();

    return ctx.wrapCloneMap(fut);
  }