code: synchronized EvictionResult evictBefore(int oldestGeneration) {
          // Remove those entries that have a generation below the oldest permissible one.
          long sizeRemoved = 0;
          ArrayList<Short> removedGroups = new ArrayList<>();
          for (val e : this.cacheEntries.entrySet()) {
              CacheEntry entry = e.getValue();
              if (entry.getGeneration() < oldestGeneration
                      && entry.getHighestOffset() < this.lastIndexedOffset) {
                  removedGroups.add(e.getKey());
                  sizeRemoved += entry.getSize();
              }
          }
  
          // Clear the expired cache entries.
          removedGroups.forEach(this.cacheEntries::remove);
  
          // Remove from the Cache. It's ok to do this outside of the lock as the cache is thread safe.
          return new EvictionResult(sizeRemoved, removedGroups.stream().map(CacheKey::new).collect(Collectors.toList()));
      }
docs: Collects and unregisters all Cache Entries with a generation smaller than the given one. This method does not
  actually execute the eviction since it is invoked while a lock is held in {@link ContainerKeyCache}. The caller
  ({@link ContainerKeyCache}) needs to execute the actual cache eviction.
  
  @param oldestGeneration The oldest permissible generation.
  @return An {@link EvictionResult} instance containing the number of bytes evicted and the {@link Cache.Key} for
  each Cache Entry that needs eviction.