class EHCachingSearchCache {

  public IntObjectPair<List<UniqueId>> search(final Bean requestBean, PagingRequest pagingRequest,
                                                     boolean blockUntilCached) {

    ArgumentChecker.notNull(requestBean, "requestBean");
    ArgumentChecker.notNull(pagingRequest, "pagingRequest");

    // Fetch the total #results and cached ranges for the search request (without paging)
    final IntObjectPair<ConcurrentNavigableMap<Integer, List<UniqueId>>> info =
        getCachedRequestInfo(requestBean, pagingRequest);
    final int totalResults = info.getFirstInt();
    final ConcurrentNavigableMap<Integer, List<UniqueId>> rangeMap = info.getSecond();

    // Fix indexes larger than the total doc count
    if (pagingRequest.getFirstItem() >= totalResults) {
      pagingRequest = PagingRequest.ofIndex(totalResults, 0);
    } else if (pagingRequest.getLastItem() >= totalResults) {
      pagingRequest = PagingRequest.ofIndex(pagingRequest.getFirstItem(), totalResults - pagingRequest.getFirstItem());
    }

    // Ensure that the required range is cached in its entirety
    IntObjectPair<List<UniqueId>> pair =
        cacheSuperRange(requestBean, pagingRequest, rangeMap, totalResults, blockUntilCached);

    final int superIndex = pair.getFirstInt();
    final List<UniqueId> superRange = pair.getSecond();

    // Create and return the search result
    final List<UniqueId> resultUniqueIds = superRange.subList(
        pagingRequest.getFirstItem() - superIndex,
        Math.min(pagingRequest.getLastItem()  - superIndex, superRange.size()));

    return IntObjectPair.of(totalResults, resultUniqueIds);
  }

  public  EHCachingSearchCache(String name, CacheManager cacheManager, Searcher searcher);

}