/** @param nodeId Node to remove. */
  private void removeNode(UUID nodeId) {
    assert nodeId != null;
    assert lock.writeLock().isHeldByCurrentThread();

    ClusterNode oldest = CU.oldestAliveCacheServerNode(cctx.shared(), topVer);

    assert oldest != null;

    ClusterNode loc = cctx.localNode();

    if (node2part != null) {
      if (oldest.equals(loc) && !node2part.nodeId().equals(loc.id())) {
        updateSeq.setIfGreater(node2part.updateSequence());

        node2part =
            new GridDhtPartitionFullMap(
                loc.id(), loc.order(), updateSeq.incrementAndGet(), node2part, false);
      } else node2part = new GridDhtPartitionFullMap(node2part, node2part.updateSequence());

      part2node = new HashMap<>(part2node);

      GridDhtPartitionMap parts = node2part.remove(nodeId);

      if (parts != null) {
        for (Integer p : parts.keySet()) {
          Set<UUID> nodeIds = part2node.get(p);

          if (nodeIds != null) {
            nodeIds.remove(nodeId);

            if (nodeIds.isEmpty()) part2node.remove(p);
          }
        }
      }

      consistencyCheck();
    }
  }
  /** {@inheritDoc} */
  @Override
  public void updateTopologyVersion(
      GridDhtPartitionExchangeId exchId,
      GridDhtPartitionsExchangeFuture exchFut,
      long updSeq,
      boolean stopping) {
    lock.writeLock().lock();

    try {
      assert exchId.topologyVersion().compareTo(topVer) > 0
          : "Invalid topology version [topVer=" + topVer + ", exchId=" + exchId + ']';

      this.stopping = stopping;

      topVer = exchId.topologyVersion();

      updateSeq.setIfGreater(updSeq);

      topReadyFut = exchFut;
    } finally {
      lock.writeLock().unlock();
    }
  }