class TrackedQueryManager {

  public PruneForest pruneOldQueries(CachePolicy cachePolicy) {
    List<TrackedQuery> prunable = getQueriesMatching(IS_QUERY_PRUNABLE_PREDICATE);
    long countToPrune = calculateCountToPrune(cachePolicy, prunable.size());
    PruneForest forest = new PruneForest();

    if (logger.logsDebug()) {
      logger.debug(
          "Pruning old queries.  Prunable: "
              + prunable.size()
              + " Count to prune: "
              + countToPrune);
    }

    Collections.sort(
        prunable,
        new Comparator<TrackedQuery>() {
          @Override
          public int compare(TrackedQuery q1, TrackedQuery q2) {
            return Utilities.compareLongs(q1.lastUse, q2.lastUse);
          }
        });

    for (int i = 0; i < countToPrune; i++) {
      TrackedQuery toPrune = prunable.get(i);
      forest = forest.prune(toPrune.querySpec.getPath());
      removeTrackedQuery(toPrune.querySpec);
    }

    // Keep the rest of the prunable queries.
    for (int i = (int) countToPrune; i < prunable.size(); i++) {
      TrackedQuery toKeep = prunable.get(i);
      forest = forest.keep(toKeep.querySpec.getPath());
    }

    // Also keep the unprunable queries.
    List<TrackedQuery> unprunable = getQueriesMatching(IS_QUERY_UNPRUNABLE_PREDICATE);
    if (logger.logsDebug()) {
      logger.debug("Unprunable queries: " + unprunable.size());
    }
    for (TrackedQuery toKeep : unprunable) {
      forest = forest.keep(toKeep.querySpec.getPath());
    }

    return forest;
  }

  public  TrackedQueryManager(
      PersistenceStorageEngine storageLayer, LogWrapper logger, Clock clock);

}