public String printPendingRanges() {
    StringBuilder sb = new StringBuilder();

    for (Map.Entry<String, Multimap<Range, InetAddress>> entry : pendingRanges.entrySet()) {
      for (Map.Entry<Range, InetAddress> rmap : entry.getValue().entries()) {
        sb.append(rmap.getValue() + ":" + rmap.getKey());
        sb.append(System.getProperty("line.separator"));
      }
    }

    return sb.toString();
  }
  public String toString() {
    StringBuilder sb = new StringBuilder();
    lock.readLock().lock();
    try {
      Set<InetAddress> eps = tokenToEndPointMap.inverse().keySet();

      if (!eps.isEmpty()) {
        sb.append("Normal Tokens:");
        sb.append(System.getProperty("line.separator"));
        for (InetAddress ep : eps) {
          sb.append(ep);
          sb.append(":");
          sb.append(tokenToEndPointMap.inverse().get(ep));
          sb.append(System.getProperty("line.separator"));
        }
      }

      if (!bootstrapTokens.isEmpty()) {
        sb.append("Bootstrapping Tokens:");
        sb.append(System.getProperty("line.separator"));
        for (Map.Entry<Token, InetAddress> entry : bootstrapTokens.entrySet()) {
          sb.append(entry.getValue() + ":" + entry.getKey());
          sb.append(System.getProperty("line.separator"));
        }
      }

      if (!leavingEndPoints.isEmpty()) {
        sb.append("Leaving EndPoints:");
        sb.append(System.getProperty("line.separator"));
        for (InetAddress ep : leavingEndPoints) {
          sb.append(ep);
          sb.append(System.getProperty("line.separator"));
        }
      }

      if (!pendingRanges.isEmpty()) {
        sb.append("Pending Ranges:");
        sb.append(System.getProperty("line.separator"));
        sb.append(printPendingRanges());
      }
    } finally {
      lock.readLock().unlock();
    }

    return sb.toString();
  }