/** * 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 write 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 * @throws IllegalArgumentException if {@code duration} is negative */ default void put(@NonNull K key, @NonNull V value, @NonNull Duration duration) { // This method will be abstract in version 3.0.0 put(key, value, duration.toNanos(), TimeUnit.NANOSECONDS); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.MOCKITO, expiryTime = Expire.ONE_MINUTE) public void getExpiresAfter_duration(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { assertThat(expireAfterVar.getExpiresAfter(context.absentKey()), is(Optional.empty())); assertThat(expireAfterVar.getExpiresAfter(context.firstKey()), is(Optional.of(Duration.ofMinutes(1L)))); when(context.expiry().expireAfterUpdate(any(), any(), anyLong(), anyLong())) .thenReturn(TimeUnit.HOURS.toNanos(1)); cache.put(context.firstKey(), context.absentValue()); assertThat(expireAfterVar.getExpiresAfter(context.firstKey()), is(Optional.of(Duration.ofHours(1)))); assertThat(expireAfterVar.getExpiresAfter(context.lastKey()), is(Optional.of(Duration.ofMinutes(1)))); }
/** * 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 write 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 <tt>true</tt> if this cache did not already contain the specified entry * @throws IllegalArgumentException if {@code duration} is negative */ default boolean putIfAbsent(@NonNull K key, @NonNull V value, @NonNull Duration duration) { // This method will be abstract in version 3.0.0 return putIfAbsent(key, value, duration.toNanos(), TimeUnit.NANOSECONDS); }
@Override public <T> void put(String appid, String id, T object, Long ttlSeconds) { if (ttlSeconds == null || ttlSeconds <= 0L) { put(appid, id, object); return; } if (!StringUtils.isBlank(id) && object != null && !StringUtils.isBlank(appid)) { String key = key(appid, id); cache.policy().expireVariably().ifPresent((t) -> { t.put(key, object, ttlSeconds, TimeUnit.SECONDS); }); logger.debug("Cache.put() {} {} ttl {}", appid, id, ttlSeconds); } }
@Override public <T> void put(String appid, String id, T object, Long ttlSeconds) { if (ttlSeconds == null || ttlSeconds <= 0L) { put(appid, id, object); return; } if (!StringUtils.isBlank(id) && object != null && !StringUtils.isBlank(appid)) { String key = key(appid, id); cache.policy().expireVariably().ifPresent((t) -> { t.put(key, object, ttlSeconds, TimeUnit.SECONDS); }); logger.debug("Cache.put() {} {} ttl {}", appid, id, ttlSeconds); } }
/** * 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 write 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 * @throws IllegalArgumentException if {@code duration} is negative */ default void put(@Nonnull K key, @Nonnull V value, @Nonnull Duration duration) { // This method will be abstract in version 3.0.0 put(key, value, duration.toNanos(), 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 write 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 <tt>true</tt> if this cache did not already contain the specified entry * @throws IllegalArgumentException if {@code duration} is negative */ default boolean putIfAbsent(@Nonnull K key, @Nonnull V value, @Nonnull Duration duration) { // This method will be abstract in version 3.0.0 return putIfAbsent(key, value, duration.toNanos(), TimeUnit.NANOSECONDS); }
/** * 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 */ @Nonnull default Optional<Duration> getExpiresAfter(@Nonnull K key) { // This method will be abstract in version 3.0.0 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 * @throws IllegalArgumentException if {@code duration} is negative */ default void setExpiresAfter(@Nonnull K key, @Nonnull Duration duration) { // This method will be abstract in version 3.0.0 setExpiresAfter(key, duration.toNanos(), TimeUnit.NANOSECONDS); }
@CacheSpec(implementation = Implementation.Caffeine, expiryTime = Expire.ONE_MINUTE, population = Population.FULL, expiry = CacheExpiry.MOCKITO) @Test(dataProvider = "caches", expectedExceptions = ExpirationException.class) public void put_insert_replaceExpired_expiryFails(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireVariably) { OptionalLong duration = expireVariably.getExpiresAfter(context.firstKey(), NANOSECONDS); try { context.ticker().advance(1, TimeUnit.HOURS); when(context.expiry().expireAfterCreate(any(), any(), anyLong())) .thenThrow(ExpirationException.class); cache.put(context.firstKey(), context.absentValue()); } finally { context.ticker().advance(-1, TimeUnit.HOURS); assertThat(cache.asMap(), equalTo(context.original())); assertThat(expireVariably.getExpiresAfter(context.firstKey(), NANOSECONDS), is(duration)); } }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.MOCKITO, expiryTime = Expire.ONE_MINUTE) public void getExpiresAfter(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { assertThat(expireAfterVar.getExpiresAfter(context.absentKey(), TimeUnit.MINUTES), is(OptionalLong.empty())); assertThat(expireAfterVar.getExpiresAfter(context.firstKey(), TimeUnit.MINUTES), is(OptionalLong.of(1))); when(context.expiry().expireAfterUpdate(any(), any(), anyLong(), anyLong())) .thenReturn(TimeUnit.HOURS.toNanos(1)); cache.put(context.firstKey(), context.absentValue()); assertThat(expireAfterVar.getExpiresAfter(context.firstKey(), TimeUnit.MINUTES), is(OptionalLong.of(60))); assertThat(expireAfterVar.getExpiresAfter(context.lastKey(), TimeUnit.MINUTES), is(OptionalLong.of(1))); }
@CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.MOCKITO) @Test(dataProvider = "caches", expectedExceptions = ExpirationException.class) public void put_update_expiryFails(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireVariably) { OptionalLong duration = expireVariably.getExpiresAfter(context.firstKey(), NANOSECONDS); try { context.ticker().advance(1, TimeUnit.HOURS); when(context.expiry().expireAfterUpdate(any(), any(), anyLong(), anyLong())) .thenThrow(ExpirationException.class); cache.put(context.firstKey(), context.absentValue()); } finally { context.ticker().advance(-1, TimeUnit.HOURS); assertThat(cache.asMap(), equalTo(context.original())); assertThat(expireVariably.getExpiresAfter(context.firstKey(), NANOSECONDS), is(duration)); } }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.MOCKITO, expiryTime = Expire.ONE_MINUTE) public void setExpiresAfter(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { expireAfterVar.setExpiresAfter(context.firstKey(), 2, TimeUnit.MINUTES); assertThat(expireAfterVar.getExpiresAfter(context.firstKey(), TimeUnit.MINUTES), is(OptionalLong.of(2))); expireAfterVar.setExpiresAfter(context.absentKey(), 4, TimeUnit.MINUTES); assertThat(expireAfterVar.getExpiresAfter(context.absentKey(), TimeUnit.MINUTES), is(OptionalLong.empty())); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.WRITE, expiryTime = Expire.ONE_MINUTE) public void putIfAbsent_present(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { Integer key = context.firstKey(); Integer value = context.absentValue(); assertThat(expireAfterVar.putIfAbsent(key, value, Duration.ofMinutes(2L)), is(false)); assertThat(cache.getIfPresent(key), is(context.original().get(key))); assertThat(expireAfterVar.getExpiresAfter(key), is(Optional.of(Duration.ofMinutes(1L)))); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(0L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.WRITE, expiryTime = Expire.ONE_MINUTE) public void putIfAbsent_insert(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { Integer key = context.absentKey(); Integer value = context.absentValue(); assertThat(expireAfterVar.putIfAbsent(key, value, Duration.ofMinutes(2L)), is(true)); assertThat(cache.getIfPresent(key), is(value)); assertThat(expireAfterVar.getExpiresAfter(key), is(Optional.of(Duration.ofMinutes(2L)))); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(1L)); }
/** * 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 */ @NonNull default Optional<Duration> getExpiresAfter(@NonNull K key) { // This method will be abstract in version 3.0.0 OptionalLong duration = getExpiresAfter(key, TimeUnit.NANOSECONDS); return duration.isPresent() ? Optional.of(Duration.ofNanos(duration.getAsLong())) : Optional.empty(); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.WRITE, expiryTime = Expire.ONE_MINUTE) public void put_replace(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { Integer key = context.firstKey(); Integer value = context.absentValue(); expireAfterVar.put(key, value, Duration.ofMinutes(2L)); assertThat(cache.getIfPresent(key), is(value)); assertThat(expireAfterVar.getExpiresAfter(key), is(Optional.of(Duration.ofMinutes(2L)))); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.WRITE, expiryTime = Expire.ONE_MINUTE) public void put_insert(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { Integer key = context.absentKey(); Integer value = context.absentValue(); expireAfterVar.put(key, value, Duration.ofMinutes(2L)); assertThat(cache.getIfPresent(key), is(value)); assertThat(expireAfterVar.getExpiresAfter(key), is(Optional.of(Duration.ofMinutes(2L)))); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.MOCKITO, expiryTime = Expire.ONE_MINUTE) public void setExpiresAfter_duration(Cache<Integer, Integer> cache, CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { expireAfterVar.setExpiresAfter(context.firstKey(), Duration.ofMinutes(2L)); assertThat(expireAfterVar.getExpiresAfter(context.firstKey()), is(Optional.of(Duration.ofMinutes(2L)))); expireAfterVar.setExpiresAfter(context.absentKey(), Duration.ofMinutes(4L)); assertThat(expireAfterVar.getExpiresAfter(context.absentKey()), is(Optional.empty())); context.ticker().advance(90, TimeUnit.SECONDS); cache.cleanUp(); assertThat(cache.estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, population = Population.FULL, expiry = CacheExpiry.ACCESS) public void oldest_partial(CacheContext context, VarExpiration<Integer, Integer> expireAfterVar) { int count = (int) context.initialSize() / 2; assertThat(expireAfterVar.oldest(count).size(), is(count)); }