/** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public Collection<BinaryType> metadata() throws BinaryObjectException {
    if (clientNode)
      return F.viewReadOnly(
          clientMetaDataCache.values(),
          new IgniteClosure<BinaryTypeImpl, BinaryType>() {
            @Override
            public BinaryType apply(BinaryTypeImpl meta) {
              return meta;
            }
          });
    else {
      return F.viewReadOnly(
          metaDataCache.entrySetx(metaPred),
          new C1<Cache.Entry<PortableMetadataKey, BinaryMetadata>, BinaryType>() {
            private static final long serialVersionUID = 0L;

            @Override
            public BinaryType apply(Cache.Entry<PortableMetadataKey, BinaryMetadata> e) {
              return e.getValue().wrap(portableCtx);
            }
          });
    }
  }
  /**
   * @param nodes Nodes.
   * @param id ID.
   * @throws IgniteCheckedException If failed.
   */
  private void sendAllPartitions(
      Collection<? extends ClusterNode> nodes, GridDhtPartitionExchangeId id)
      throws IgniteCheckedException {
    GridDhtPartitionsFullMessage m =
        new GridDhtPartitionsFullMessage(id, lastVer.get(), id.topologyVersion());

    for (GridCacheContext cacheCtx : cctx.cacheContexts()) {
      if (!cacheCtx.isLocal()) {
        AffinityTopologyVersion startTopVer = cacheCtx.startTopologyVersion();

        boolean ready = startTopVer == null || startTopVer.compareTo(id.topologyVersion()) <= 0;

        if (ready)
          m.addFullPartitionsMap(cacheCtx.cacheId(), cacheCtx.topology().partitionMap(true));
      }
    }

    // It is important that client topologies be added after contexts.
    for (GridClientPartitionTopology top : cctx.exchange().clientTopologies())
      m.addFullPartitionsMap(top.cacheId(), top.partitionMap(true));

    if (log.isDebugEnabled())
      log.debug(
          "Sending full partition map [nodeIds="
              + F.viewReadOnly(nodes, F.node2id())
              + ", exchId="
              + exchId
              + ", msg="
              + m
              + ']');

    cctx.io().safeSend(nodes, m, SYSTEM_POOL, null);
  }
  /** {@inheritDoc} */
  @Override
  public String toString() {
    Collection<String> futs =
        F.viewReadOnly(
            futures(),
            new C1<IgniteInternalFuture<?>, String>() {
              @SuppressWarnings("unchecked")
              @Override
              public String apply(IgniteInternalFuture<?> f) {
                return "[node="
                    + ((MiniFuture) f).node().id()
                    + ", loc="
                    + ((MiniFuture) f).node().isLocal()
                    + ", done="
                    + f.isDone()
                    + "]";
              }
            });

    return S.toString(
        GridDhtTxFinishFuture.class,
        this,
        "xidVer",
        tx.xidVersion(),
        "innerFuts",
        futs,
        "super",
        super.toString());
  }
  /** {@inheritDoc} */
  @Override
  public String toString() {
    Collection<String> futs =
        F.viewReadOnly(
            futures(),
            new C1<IgniteInternalFuture<?>, String>() {
              @SuppressWarnings("unchecked")
              @Override
              public String apply(IgniteInternalFuture<?> f) {
                if (f.getClass() == FinishMiniFuture.class) {
                  FinishMiniFuture fut = (FinishMiniFuture) f;

                  ClusterNode node = fut.node();

                  if (node != null) {
                    return "FinishFuture[node="
                        + node.id()
                        + ", loc="
                        + node.isLocal()
                        + ", done="
                        + fut.isDone()
                        + ']';
                  } else {
                    return "FinishFuture[node=null, done=" + fut.isDone() + ']';
                  }
                } else if (f.getClass() == CheckBackupMiniFuture.class) {
                  CheckBackupMiniFuture fut = (CheckBackupMiniFuture) f;

                  ClusterNode node = fut.node();

                  if (node != null) {
                    return "CheckBackupFuture[node="
                        + node.id()
                        + ", loc="
                        + node.isLocal()
                        + ", done="
                        + f.isDone()
                        + "]";
                  } else {
                    return "CheckBackupFuture[node=null, done=" + f.isDone() + "]";
                  }
                } else if (f.getClass() == CheckRemoteTxMiniFuture.class) {
                  CheckRemoteTxMiniFuture fut = (CheckRemoteTxMiniFuture) f;

                  return "CheckRemoteTxMiniFuture[nodes="
                      + fut.nodes()
                      + ", done="
                      + f.isDone()
                      + "]";
                } else return "[loc=true, done=" + f.isDone() + "]";
              }
            });

    return S.toString(
        GridNearTxFinishFuture.class, this, "innerFuts", futs, "super", super.toString());
  }
  /** {@inheritDoc} */
  @Override
  public GridDhtPartitionMap localPartitionMap() {
    lock.readLock().lock();

    try {
      return new GridDhtPartitionMap(
          cctx.nodeId(), updateSeq.get(), F.viewReadOnly(locParts, CU.part2state()), true);
    } finally {
      lock.readLock().unlock();
    }
  }
  /** {@inheritDoc} */
  @Override
  public Collection<ClusterNode> nodes(int p, AffinityTopologyVersion topVer) {
    Collection<ClusterNode> affNodes = cctx.affinity().nodes(p, topVer);

    lock.readLock().lock();

    try {
      assert node2part != null && node2part.valid()
          : "Invalid node-to-partitions map [topVer1="
              + topVer
              + ", topVer2="
              + this.topVer
              + ", cache="
              + cctx.name()
              + ", node2part="
              + node2part
              + ']';

      Collection<ClusterNode> nodes = null;

      Collection<UUID> nodeIds = part2node.get(p);

      if (!F.isEmpty(nodeIds)) {
        Collection<UUID> affIds = new HashSet<>(F.viewReadOnly(affNodes, F.node2id()));

        for (UUID nodeId : nodeIds) {
          if (!affIds.contains(nodeId) && hasState(p, nodeId, OWNING, MOVING, RENTING)) {
            ClusterNode n = cctx.discovery().node(nodeId);

            if (n != null
                && (topVer.topologyVersion() < 0 || n.order() <= topVer.topologyVersion())) {
              if (nodes == null) {
                nodes = new ArrayList<>(affNodes.size() + 2);

                nodes.addAll(affNodes);
              }

              nodes.add(n);
            }
          }
        }
      }

      return nodes != null ? nodes : affNodes;
    } finally {
      lock.readLock().unlock();
    }
  }
  /** {@inheritDoc} */
  @Override
  public String toString() {
    Collection<String> futs =
        F.viewReadOnly(
            futures(),
            new C1<IgniteInternalFuture<?>, String>() {
              @SuppressWarnings("unchecked")
              @Override
              public String apply(IgniteInternalFuture<?> f) {
                if (isMini(f)) {
                  return "[node="
                      + ((MiniFuture) f).node().id()
                      + ", loc="
                      + ((MiniFuture) f).node().isLocal()
                      + ", done="
                      + f.isDone()
                      + "]";
                } else return "[loc=true, done=" + f.isDone() + "]";
              }
            });

    return S.toString(
        GridPartitionedGetFuture.class, this, "innerFuts", futs, "super", super.toString());
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public void notifyCallback(
      UUID nodeId, UUID routineId, Collection<?> objs, GridKernalContext ctx) {
    assert nodeId != null;
    assert routineId != null;
    assert objs != null;
    assert ctx != null;

    Collection<CacheContinuousQueryEntry> entries = (Collection<CacheContinuousQueryEntry>) objs;

    final GridCacheContext cctx = cacheContext(ctx);

    for (CacheContinuousQueryEntry e : entries) {
      GridCacheDeploymentManager depMgr = cctx.deploy();

      ClassLoader ldr = depMgr.globalLoader();

      if (ctx.config().isPeerClassLoadingEnabled()) {
        GridDeploymentInfo depInfo = e.deployInfo();

        if (depInfo != null) {
          depMgr.p2pContext(
              nodeId,
              depInfo.classLoaderId(),
              depInfo.userVersion(),
              depInfo.deployMode(),
              depInfo.participants(),
              depInfo.localDeploymentOwner());
        }
      }

      try {
        e.unmarshal(cctx, ldr);
      } catch (IgniteCheckedException ex) {
        U.error(ctx.log(getClass()), "Failed to unmarshal entry.", ex);
      }
    }

    final IgniteCache cache = cctx.kernalContext().cache().jcache(cctx.name());

    Collection<CacheContinuousQueryEntry> entries0 = new ArrayList<>();

    for (CacheContinuousQueryEntry e : entries) entries0.addAll(handleEvent(ctx, e));

    Iterable<CacheEntryEvent<? extends K, ? extends V>> evts =
        F.viewReadOnly(
            entries0,
            new C1<CacheContinuousQueryEntry, CacheEntryEvent<? extends K, ? extends V>>() {
              @Override
              public CacheEntryEvent<? extends K, ? extends V> apply(CacheContinuousQueryEntry e) {
                return new CacheContinuousQueryEvent<>(cache, cctx, e);
              }
            },
            new IgnitePredicate<CacheContinuousQueryEntry>() {
              @Override
              public boolean apply(CacheContinuousQueryEntry entry) {
                return !entry.isFiltered();
              }
            });

    locLsnr.onUpdated(evts);
  }