All Downloads are FREE. Search and download functionalities are using the official Maven repository.

keycloakjar.com.github.benmanes.caffeine.cache.Policy Maven / Gradle / Ivy

There is a newer version: 7.22.0
Show newest version
/*
 * Copyright 2014 Ben Manes. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.cache.Caffeine.saturatedToNanos;

import java.time.Duration;
import java.util.ConcurrentModificationException;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;

import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.PolyNull;

/**
 * An access point for inspecting and performing low-level operations based on the cache's runtime
 * characteristics. These operations are optional and dependent on how the cache was constructed
 * and what abilities the implementation exposes.
 *
 * @author [email protected] (Ben Manes)
 */
public interface Policy {

  /**
   * Returns whether the cache statistics are being accumulated.
   *
   * @return if cache statistics are being recorded
   */
  boolean isRecordingStats();

  /**
   * Returns the value associated with the {@code key} in this cache, or {@code null} if there is no
   * cached value for the {@code key}. Unlike {@link Cache#getIfPresent(Object)}, this method does
   * not produce any side effects such as updating statistics, the eviction policy, resetting the
   * expiration time, or triggering a refresh.
   *
   * @param key the key whose associated value is to be returned
   * @return the value to which the specified key is mapped, or {@code null} if this cache contains
   *         no mapping for the key
   * @throws NullPointerException if the specified key is null
   */
  @Nullable
  V getIfPresentQuietly(K key);

  /**
   * Returns the cache entry associated with the {@code key} in this cache, or {@code null} if there
   * is no cached value for the {@code key}. Unlike {@link Cache#getIfPresent(Object)}, this method
   * does not produce any side effects such as updating statistics, the eviction policy, resetting
   * the expiration time, or triggering a refresh.
   *
   * @param key the key whose associated value is to be returned
   * @return the entry mapping for the specified key, or {@code null} if this cache contains no
   *         mapping for the key
   * @throws NullPointerException if the specified key is null
   */
  @Nullable
  default CacheEntry getEntryIfPresentQuietly(K key) {
    // This method was added & implemented in version 3.0.6
    throw new UnsupportedOperationException();
  }

  /**
   * Returns an unmodifiable snapshot {@link Map} view of the in-flight refresh operations.
   *
   * @return a snapshot view of the in-flight refresh operations
   */
  Map> refreshes();

  /**
   * Returns access to perform operations based on the maximum size or maximum weight eviction
   * policy. If the cache was not constructed with a size-based bound or the implementation does
   * not support these operations, an empty {@link Optional} is returned.
   *
   * @return access to low-level operations for this cache if an eviction policy is used
   */
  Optional> eviction();

