/**
  * Create a copy of TokenMetadata with tokenToEndPointMap reflecting situation after all current
  * leave operations have finished.
  */
 public TokenMetadata cloneAfterAllLeft() {
   lock.readLock().lock();
   try {
     TokenMetadata allLeftMetadata = cloneOnlyTokenMap();
     for (InetAddress endPoint : leavingEndPoints) allLeftMetadata.removeEndpoint(endPoint);
     return allLeftMetadata;
   } finally {
     lock.readLock().unlock();
   }
 }
  /**
   * Create a copy of TokenMetadata with tokenToEndpointMap reflecting situation after all current
   * leave, move, and relocate operations have finished.
   *
   * @return new token metadata
   */
  public TokenMetadata cloneAfterAllSettled() {
    lock.readLock().lock();

    try {
      TokenMetadata metadata = cloneOnlyTokenMap();

      for (InetAddress endpoint : leavingEndpoints) metadata.removeEndpoint(endpoint);

      for (Pair<Token, InetAddress> pair : movingEndpoints)
        metadata.updateNormalToken(pair.left, pair.right);

      for (Map.Entry<Token, InetAddress> relocating : relocatingTokens.entrySet())
        metadata.updateNormalToken(relocating.getKey(), relocating.getValue());

      return metadata;
    } finally {
      lock.readLock().unlock();
    }
  }