/**
   * Cleans up the cache. All outdated items will be removed from both maps.
   *
   * @return the set of reservations that was removed from the two caches
   */
  @VisibleForTesting
  protected Set<Reservation> cleanUpCache() {

    log.trace("ReservationManagerImpl.cleanUpCache()");

    final Set<Reservation> removed = newHashSet();

    reservationsCacheLock.lock();
    try {

      for (Iterator<Map.Entry<NodeUrn, List<CacheItem<Reservation>>>> cacheIterator =
              reservationsByNodeUrn.entrySet().iterator();
          cacheIterator.hasNext(); ) {

        final Map.Entry<NodeUrn, List<CacheItem<Reservation>>> entry = cacheIterator.next();

        for (Iterator<CacheItem<Reservation>> itemIterator = entry.getValue().iterator();
            itemIterator.hasNext(); ) {
          final CacheItem<Reservation> item = itemIterator.next();
          if (item.isOutdated()) {
            removed.add(item.get());
            itemIterator.remove();
          }
        }

        if (entry.getValue().isEmpty()) {
          cacheIterator.remove();
        }
      }

      for (Iterator<Map.Entry<Set<SecretReservationKey>, CacheItem<Reservation>>> iterator =
              reservationsBySrk.entrySet().iterator();
          iterator.hasNext(); ) {

        final Map.Entry<Set<SecretReservationKey>, CacheItem<Reservation>> entry = iterator.next();
        final CacheItem<Reservation> item = entry.getValue();

        if (item.isOutdated()) {
          iterator.remove();
          removed.add(item.get());
        }
      }

      log.trace(
          "ReservationManagerImpl.cleanUpCache() removed {} entries: {}", removed.size(), removed);

      return removed;

    } finally {
      reservationsCacheLock.unlock();
    }
  }
 @Override
 public Set<Reservation> getAll() {
   log.trace("ReservationCacheImpl.getAll()");
   checkRunning();
   Set<Reservation> reservations = newHashSet();
   for (CacheItem<Reservation> item : reservationsBySrk.values()) {
     if (!item.isOutdated()) {
       reservations.add(item.get());
       item.touch();
     }
   }
   return reservations;
 }
 @Override
 public Optional<Reservation> lookup(final Set<SecretReservationKey> srks) {
   log.trace("ReservationCacheImpl.lookup({})", srks);
   checkRunning();
   CacheItem<Reservation> item = reservationsBySrk.get(srks);
   if (item != null) {
     if (item.isOutdated()) {
       return Optional.absent();
     }
     Reservation reservation = item.get();
     reservation.touch();
     return Optional.of(reservation);
   }
   return Optional.absent();
 }
  @Override
  public Optional<Reservation> lookup(final NodeUrn nodeUrn, final DateTime timestamp) {

    log.trace("ReservationCacheImpl.lookup({}, {})", nodeUrn, timestamp);
    checkRunning();

    synchronized (reservationsByNodeUrn) {
      final List<CacheItem<Reservation>> entry = reservationsByNodeUrn.get(nodeUrn);

      if (entry == null) {
        log.trace("ReservationManagerImpl.lookup() CACHE MISS");
        return Optional.absent();
      }

      for (CacheItem<Reservation> item : entry) {

        final Interval effectiveInterval;
        final Reservation reservation = item.get();
        final DateTime reservationStart = reservation.getInterval().getStart();
        final DateTime reservationCancellation = reservation.getCancelled();

        if (reservationCancellation != null) {
          if (reservationCancellation.isBefore(reservationStart)) {
            continue;
          } else {
            effectiveInterval = new Interval(reservationStart, reservationCancellation);
          }
        } else {
          effectiveInterval = reservation.getInterval();
        }

        if (effectiveInterval.contains(timestamp)) {
          if (!item.isOutdated()) {
            item.touch();
            log.trace("ReservationManagerImpl.lookup() CACHE HIT");
            return Optional.of(reservation);
          }
        }
      }
    }
    return Optional.absent();
  }