  /**
   * Returns access to perform operations based on the time-to-idle expiration policy. This policy
   * determines that an entry should be automatically removed from the cache once a fixed duration
   * has elapsed after the entry's creation, the most recent replacement of its value, or its last
   * access. Access time is reset by all cache read and write operations (including
   * {@code Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by operations
   * on the collection-views of {@link Cache#asMap}.
   * 

* If the cache was not constructed with access-based expiration or the implementation does not * support these operations, an empty {@link Optional} is returned. * * @return access to low-level operations for this cache if a time-to-idle expiration policy is * used */ Optional> expireAfterAccess(); /** * Returns access to perform operations based on the time-to-live expiration policy. This policy * determines that an entry should be automatically removed from the cache once a fixed duration * has elapsed after the entry's creation, or the most recent replacement of its value. *

* If the cache was not constructed with write-based expiration or the implementation does not * support these operations, an empty {@link Optional} is returned. * * @return access to low-level operations for this cache if a time-to-live expiration policy is * used */ Optional> expireAfterWrite(); /** * Returns access to perform operations based on the variable expiration policy. This policy * determines that an entry should be automatically removed from the cache once a per-entry * duration has elapsed. *

* If the cache was not constructed with variable expiration or the implementation does not * support these operations, an empty {@link Optional} is returned. * * @return access to low-level operations for this cache if a variable expiration policy is used */ Optional> expireVariably(); /** * Returns access to perform operations based on the time-to-live refresh policy. This policy * determines that an entry should be automatically reloaded once a fixed duration has elapsed * after the entry's creation, or the most recent replacement of its value. *

* If the cache was not constructed with write-based refresh or the implementation does not * support these operations, an empty {@link Optional} is returned. * * @return access to low-level operations for this cache if a time-to-live refresh policy is used */ Optional> refreshAfterWrite(); /** The low-level operations for a cache with a size-based eviction policy. */ interface Eviction { /** * Returns whether the cache is bounded by a maximum size or maximum weight. * * @return if the size bounding takes into account the entry's weight */ boolean isWeighted(); /** * Returns the weight of the entry. If this cache does not use a weighted size bound or does not * support querying for the entry's weight, then the {@link OptionalInt} will be empty. * * @param key the key for the entry being queried * @return the weight if the entry is present in the cache * @throws NullPointerException if the specified key is null */ OptionalInt weightOf(K key); /** * Returns the approximate accumulated weight of entries in this cache. If this cache does not * use a weighted size bound, then the {@link OptionalLong} will be empty. * * @return the combined weight of the values in this cache */ OptionalLong weightedSize(); /** * Returns the maximum total weighted or unweighted size of this cache, depending on how the * cache was constructed. This value can be best understood by inspecting {@link #isWeighted()}. * * @return the maximum size bounding, which may be either weighted or unweighted */ @NonNegative long getMaximum(); /** * Specifies the maximum total size of this cache. This value may be interpreted as the weighted * or unweighted threshold size based on how this cache was constructed. If the cache currently * exceeds the new maximum size this operation eagerly evict entries until the cache shrinks to * the appropriate size. *

* Note that some implementations may have an internal inherent bound on the maximum total size. * If the value specified exceeds that bound, then the value is set to the internal maximum. * * @param maximum the maximum, interpreted as weighted or unweighted size depending on how this * cache was constructed * @throws IllegalArgumentException if the maximum size specified is negative */ void setMaximum(@NonNegative long maximum); /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries least likely to be retained (coldest) to the entries * most likely to be retained (hottest). This order is determined by the eviction policy's best * guess at the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries within the eviction policy's exclusive lock. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the coldest entry to the hottest */ Map coldest(@NonNegative int limit); /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries least likely to be retained (coldest) to the entries * most likely to be retained (hottest). This order is determined by the eviction policy's best * guess at the time of creating this snapshot view. If the cache is bounded by a maximum size * rather than a maximum weight, then this method is equivalent to {@link #coldest(int)}. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries within the eviction policy's exclusive lock. * * @param weightLimit the maximum weight of the returned map (use {@link Long#MAX_VALUE} to * disregard the limit) * @return a snapshot view of the cache from the coldest entry to the hottest */ default Map coldestWeighted(@NonNegative long weightLimit) { // This method was added & implemented in version 3.0.4 throw new UnsupportedOperationException(); } /** * Returns the computed result from the ordered traversal of the cache entries. The order of * iteration is from the entries least likely to be retained (coldest) to the entries most * likely to be retained (hottest). This order is determined by the eviction policy's best guess * at the time of creating this computation. *

* Usage example: *

{@code
     *   List tenColdestKeys = cache.policy().eviction().orElseThrow()
     *       .coldest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so * @throws ConcurrentModificationException if the computation detectably reads or writes an * entry in this cache */ default T coldest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries most likely to be retained (hottest) to the entries * least likely to be retained (coldest). This order is determined by the eviction policy's best * guess at the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries within the eviction policy's exclusive lock. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the hottest entry to the coldest */ Map hottest(@NonNegative int limit); /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries most likely to be retained (hottest) to the entries * least likely to be retained (coldest). This order is determined by the eviction policy's best * guess at the time of creating this snapshot view. If the cache is bounded by a maximum size * rather than a maximum weight, then this method is equivalent to {@link #hottest(int)}. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries within the eviction policy's exclusive lock. * * @param weightLimit the maximum weight of the returned map (use {@link Long#MAX_VALUE} to * disregard the limit) * @return a snapshot view of the cache from the hottest entry to the coldest */ default Map hottestWeighted(@NonNegative long weightLimit) { // This method was added & implemented in version 3.0.4 throw new UnsupportedOperationException(); } /** * Returns the computed result from the ordered traversal of the cache entries. The order of * iteration is from the entries most likely to be retained (hottest) to the entries least * likely to be retained (coldest). This order is determined by the eviction policy's best guess * at the time of creating this computation. *

* Usage example: *

{@code
     *   List tenHottestKeys = cache.policy().eviction().orElseThrow()
     *       .hottest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so * @throws ConcurrentModificationException if the computation detectably reads or writes an * entry in this cache */ default T hottest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } } /** The low-level operations for a cache with a fixed expiration policy. */ interface FixedExpiration { /** * Returns the age of the entry based on the expiration policy. The entry's age is the cache's * estimate of the amount of time since the entry's expiration was last reset. *

* An expiration policy uses the age to determine if an entry is fresh or stale by comparing it * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age} * where {@code freshnessLifetime = expires - currentTime}. * * @param key the key for the entry being queried * @param unit the unit that {@code age} is expressed in * @return the age if the entry is present in the cache * @throws NullPointerException if the specified key is null */ OptionalLong ageOf(K key, TimeUnit unit); /** * Returns the age of the entry based on the expiration policy. The entry's age is the cache's * estimate of the amount of time since the entry's expiration was last reset. *

* An expiration policy uses the age to determine if an entry is fresh or stale by comparing it * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age} * where {@code freshnessLifetime = expires - currentTime}. * * @param key the key for the entry being queried * @return the age if the entry is present in the cache * @throws NullPointerException if the specified key is null */ default Optional ageOf(K key) { OptionalLong duration = ageOf(key, TimeUnit.NANOSECONDS); return duration.isPresent() ? Optional.of(Duration.ofNanos(duration.getAsLong())) : Optional.empty(); } /** * Returns the fixed duration used to determine if an entry should be automatically removed due * to elapsing this time bound. An entry is considered fresh if its age is less than this * duration, and stale otherwise. The expiration policy determines when the entry's age is * reset. * * @param unit the unit that duration is expressed in * @return the length of time after which an entry should be automatically removed * @throws NullPointerException if the unit is null */ @NonNegative long getExpiresAfter(TimeUnit unit); /** * Returns the fixed duration used to determine if an entry should be automatically removed due * to elapsing this time bound. An entry is considered fresh if its age is less than this * duration, and stale otherwise. The expiration policy determines when the entry's age is * reset. * * @return the length of time after which an entry should be automatically removed */ default Duration getExpiresAfter() { return Duration.ofNanos(getExpiresAfter(TimeUnit.NANOSECONDS)); } /** * Specifies that each entry should be automatically removed from the cache once a fixed * duration has elapsed. The expiration policy determines when the entry's age is reset. * * @param duration the length of time after which an entry should be automatically removed * @param unit the unit that {@code duration} is expressed in * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the unit is null */ void setExpiresAfter(@NonNegative long duration, TimeUnit unit); /** * Specifies that each entry should be automatically removed from the cache once a fixed * duration has elapsed. The expiration policy determines when the entry's age is reset. * * @param duration the length of time after which an entry should be automatically removed * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the duration is null */ default void setExpiresAfter(Duration duration) { setExpiresAfter(saturatedToNanos(duration), TimeUnit.NANOSECONDS); } /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries most likely to expire (oldest) to the entries least * likely to expire (youngest). This order is determined by the expiration policy's best guess * at the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the oldest entry to the youngest */ Map oldest(@NonNegative int limit); /** * Returns the computed result from the ordered traversal of the cache entries. The oorder of * iteration is from the entries most likely to expire (oldest) to the entries least likely to * expire (youngest). This order is determined by the expiration policy's best guess at the time * of creating this computation. *

* Usage example: *

{@code
     *   List tenOldestKeys = cache.policy().expireAfterWrite().orElseThrow()
     *       .oldest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so */ default T oldest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries least likely to expire (youngest) to the entries most * likely to expire (oldest). This order is determined by the expiration policy's best guess at * the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the youngest entry to the oldest */ Map youngest(@NonNegative int limit); /** * Returns the computed result from the ordered traversal of the cache entries. The order of * iteration is from the entries least likely to expire (youngest) to the entries most likely to * expire (oldest). This order is determined by the expiration policy's best guess at the time * of creating this computation. *

* Usage example: *

{@code
     *   List tenYoungestKeys = cache.policy().expireAfterWrite().orElseThrow()
     *       .youngest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so */ default T youngest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } } /** The low-level operations for a cache with a variable expiration policy. */ interface VarExpiration { /** * Returns the duration until the entry should be automatically removed. The expiration policy * determines when the entry's duration is reset. * * @param key the key for the entry being queried * @param unit the unit that {@code age} is expressed in * @return the duration if the entry is present in the cache * @throws NullPointerException if the specified key or unit is null */ OptionalLong getExpiresAfter(K key, TimeUnit unit); /** * Returns the duration until the entry should be automatically removed. The expiration policy * determines when the entry's duration is reset. * * @param key the key for the entry being queried * @return the duration if the entry is present in the cache * @throws NullPointerException if the specified key is null */ default Optional getExpiresAfter(K key) { OptionalLong duration = getExpiresAfter(key, TimeUnit.NANOSECONDS); return duration.isPresent() ? Optional.of(Duration.ofNanos(duration.getAsLong())) : Optional.empty(); } /** * Specifies that the entry should be automatically removed from the cache once the duration has * elapsed. The expiration policy determines when the entry's age is reset. * * @param key the key for the entry being set * @param duration the length of time from now when the entry should be automatically removed * @param unit the unit that {@code duration} is expressed in * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key or unit is null */ void setExpiresAfter(K key, @NonNegative long duration, TimeUnit unit); /** * Specifies that the entry should be automatically removed from the cache once the duration has * elapsed. The expiration policy determines when the entry's age is reset. * * @param key the key for the entry being set * @param duration the length of time from now when the entry should be automatically removed * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key or duration is null */ default void setExpiresAfter(K key, Duration duration) { setExpiresAfter(key, saturatedToNanos(duration), TimeUnit.NANOSECONDS); } /** * Associates the {@code value} with the {@code key} in this cache if the specified key is not * already associated with a value. This method differs from {@link Map#putIfAbsent} by * substituting the configured {@link Expiry} with the specified duration, has no effect on the * duration if the entry was present, and returns the success rather than a value. * * @param key the key with which the specified value is to be associated * @param value value to be associated with the specified key * @param duration the length of time from now when the entry should be automatically removed * @param unit the unit that {@code duration} is expressed in * @return the previous value associated with the specified key, or {@code null} if there was no * mapping for the key. * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key, value, or unit is null */ @Nullable V putIfAbsent(K key, V value, @NonNegative long duration, TimeUnit unit); /** * Associates the {@code value} with the {@code key} in this cache if the specified key is not * already associated with a value. This method differs from {@link Map#putIfAbsent} by * substituting the configured {@link Expiry} with the specified duration, has no effect on the * duration if the entry was present, and returns the success rather than a value. * * @param key the key with which the specified value is to be associated * @param value value to be associated with the specified key * @param duration the length of time from now when the entry should be automatically removed * @return the previous value associated with the specified key, or {@code null} if there was no * mapping for the key. * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key, value, or duration is null */ default @Nullable V putIfAbsent(K key, V value, Duration duration) { return putIfAbsent(key, value, saturatedToNanos(duration), TimeUnit.NANOSECONDS); } /** * Associates the {@code value} with the {@code key} in this cache. If the cache previously * contained a value associated with the {@code key}, the old value is replaced by the new * {@code value}. This method differs from {@link Cache#put} by substituting the configured * {@link Expiry} with the specified duration. * * @param key the key with which the specified value is to be associated * @param value value to be associated with the specified key * @param duration the length of time from now when the entry should be automatically removed * @param unit the unit that {@code duration} is expressed in * @return the previous value associated with {@code key}, or {@code null} if there was no * mapping for {@code key}. * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key, value, or unit is null */ @Nullable V put(K key, V value, @NonNegative long duration, TimeUnit unit); /** * Associates the {@code value} with the {@code key} in this cache. If the cache previously * contained a value associated with the {@code key}, the old value is replaced by the new * {@code value}. This method differs from {@link Cache#put} by substituting the * configured {@link Expiry} with the specified duration. * * @param key the key with which the specified value is to be associated * @param value value to be associated with the specified key * @param duration the length of time from now when the entry should be automatically removed * @return the previous value associated with {@code key}, or {@code null} if there was no * mapping for {@code key}. * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key, value, or duration is null */ default @Nullable V put(K key, V value, Duration duration) { return put(key, value, saturatedToNanos(duration), TimeUnit.NANOSECONDS); } /** * Attempts to compute a mapping for the specified key and its current mapped value (or * {@code null} if there is no current mapping). The entire method invocation is performed * atomically. The supplied function is invoked exactly once per invocation of this method. Some * attempted update operations on this cache by other threads may be blocked while the * computation is in progress, so the computation should be short and simple. This method * differs from {@code cache.asMap().compute(key, remappingFunction)} by substituting the * configured {@link Expiry} with the specified duration. *

* Warning: the {@code remappingFunction} must not attempt to update any other * mappings of this cache. * * @param key key with which the specified value is to be associated * @param remappingFunction the function to compute a value * @param duration the length of time from now when the entry should be automatically removed * @return the new value associated with the specified key, or null if none * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the specified key, remappingFunction, or duration is null * @throws IllegalStateException if the computation detectably attempts a recursive update to * this cache that would otherwise never complete * @throws RuntimeException or Error if the remappingFunction does so, in which case the mapping * is unchanged */ default @PolyNull V compute(K key, BiFunction remappingFunction, Duration duration) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries most likely to expire (oldest) to the entries least * likely to expire (youngest). This order is determined by the expiration policy's best guess * at the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the oldest entry to the youngest */ Map oldest(@NonNegative int limit); /** * Returns the computed result from the ordered traversal of the cache entries. The oorder of * iteration is from the entries most likely to expire (oldest) to the entries least likely to * expire (youngest). This order is determined by the expiration policy's best guess at the time * of creating this computation. *

* Usage example: *

{@code
     *   List tenOldestKeys = cache.policy().expireAfterVariably().orElseThrow()
     *       .oldest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so */ default T oldest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } /** * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The * order of iteration is from the entries least likely to expire (youngest) to the entries most * likely to expire (oldest). This order is determined by the expiration policy's best guess at * the time of creating this snapshot view. *

* Beware that obtaining the mappings is NOT a constant-time operation. Because of the * asynchronous nature of the page replacement policy, determining the retention ordering * requires a traversal of the entries. * * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard * the limit) * @return a snapshot view of the cache from the youngest entry to the oldest */ Map youngest(@NonNegative int limit); /** * Returns the computed result from the ordered traversal of the cache entries. The order of * iteration is from the entries least likely to expire (youngest) to the entries most likely to * expire (oldest). This order is determined by the expiration policy's best guess at the time * of creating this computation. *

* Usage example: *

{@code
     *   List tenYoungestKeys = cache.policy().expireAfterVariably().orElseThrow()
     *       .youngest(stream -> stream.map(Map.Entry::getKey).limit(10).toList());
     * }
*

* Beware that this computation is performed within the eviction policy's exclusive lock, so the * computation should be short and simple. While the computation is in progress further eviction * maintenance will be halted. * * @param the type of the result of the mappingFunction * @param mappingFunction the mapping function to compute a value * @return the computed value * @throws NullPointerException if the mappingFunction is null * @throws RuntimeException or Error if the mappingFunction does so */ default T youngest(Function>, T> mappingFunction) { // This method was added & implemented in version 3.0.6 throw new UnsupportedOperationException(); } } /** The low-level operations for a cache with a fixed refresh policy. */ interface FixedRefresh { /** * Returns the age of the entry based on the refresh policy. The entry's age is the cache's * estimate of the amount of time since the entry's refresh period was last reset. *

* A refresh policy uses the age to determine if an entry is fresh or stale by comparing it * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age} * where {@code freshnessLifetime = expires - currentTime}. * * @param key the key for the entry being queried * @param unit the unit that {@code age} is expressed in * @return the age if the entry is present in the cache * @throws NullPointerException if the specified key or unit is null */ OptionalLong ageOf(K key, TimeUnit unit); /** * Returns the age of the entry based on the refresh policy. The entry's age is the cache's * estimate of the amount of time since the entry's refresh period was last reset. *

* A refresh policy uses the age to determine if an entry is fresh or stale by comparing it * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age} * where {@code freshnessLifetime = expires - currentTime}. * * @param key the key for the entry being queried * @return the age if the entry is present in the cache * @throws NullPointerException if the specified key is null */ default Optional ageOf(K key) { OptionalLong duration = ageOf(key, TimeUnit.NANOSECONDS); return duration.isPresent() ? Optional.of(Duration.ofNanos(duration.getAsLong())) : Optional.empty(); } /** * Returns the fixed duration used to determine if an entry should be eligible for reloading due * to elapsing this time bound. An entry is considered fresh if its age is less than this * duration, and stale otherwise. The refresh policy determines when the entry's age is * reset. * * @param unit the unit that duration is expressed in * @return the length of time after which an entry is eligible to be reloaded * @throws NullPointerException if the unit is null */ @NonNegative long getRefreshesAfter(TimeUnit unit); /** * Returns the fixed duration used to determine if an entry should be eligible for reloading due * to elapsing this time bound. An entry is considered fresh if its age is less than this * duration, and stale otherwise. The refresh policy determines when the entry's age is * reset. * * @return the length of time after which an entry is eligible to be reloaded */ default Duration getRefreshesAfter() { return Duration.ofNanos(getRefreshesAfter(TimeUnit.NANOSECONDS)); } /** * Specifies that each entry should be eligible for reloading once a fixed duration has elapsed. * The refresh policy determines when the entry's age is reset. * * @param duration the length of time after which an entry is eligible to be reloaded * @param unit the unit that {@code duration} is expressed in * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the unit is null */ void setRefreshesAfter(@NonNegative long duration, TimeUnit unit); /** * Specifies that each entry should be eligible for reloading once a fixed duration has elapsed. * The refresh policy determines when the entry's age is reset. * * @param duration the length of time after which an entry is eligible to be reloaded * @throws IllegalArgumentException if {@code duration} is negative * @throws NullPointerException if the duration is null */ default void setRefreshesAfter(Duration duration) { setRefreshesAfter(saturatedToNanos(duration), TimeUnit.NANOSECONDS); } } /** * A key-value pair that may include policy metadata for the cached entry. Unless otherwise * specified, this is a value-based class, it can be assumed that the implementation is an * immutable snapshot of the cached data at the time of this entry's creation, and it will not * reflect changes afterwards. */ interface CacheEntry extends Map.Entry { /** * Returns the entry's weight. If the cache was not configured with a maximum weight then this * value is always {@code 1}. * * @return the weight if the entry */ int weight(); /** * Returns the {@link Ticker#read()} ticks for when this entry expires. If the cache was not * configured with an expiration policy then this value is roughly {@link Long#MAX_VALUE} * ticks away from the {@link #snapshotAt()} reading. * * @return the ticker reading for when the entry expires */ long expiresAt(); /** * Returns the duration between {@link #expiresAt()} and {@link #snapshotAt()}. * * @return the length of time after which the entry will be automatically removed */ default Duration expiresAfter() { return Duration.ofNanos(expiresAt() - snapshotAt()); } /** * Returns the {@link Ticker#read()} ticks for when this entry becomes refreshable. If the cache * was not configured with a refresh policy then this value is roughly {@link Long#MAX_VALUE} * ticks away from the {@link #snapshotAt()} reading. * * @return the ticker reading for when the entry may be refreshed */ long refreshableAt(); /** * Returns the duration between {@link #refreshableAt()} and {@link #snapshotAt()}. * * @return the length of time after which an entry is eligible to be reloaded */ default Duration refreshableAfter() { return Duration.ofNanos(refreshableAt() - snapshotAt()); } /** * Returns the {@link Ticker#read()} ticks for when this snapshot of the entry was taken. This * reading may be a constant if no time-based policy is configured. * * @return the ticker reading for when this snapshot of the entry was taken. */ long snapshotAt(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy