@Override
  protected ApacheLogEntry prefetch() throws Exception {
    while (sortedBuffer.size() < maxSortedBufferSize) {
      if (itEntry == null) {
        if (itFile.hasNext()) {
          itEntry = new ApacheLogEntryIterator(LogDirectory.open(itFile.next().getValue()), true);
        } else {
          break;
        }
      }

      if (!itEntry.hasNext()) {
        itEntry = null;
        continue;
      }

      ApacheLogEntry entry = itEntry.next();

      if (low != null) {
        int d = entry.getDate().compareTo(low);
        if (d < 0 || (d == 0 && !lowInclusive)) {
          continue;
        }
      }

      sortedBuffer.put(entry.getDate(), entry);
    }

    if (!sortedBuffer.isEmpty()) {
      ApacheLogEntry entry = sortedBuffer.pollFirstEntry().getValue();

      if (sanityCheckMonotonictyDate != null) {
        if (sanityCheckMonotonictyDate.compareTo(entry.getDate()) > 0) {
          throw new RuntimeException("Dates are not monoton");
        }
      }
      sanityCheckMonotonictyDate = entry.getDate();

      if (high != null) {
        int d = high.compareTo(entry.getDate());
        if (d < 0 || (d == 0 && !highInclusive)) {
          return finish();
        }
      }

      return entry;
    }

    return finish();
  }
  public LogDirectory(File dir, Pattern pattern) throws IOException {
    if (!dir.isDirectory()) {
      throw new IllegalArgumentException("Argument must be a directory, got: " + dir);
    }

    // Read the date from the first line of each file, and sort the files
    // accordingly
    for (File file : dir.listFiles(new PatternFilenameFilter(pattern))) {
      ApacheLogEntryIterator it = new ApacheLogEntryIterator(open(file), true);

      while (it.hasNext()) {
        Date date = it.next().getDate();
        // logger.debug("Found log file " + file.getAbsolutePath() + " with date " + date);
        dateToFile.put(date, file);
        it.close();
        break;
      }
    }
    logger.debug("Found log files: " + dateToFile);
  }