/** {@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} */
  @Override
  public V unswap(K key) throws GridException {
    ctx.denyOnFlags(F.asList(READ, SKIP_SWAP));

    // Unswap only from DHT. Near cache does not have swap storage.
    return dht.unswap(key);
  }
  /** {@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} */
  @Override
  public void clearAll(
      Collection<? extends K> keys,
      @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    super.clearAll(keys, filter);

    dht.clearAll(keys, filter);
  }
 /** {@inheritDoc} */
 @SuppressWarnings({"UnnecessarySuperQualifier"})
 @Override
 public Set<GridCacheEntry<K, V>> entrySet(
     @Nullable Collection<? extends K> keys,
     @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
   return new EntrySet(
       super.entrySet(keys, nearHasKey, filter), dht.entrySet(keys, dhtHasKey, filter));
 }
  /** {@inheritDoc} */
  @SuppressWarnings({"unchecked"})
  @Override
  public GridFuture<?> reloadAllAsync() {
    GridCompoundFuture fut = new GridCompoundFuture(ctx.kernalContext());

    fut.add(super.reloadAllAsync());
    fut.add(dht.reloadAllAsync());

    fut.markInitialized();

    return fut;
  }
  /** {@inheritDoc} */
  @SuppressWarnings({"unchecked"})
  @Override
  public GridFuture<?> reloadAllAsync(
      @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    GridCompoundFuture fut = new GridCompoundFuture(ctx.kernalContext());

    fut.add(super.reloadAllAsync());
    fut.add(dht.reloadAllAsync(filter));

    fut.markInitialized();

    return fut;
  }
  /** {@inheritDoc} */
  @Override
  public V peek(K key, @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    V val;

    try {
      val = peek0(true, key, SMART, filter);
    } catch (GridCacheFilterFailedException ignored) {
      if (log.isDebugEnabled()) log.debug("Filter validation failed for key: " + key);

      return null;
    }

    return val == null ? dht.peek(key, filter) : val;
  }
  /** {@inheritDoc} */
  @Override
  public V peek(K key, @Nullable Collection<GridCachePeekMode> modes) throws GridException {
    V val = null;

    if (!modes.contains(PARTITIONED_ONLY)) {
      try {
        val = peek0(true, key, modes, ctx.tm().txx());
      } catch (GridCacheFilterFailedException ignored) {
        if (log.isDebugEnabled()) log.debug("Filter validation failed for key: " + key);

        return null;
      }
    }

    return val == null && !modes.contains(NEAR_ONLY) ? dht.peek(key, modes) : val;
  }
  /** {@inheritDoc} */
  @Override
  public void reloadAll() throws GridException {
    super.reloadAll();

    dht.reloadAll();
  }
 /** {@inheritDoc} */
 @Override
 public boolean isLocked(K key) {
   return super.isLocked(key) || dht.isLocked(key);
 }
 /** {@inheritDoc} */
 @Override
 public GridCachePreloader<K, V> preloader() {
   return dht.preloader();
 }
 /** {@inheritDoc} */
 @Override
 public Set<GridCacheEntry<K, V>> primaryEntrySet(
     @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
   return new EntrySet(super.primaryEntrySet(filter), dht.primaryEntrySet(filter));
 }
  /** {@inheritDoc} */
  @Override
  public void unlockAll(
      Collection<? extends K> keys, GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    if (keys.isEmpty()) return;

    try {
      GridCacheVersion ver = null;

      Collection<GridRichNode> affNodes = null;

      int keyCnt = -1;

      Map<GridRichNode, GridNearUnlockRequest<K, V>> map = null;

      Collection<K> locKeys = new LinkedList<K>();

      GridCacheVersion obsoleteVer = ctx.versions().next();

      for (K key : keys) {
        while (true) {
          GridDistributedCacheEntry<K, V> entry = peekExx(key);

          if (entry == null || !ctx.isAll(entry.wrap(false), filter)) break; // While.

          try {
            GridCacheMvccCandidate<K> cand =
                entry.candidate(ctx.nodeId(), Thread.currentThread().getId());

            if (cand != null) {
              ver = cand.version();

              if (affNodes == null) {
                affNodes = CU.allNodes(ctx, cand.topologyVersion());

                keyCnt = (int) Math.ceil((double) keys.size() / affNodes.size());

                map = new HashMap<GridRichNode, GridNearUnlockRequest<K, V>>(affNodes.size());
              }

              // Send request to remove from remote nodes.
              GridRichNode primary = CU.primary0(ctx.affinity(key, affNodes));

              GridNearUnlockRequest<K, V> req = map.get(primary);

              if (req == null) {
                map.put(primary, req = new GridNearUnlockRequest<K, V>(keyCnt));

                req.version(ver);
              }

              // Remove candidate from local node first.
              GridCacheMvccCandidate<K> rmv = entry.removeLock();

              if (rmv != null) {
                if (!rmv.reentry()) {
                  if (ver != null && !ver.equals(rmv.version()))
                    throw new GridException(
                        "Failed to unlock (if keys were locked separately, "
                            + "then they need to be unlocked separately): "
                            + keys);

                  if (!primary.isLocal()) {
                    assert req != null;

                    req.addKey(entry.key(), entry.getOrMarshalKeyBytes(), ctx);
                  } else locKeys.add(key);

                  if (log.isDebugEnabled()) log.debug("Removed lock (will distribute): " + rmv);
                } else if (log.isDebugEnabled())
                  log.debug(
                      "Current thread still owns lock (or there are no other nodes)"
                          + " [lock="
                          + rmv
                          + ", curThreadId="
                          + Thread.currentThread().getId()
                          + ']');
              }

              // Try to evict near entry if it's dht-mapped locally.
              evictNearEntry(entry, obsoleteVer);
            }

            break;
          } catch (GridCacheEntryRemovedException ignore) {
            if (log.isDebugEnabled())
              log.debug("Attempted to unlock removed entry (will retry): " + entry);
          }
        }
      }

      if (ver == null) return;

      for (Map.Entry<GridRichNode, GridNearUnlockRequest<K, V>> mapping : map.entrySet()) {
        GridRichNode n = mapping.getKey();

        GridDistributedUnlockRequest<K, V> req = mapping.getValue();

        if (n.isLocal()) dht.removeLocks(ctx.nodeId(), req.version(), locKeys, true);
        else if (!req.keyBytes().isEmpty())
          // We don't wait for reply to this message.
          ctx.io().send(n, req);
      }
    } catch (GridException ex) {
      U.error(log, "Failed to unlock the lock for keys: " + keys, ex);
    }
  }
 /** {@inheritDoc} */
 @Override
 public GridFuture<?> loadCacheAsync(GridPredicate2<K, V> p, long ttl, Object[] args) {
   return dht.loadCacheAsync(p, ttl, args);
 }
 /** {@inheritDoc} */
 @Override
 public boolean containsKey(K key, GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
   return super.containsKey(key, filter) || dht.containsKey(key, filter);
 }
 /** {@inheritDoc} */
 @Override
 public boolean evict(K key, @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
   // Use unary 'and' to make sure that both sides execute.
   return super.evict(key, filter) & dht.evict(key, filter);
 }
 /** {@inheritDoc} */
 @Override
 public void loadCache(GridPredicate2<K, V> p, long ttl, Object[] args) throws GridException {
   dht.loadCache(p, ttl, args);
 }
 /** {@inheritDoc} */
 @Override
 public boolean clear(K key, @Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
   return super.clear(key, filter) | dht.clear(key, filter);
 }
 @Override
 public boolean apply(K k) {
   return dht.peek(k) != null;
 }
  /** {@inheritDoc} */
  @Override
  public void clearAll(@Nullable GridPredicate<? super GridCacheEntry<K, V>>[] filter) {
    super.clearAll(filter);

    dht.clearAll(filter);
  }
  /**
   * Removes locks regardless of whether they are owned or not for given version and keys.
   *
   * @param ver Lock version.
   * @param keys Keys.
   */
  @SuppressWarnings({"unchecked"})
  public void removeLocks(GridCacheVersion ver, Collection<? extends K> keys) {
    if (keys.isEmpty()) return;

    try {
      Collection<GridRichNode> affNodes = null;

      int keyCnt = -1;

      Map<GridNode, GridNearUnlockRequest<K, V>> map = null;

      for (K key : keys) {
        // Send request to remove from remote nodes.
        GridNearUnlockRequest<K, V> req = null;

        while (true) {
          GridDistributedCacheEntry<K, V> entry = peekExx(key);

          try {
            if (entry != null) {
              GridCacheMvccCandidate<K> cand = entry.candidate(ver);

              if (cand != null) {
                if (affNodes == null) {
                  affNodes = CU.allNodes(ctx, cand.topologyVersion());

                  keyCnt = (int) Math.ceil((double) keys.size() / affNodes.size());

                  map = new HashMap<GridNode, GridNearUnlockRequest<K, V>>(affNodes.size());
                }

                GridRichNode primary = CU.primary0(ctx.affinity(key, affNodes));

                if (!primary.isLocal()) {
                  req = map.get(primary);

                  if (req == null) {
                    map.put(primary, req = new GridNearUnlockRequest<K, V>(keyCnt));

                    req.version(ver);
                  }
                }

                // Remove candidate from local node first.
                if (entry.removeLock(cand.version())) {
                  if (primary.isLocal()) {
                    dht.removeLocks(primary.id(), ver, F.asList(key), true);

                    assert req == null;

                    continue;
                  }

                  req.addKey(entry.key(), entry.getOrMarshalKeyBytes(), ctx);
                }
              }
            }

            break;
          } catch (GridCacheEntryRemovedException ignored) {
            if (log.isDebugEnabled())
              log.debug(
                  "Attempted to remove lock from removed entry (will retry) [rmvVer="
                      + ver
                      + ", entry="
                      + entry
                      + ']');
          }
        }
      }

      if (map == null || map.isEmpty()) return;

      Collection<GridCacheVersion> committed = ctx.tm().committedVersions(ver);
      Collection<GridCacheVersion> rolledback = ctx.tm().rolledbackVersions(ver);

      for (Map.Entry<GridNode, GridNearUnlockRequest<K, V>> mapping : map.entrySet()) {
        GridNode n = mapping.getKey();

        GridDistributedUnlockRequest<K, V> req = mapping.getValue();

        if (!req.keyBytes().isEmpty()) {
          req.completedVersions(committed, rolledback);

          // We don't wait for reply to this message.
          ctx.io().send(n, req);
        }
      }
    } catch (GridException ex) {
      U.error(log, "Failed to unlock the lock for keys: " + keys, ex);
    }
  }
 /** {@inheritDoc} */
 @Override
 public int keySize() {
   return super.keySize() + dht.keySize();
 }