@Override
  public long doRead(Master master, ReadRequest readRequest) {
    incrementAccessAndMaybeRecalibrate(master);
    long fileId = readRequest.getFileId();
    Location accessLoc = readRequest.getLocation();
    MasterMeta fm = master.map.get(fileId);
    if (fm == null || fm.instances.size() == 0) {
      return -1;
    }
    long delay = -1;
    Set<Cluster> attemptedClusters = new HashSet<Cluster>();
    while (delay == -1 && attemptedClusters.size() < fm.instances.size()) {
      double minDistance = Double.MAX_VALUE;
      Cluster closest = null;
      for (Cluster c : fm.instances) {
        if (!c.isHealthy()) {
          attemptedClusters.add(c);
          continue;
        }
        if (attemptedClusters.contains(c)) {
          continue;
        }
        double cDistance = c.getLocation().distance(accessLoc);
        if (cDistance < minDistance) {
          minDistance = cDistance;
          closest = c;
        }
      }
      FileRead fr = closest.read(fileId);
      if (fr.time > 0) {
        delay = fr.time + Util.networkTime(fr.file.getSize(), minDistance);
      }
      attemptedClusters.add(closest);
    }
    return delay;
  }