/** {@inheritDoc} */
  @Override
  public Map<K, V> peekAll(
      @Nullable Collection<? extends K> keys,
      @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    if (keys == null || keys.isEmpty()) return emptyMap();

    final Collection<K> skipped = new GridLeanSet<K>();

    final Map<K, V> map = peekAll0(keys, filter, skipped);

    if (map.size() + skipped.size() != keys.size()) {
      map.putAll(
          dht.peekAll(
              F.view(
                  keys,
                  new P1<K>() {
                    @Override
                    public boolean apply(K k) {
                      return !map.containsKey(k) && !skipped.contains(k);
                    }
                  }),
              filter));
    }

    return map;
  }
  /** {@inheritDoc} */
  @Nullable
  @Override
  public Map<? extends GridComputeJob, GridNode> map(
      List<GridNode> subgrid, @Nullable GridBiTuple<Set<UUID>, A> arg) throws GridException {
    assert arg != null;
    assert arg.get1() != null;

    start = U.currentTimeMillis();

    boolean debug = debugState(g);

    if (debug) logStart(g.log(), getClass(), start);

    Set<UUID> nodeIds = arg.get1();

    Map<GridComputeJob, GridNode> map = U.newHashMap(nodeIds.size());

    try {
      taskArg = arg.get2();

      for (GridNode node : subgrid) if (nodeIds.contains(node.id())) map.put(job(taskArg), node);

      return map;
    } finally {
      if (debug) logMapped(g.log(), getClass(), map.values());
    }
  }
    /** {@inheritDoc} */
    @Nullable
    @Override
    public Map<String, Collection<?>> run(GridStreamerContext ctx, Collection<Quote> quotes)
        throws GridException {
      GridStreamerWindow win = ctx.window("stage1");

      // Add numbers to window.
      win.enqueueAll(quotes);

      Collection<Quote> polled = win.pollEvictedBatch();

      if (!polled.isEmpty()) {
        Map<String, Bar> map = new HashMap<>();

        for (Quote quote : polled) {
          String symbol = quote.symbol();

          Bar bar = map.get(symbol);

          if (bar == null) map.put(symbol, bar = new Bar(symbol));

          bar.update(quote.price());
        }

        return Collections.<String, Collection<?>>singletonMap(ctx.nextStageName(), map.values());
      }

      return null;
    }
  /** {@inheritDoc} */
  @Override
  public Map<K, V> peekAll(
      @Nullable Collection<? extends K> keys, @Nullable Collection<GridCachePeekMode> modes)
      throws GridException {
    if (keys == null || keys.isEmpty()) return emptyMap();

    final Collection<K> skipped = new GridLeanSet<K>();

    final Map<K, V> map =
        !modes.contains(PARTITIONED_ONLY)
            ? peekAll0(keys, modes, ctx.tm().localTxx(), skipped)
            : new GridLeanMap<K, V>(0);

    if (map.size() != keys.size() && !modes.contains(NEAR_ONLY)) {
      map.putAll(
          dht.peekAll(
              F.view(
                  keys,
                  new P1<K>() {
                    @Override
                    public boolean apply(K k) {
                      return !map.containsKey(k) && !skipped.contains(k);
                    }
                  }),
              modes));
    }

    return map;
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public <K, V> V waitForAttribute(K key, long timeout) throws InterruptedException {
    A.notNull(key, "key");

    if (timeout == 0) timeout = Long.MAX_VALUE;

    long now = System.currentTimeMillis();

    // Prevent overflow.
    long end = now + timeout < 0 ? Long.MAX_VALUE : now + timeout;

    // Don't wait longer than session timeout.
    if (end > endTime) end = endTime;

    synchronized (mux) {
      while (!closed && !attrs.containsKey(key) && now < end) {
        mux.wait(end - now);

        now = System.currentTimeMillis();
      }

      if (closed) throw new InterruptedException("Session was closed: " + this);

      return (V) attrs.get(key);
    }
  }
    /** {@inheritDoc} */
    @Nullable
    @Override
    public Map<String, Collection<?>> run(GridStreamerContext ctx, Collection<Bar> bars)
        throws GridException {
      ConcurrentMap<String, Bar> loc = ctx.localSpace();

      GridStreamerWindow win = ctx.window("stage2");

      // Add numbers to window.
      win.enqueueAll(bars);

      Collection<Bar> polled = win.pollEvictedBatch();

      if (!polled.isEmpty()) {
        Map<String, Bar> map = new HashMap<>();

        for (Bar polledBar : polled) {
          String symbol = polledBar.symbol();

          Bar bar = map.get(symbol);

          if (bar == null) map.put(symbol, bar = new Bar(symbol));

          bar.update(polledBar);
        }

        loc.putAll(map);
      }

      return null;
    }
  /** {@inheritDoc} */
  @Override
  public void addAttributeListener(GridTaskSessionAttributeListener lsnr, boolean rewind) {
    A.notNull(lsnr, "lsnr");

    Map<Object, Object> attrs = null;

    List<GridTaskSessionAttributeListener> lsnrs;

    synchronized (mux) {
      lsnrs = new ArrayList<GridTaskSessionAttributeListener>(this.lsnrs.size());

      lsnrs.addAll(this.lsnrs);

      lsnrs.add(lsnr);

      lsnrs = Collections.unmodifiableList(lsnrs);

      this.lsnrs = lsnrs;

      if (rewind) attrs = new HashMap<Object, Object>(this.attrs);
    }

    if (rewind) {
      for (Map.Entry<Object, Object> entry : attrs.entrySet()) {
        for (GridTaskSessionAttributeListener l : lsnrs) {
          l.onAttributeSet(entry.getKey(), entry.getValue());
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean waitForAttributes(Map<?, ?> attrs, long timeout) throws InterruptedException {
    A.notNull(attrs, "attrs");

    if (attrs.isEmpty()) {
      return true;
    }

    if (timeout == 0) timeout = Long.MAX_VALUE;

    long now = System.currentTimeMillis();

    // Prevent overflow.
    long end = now + timeout < 0 ? Long.MAX_VALUE : now + timeout;

    // Don't wait longer than session timeout.
    if (end > endTime) end = endTime;

    synchronized (mux) {
      boolean isFound = false;

      while (!closed
          && !(isFound = this.attrs.entrySet().containsAll(attrs.entrySet()))
          && now < end) {
        mux.wait(end - now);

        now = System.currentTimeMillis();
      }

      if (closed) throw new InterruptedException("Session was closed: " + this);

      return isFound;
    }
  }
  /** {@inheritDoc} */
  @Override
  public Map<?, ?> waitForAttributes(Collection<?> keys, long timeout) throws InterruptedException {
    A.notNull(keys, "keys");

    if (keys.isEmpty()) return Collections.emptyMap();

    if (timeout == 0) timeout = Long.MAX_VALUE;

    long now = System.currentTimeMillis();

    // Prevent overflow.
    long end = now + timeout < 0 ? Long.MAX_VALUE : now + timeout;

    // Don't wait longer than session timeout.
    if (end > endTime) end = endTime;

    synchronized (mux) {
      while (!closed && !attrs.keySet().containsAll(keys) && now < end) {
        mux.wait(end - now);

        now = System.currentTimeMillis();
      }

      if (closed) throw new InterruptedException("Session was closed: " + this);

      Map<Object, Object> retVal = new HashMap<Object, Object>(keys.size());

      for (Object key : keys) retVal.put(key, attrs.get(key));

      return retVal;
    }
  }
  /** @throws Exception If failed. */
  public void testAffinityPut() throws Exception {
    Thread.sleep(2 * TOP_REFRESH_FREQ);

    assertEquals(NODES_CNT, client.compute().refreshTopology(false, false).size());

    Map<UUID, Grid> gridsByLocNode = new HashMap<>(NODES_CNT);

    GridClientData partitioned = client.data(PARTITIONED_CACHE_NAME);

    GridClientCompute compute = client.compute();

    for (int i = 0; i < NODES_CNT; i++) gridsByLocNode.put(grid(i).localNode().id(), grid(i));

    for (int i = 0; i < 100; i++) {
      String key = "key" + i;

      UUID primaryNodeId = grid(0).mapKeyToNode(PARTITIONED_CACHE_NAME, key).id();

      assertEquals("Affinity mismatch for key: " + key, primaryNodeId, partitioned.affinity(key));

      assertEquals(primaryNodeId, partitioned.affinity(key));

      // Must go to primary node only. Since backup count is 0, value must present on
      // primary node only.
      partitioned.put(key, "val" + key);

      for (Map.Entry<UUID, Grid> entry : gridsByLocNode.entrySet()) {
        Object val = entry.getValue().cache(PARTITIONED_CACHE_NAME).peek(key);

        if (primaryNodeId.equals(entry.getKey())) assertEquals("val" + key, val);
        else assertNull(val);
      }
    }

    // Now check that we will see value in near cache in pinned mode.
    for (int i = 100; i < 200; i++) {
      String pinnedKey = "key" + i;

      UUID primaryNodeId = grid(0).mapKeyToNode(PARTITIONED_CACHE_NAME, pinnedKey).id();

      UUID pinnedNodeId = F.first(F.view(gridsByLocNode.keySet(), F.notEqualTo(primaryNodeId)));

      GridClientNode node = compute.node(pinnedNodeId);

      partitioned.pinNodes(node).put(pinnedKey, "val" + pinnedKey);

      for (Map.Entry<UUID, Grid> entry : gridsByLocNode.entrySet()) {
        Object val = entry.getValue().cache(PARTITIONED_CACHE_NAME).peek(pinnedKey);

        if (primaryNodeId.equals(entry.getKey()) || pinnedNodeId.equals(entry.getKey()))
          assertEquals("val" + pinnedKey, val);
        else assertNull(val);
      }
    }
  }
  /**
   * @param key Key.
   * @param val Value.
   * @return {@code true} if key/value pair was set.
   */
  private boolean isAttributeSet(Object key, Object val) {
    if (attrs.containsKey(key)) {
      Object stored = attrs.get(key);

      if (val == null && stored == null) return true;

      if (val != null && stored != null) return val.equals(stored);
    }

    return false;
  }
  /**
   * Parses HTTP parameters in an appropriate format and return back map of values to predefined
   * list of names.
   *
   * @param req Request.
   * @return Map of parsed parameters.
   */
  @SuppressWarnings({"unchecked"})
  private Map<String, Object> parameters(ServletRequest req) {
    Map<String, String[]> params = req.getParameterMap();

    if (F.isEmpty(params)) return Collections.emptyMap();

    Map<String, Object> map = U.newHashMap(params.size());

    for (Map.Entry<String, String[]> entry : params.entrySet())
      map.put(entry.getKey(), parameter(entry.getValue()));

    return map;
  }
  /**
   * Gets values referenced by sequential keys, e.g. {@code key1...keyN}.
   *
   * @param keyPrefix Key prefix, e.g. {@code key} for {@code key1...keyN}.
   * @param params Parameters map.
   * @return Values.
   */
  @Nullable
  protected List<Object> values(String keyPrefix, Map<String, Object> params) {
    assert keyPrefix != null;

    List<Object> vals = new LinkedList<>();

    for (int i = 1; ; i++) {
      String key = keyPrefix + i;

      if (params.containsKey(key)) vals.add(params.get(key));
      else break;
    }

    return vals;
  }
  /** {@inheritDoc} */
  @Override
  public void setAttribute(Object key, @Nullable Object val) {
    A.notNull(key, "key");

    synchronized (attrs) {
      attrs.put(key, val);
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public <K, V> V getAttribute(K key) {
    A.notNull(key, "key");

    synchronized (attrs) {
      return (V) attrs.get(key);
    }
  }
  /** @param attrs Attributes to set. */
  public void setInternal(Map<?, ?> attrs) {
    A.notNull(attrs, "attrs");

    if (attrs.isEmpty()) return;

    List<GridTaskSessionAttributeListener> lsnrs;

    synchronized (mux) {
      this.attrs.putAll(attrs);

      lsnrs = this.lsnrs;

      mux.notifyAll();
    }

    for (Map.Entry<?, ?> entry : attrs.entrySet())
      for (GridTaskSessionAttributeListener lsnr : lsnrs)
        lsnr.onAttributeSet(entry.getKey(), entry.getValue());
  }
  /**
   * Retrieves UUID value from parameters map.
   *
   * @param key Key.
   * @param params Parameters map.
   * @return UUID value from parameters map or {@code null} if null or not exists.
   * @throws GridException If parsing failed.
   */
  @Nullable
  private static UUID uuidValue(String key, Map<String, Object> params) throws GridException {
    assert key != null;

    String val = (String) params.get(key);

    try {
      return val == null ? null : UUID.fromString(val);
    } catch (NumberFormatException ignore) {
      throw new GridException("Failed to parse parameter of UUID type [" + key + "=" + val + "]");
    }
  }
  /**
   * Retrieves long value from parameters map.
   *
   * @param key Key.
   * @param params Parameters map.
   * @param dfltVal Default value.
   * @return Long value from parameters map or {@code dfltVal} if null or not exists.
   * @throws GridException If parsing failed.
   */
  @Nullable
  private static Long longValue(String key, Map<String, Object> params, Long dfltVal)
      throws GridException {
    assert key != null;

    String val = (String) params.get(key);

    try {
      return val == null ? dfltVal : Long.valueOf(val);
    } catch (NumberFormatException ignore) {
      throw new GridException("Failed to parse parameter of Long type [" + key + "=" + val + "]");
    }
  }
  /**
   * @param cctx Context.
   * @param tx Transaction.
   * @param failedNodeId ID of failed node started transaction.
   */
  @SuppressWarnings("ConstantConditions")
  public GridCachePessimisticCheckCommittedTxFuture(
      GridCacheContext<K, V> cctx, GridCacheTxEx<K, V> tx, UUID failedNodeId) {
    super(cctx.kernalContext(), new SingleReducer<K, V>());

    this.cctx = cctx;
    this.tx = tx;
    this.failedNodeId = failedNodeId;

    log = U.logger(ctx, logRef, GridCacheOptimisticCheckPreparedTxFuture.class);

    nodes = new GridLeanMap<>();

    for (GridNode node : CU.allNodes(cctx, tx.topologyVersion())) nodes.put(node.id(), node);
  }
  /** {@inheritDoc} */
  @Override
  public void setAttributes(Map<?, ?> attrs) throws GridException {
    A.notNull(attrs, "attrs");

    if (attrs.isEmpty()) return;

    // Note that there is no mux notification in this block.
    // The reason is that we wait for ordered attributes to
    // come back from task prior to notification. The notification
    // will happen in 'setInternal(...)' method.
    synchronized (mux) {
      this.attrs.putAll(attrs);
    }

    if (isTaskNode()) ctx.task().setAttributes(this, attrs);
  }
  /**
   * Creates REST request.
   *
   * @param cmd Command.
   * @param params Parameters.
   * @return REST request.
   * @throws GridException If creation failed.
   */
  @Nullable
  private GridRestRequest createRequest(
      GridRestCommand cmd, Map<String, Object> params, ServletRequest req) throws GridException {
    GridRestRequest restReq;

    switch (cmd) {
      case CACHE_GET:
      case CACHE_GET_ALL:
      case CACHE_PUT:
      case CACHE_PUT_ALL:
      case CACHE_REMOVE:
      case CACHE_REMOVE_ALL:
      case CACHE_ADD:
      case CACHE_CAS:
      case CACHE_METRICS:
      case CACHE_REPLACE:
      case CACHE_DECREMENT:
      case CACHE_INCREMENT:
      case CACHE_APPEND:
      case CACHE_PREPEND:
        {
          GridRestCacheRequest restReq0 = new GridRestCacheRequest();

          restReq0.cacheName((String) params.get("cacheName"));
          restReq0.key(params.get("key"));
          restReq0.value(params.get("val"));
          restReq0.value2(params.get("val2"));

          Object val1 = params.get("val1");

          if (val1 != null) restReq0.value(val1);

          restReq0.cacheFlags(intValue("cacheFlags", params, 0));
          restReq0.ttl(longValue("exp", params, null));
          restReq0.initial(longValue("init", params, null));
          restReq0.delta(longValue("delta", params, null));

          if (cmd == CACHE_GET_ALL || cmd == CACHE_PUT_ALL || cmd == CACHE_REMOVE_ALL) {
            List<Object> keys = values("k", params);
            List<Object> vals = values("v", params);

            if (keys.size() < vals.size())
              throw new GridException(
                  "Number of keys must be greater or equals to number of values.");

            Map<Object, Object> map = U.newHashMap(keys.size());

            Iterator<Object> keyIt = keys.iterator();
            Iterator<Object> valIt = vals.iterator();

            while (keyIt.hasNext()) map.put(keyIt.next(), valIt.hasNext() ? valIt.next() : null);

            restReq0.values(map);
          }

          restReq = restReq0;

          break;
        }

      case TOPOLOGY:
      case NODE:
        {
          GridRestTopologyRequest restReq0 = new GridRestTopologyRequest();

          restReq0.includeMetrics(Boolean.parseBoolean((String) params.get("mtr")));
          restReq0.includeAttributes(Boolean.parseBoolean((String) params.get("attr")));

          restReq0.nodeIp((String) params.get("ip"));

          restReq0.nodeId(uuidValue("id", params));

          restReq = restReq0;

          break;
        }

      case EXE:
      case RESULT:
      case NOOP:
        {
          GridRestTaskRequest restReq0 = new GridRestTaskRequest();

          restReq0.taskId((String) params.get("id"));
          restReq0.taskName((String) params.get("name"));

          restReq0.params(values("p", params));

          restReq0.async(Boolean.parseBoolean((String) params.get("async")));

          restReq0.timeout(longValue("timeout", params, 0L));

          restReq = restReq0;

          break;
        }

      case LOG:
        {
          GridRestLogRequest restReq0 = new GridRestLogRequest();

          restReq0.path((String) params.get("path"));

          restReq0.from(intValue("from", params, -1));
          restReq0.to(intValue("to", params, -1));

          restReq = restReq0;

          break;
        }

      case VERSION:
        {
          restReq = new GridRestRequest();

          break;
        }

      default:
        throw new GridException("Invalid command: " + cmd);
    }

    restReq.address(new InetSocketAddress(req.getRemoteAddr(), req.getRemotePort()));

    restReq.command(cmd);

    if (params.containsKey("gridgain.login") || params.containsKey("gridgain.password")) {
      GridSecurityCredentials cred =
          new GridSecurityCredentials(
              (String) params.get("gridgain.login"), (String) params.get("gridgain.password"));

      restReq.credentials(cred);
    }

    String clientId = (String) params.get("clientId");

    try {
      if (clientId != null) restReq.clientId(UUID.fromString(clientId));
    } catch (Exception ignored) {
      // Ignore invalid client id. Rest handler will process this logic.
    }

    String destId = (String) params.get("destId");

    try {
      if (destId != null) restReq.destinationId(UUID.fromString(destId));
    } catch (IllegalArgumentException ignored) {
      // Don't fail - try to execute locally.
    }

    String sesTokStr = (String) params.get("sessionToken");

    try {
      if (sesTokStr != null) restReq.sessionToken(U.hexString2ByteArray(sesTokStr));
    } catch (IllegalArgumentException ignored) {
      // Ignore invalid session token.
    }

    return restReq;
  }
 /** {@inheritDoc} */
 @Override
 public Collection<? extends GridNode> nodes() {
   return nodes.values();
 }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> addData(Map<K, V> entries) throws IllegalStateException {
    A.notNull(entries, "entries");

    return addData(entries.entrySet());
  }