/**
     * @return Query info.
     * @throws GridException In case of error.
     */
    @SuppressWarnings({"unchecked"})
    private GridCacheQueryInfo localQueryInfo() throws GridException {
      GridCacheQueryBean qry = query();

      GridPredicate<GridCacheEntry<Object, Object>> prjPred =
          qry.query().projectionFilter() == null
              ? F.<GridCacheEntry<Object, Object>>alwaysTrue()
              : qry.query().projectionFilter();

      GridMarshaller marsh = cctx.marshaller();

      GridReducer<Object, Object> rdc =
          qry.reducer() != null
              ? marsh.<GridReducer<Object, Object>>unmarshal(marsh.marshal(qry.reducer()), null)
              : null;

      GridClosure<Object, Object> trans =
          qry.transform() != null
              ? marsh.<GridClosure<Object, Object>>unmarshal(marsh.marshal(qry.transform()), null)
              : null;

      return new GridCacheQueryInfo(
          true,
          prjPred,
          trans,
          rdc,
          qry.query(),
          GridCacheLocalQueryFuture.this,
          ctx.localNodeId(),
          cctx.io().nextIoId(),
          qry.query().includeMetadata(),
          true,
          qry.arguments());
    }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public CacheQueryFuture<?> queryDistributed(
      GridCacheQueryBean qry, Collection<ClusterNode> nodes) {
    assert cctx.config().getCacheMode() != LOCAL;

    if (log.isDebugEnabled()) log.debug("Executing distributed query: " + qry);

    long reqId = cctx.io().nextIoId();

    final GridCacheDistributedQueryFuture<K, V, ?> fut =
        new GridCacheDistributedQueryFuture<>(cctx, reqId, qry, nodes);

    try {
      qry.query().validate();

      String clsName = qry.query().queryClassName();

      GridCacheQueryRequest req =
          new GridCacheQueryRequest(
              cctx.cacheId(),
              reqId,
              cctx.name(),
              qry.query().type(),
              false,
              qry.query().clause(),
              clsName,
              qry.query().scanFilter(),
              qry.query().partition(),
              qry.reducer(),
              qry.transform(),
              qry.query().pageSize(),
              qry.query().includeBackups(),
              qry.arguments(),
              false,
              qry.query().keepPortable(),
              qry.query().subjectId(),
              qry.query().taskHash());

      addQueryFuture(req.id(), fut);

      final Object topic = topic(cctx.nodeId(), req.id());

      cctx.io().addOrderedHandler(topic, resHnd);

      fut.listen(
          new CI1<IgniteInternalFuture<?>>() {
            @Override
            public void apply(IgniteInternalFuture<?> fut) {
              cctx.io().removeOrderedHandler(topic);
            }
          });

      sendRequest(fut, req, nodes);
    } catch (IgniteCheckedException e) {
      fut.onDone(e);
    }

    return fut;
  }