/** {@inheritDoc} */
  @Override
  public R get(long timeout, TimeUnit unit) throws GridException {
    A.ensure(timeout >= 0, "timeout cannot be negative: " + timeout);
    A.notNull(unit, "unit");

    checkValid();

    try {
      long now = System.currentTimeMillis();

      long end = timeout == 0 ? Long.MAX_VALUE : now + MILLISECONDS.convert(timeout, unit);

      // Account for overflow.
      if (end < 0) end = Long.MAX_VALUE;

      synchronized (mux) {
        while (!done && !cancelled && now < end) {
          mux.wait(end - now);

          if (!done) now = System.currentTimeMillis();
        }

        if (done) {
          if (err != null) throw U.cast(err);

          return res;
        }

        if (cancelled) throw new GridFutureCancelledException("Future was cancelled: " + this);

        throw new GridFutureTimeoutException(
            "Timeout was reached before computation completed [duration="
                + duration()
                + "ms, timeout="
                + unit.toMillis(timeout)
                + "ms]");
      }
    } catch (InterruptedException e) {
      throw new GridInterruptedException(
          "Got interrupted while waiting for future to complete [duration="
              + duration()
              + "ms, timeout="
              + unit.toMillis(timeout)
              + "ms]",
          e);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void autoFlushFrequency(long autoFlushFreq) {
    A.ensure(autoFlushFreq >= 0, "autoFlushFreq >= 0");

    long old = this.autoFlushFreq;

    if (autoFlushFreq != old) {
      this.autoFlushFreq = autoFlushFreq;

      if (autoFlushFreq != 0 && old == 0) flushQ.add(this);
      else if (autoFlushFreq == 0) flushQ.remove(this);
    }
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> addData(Collection<? extends Map.Entry<K, V>> entries) {
    A.notEmpty(entries, "entries");

    enterBusy();

    try {
      GridFutureAdapter<Object> resFut = new GridFutureAdapter<>(ctx);

      activeFuts.add(resFut);

      resFut.listenAsync(rmvActiveFut);

      Collection<K> keys = new GridConcurrentHashSet<>(entries.size(), 1.0f, 16);

      for (Map.Entry<K, V> entry : entries) keys.add(entry.getKey());

      load0(entries, resFut, keys, 0);

      return resFut;
    } finally {
      leaveBusy();
    }
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> addData(K key, V val) throws GridException, IllegalStateException {
    A.notNull(key, "key");

    return addData(new Entry0<>(key, val));
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> addData(Map.Entry<K, V> entry) throws GridException, IllegalStateException {
    A.notNull(entry, "entry");

    return addData(F.asList(entry));
  }
  /** {@inheritDoc} */
  @Override
  public GridFuture<?> addData(Map<K, V> entries) throws IllegalStateException {
    A.notNull(entries, "entries");

    return addData(entries.entrySet());
  }
  /** {@inheritDoc} */
  @Override
  public void perNodeBufferSize(int bufSize) {
    A.ensure(bufSize > 0, "bufSize > 0");

    this.bufSize = bufSize;
  }
  /** {@inheritDoc} */
  @Override
  public void updater(GridDataLoadCacheUpdater<K, V> updater) {
    A.notNull(updater, "updater");

    this.updater = updater;
  }