From 1d6fa59c78ad002cef0052331af22015691bf630 Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Sat, 20 May 2017 11:56:18 -0700 Subject: [PATCH] Fix calculation of JCache's access expiration (fixes #158) If the entry had been eternal then, on access, the current time was set to a duration with the unit of nanosecond instead of milliseconds. The JCache expiration time sometimes assumed wall-clock behavior and not nanoTime's. For writes there are still 3 magic values and those will be removed in the v3 JCache rewrite (to use Caffeine's variable expiration). Improved the documentation for Expiry. Unfortunately it would probably be best if the currentTime parameter was not provided. This was free as already obtained from the ticker, but that defaults to nanoTime and is not a wall-clock value. The main use cases for the parameter would be to calculate against an external resource's timestamp, but that must be done with a wall-clock resolution (System.currentTimeMillis). The focus on implementation details and writing docs late meant this API gaffe was overlooked, resulting in hinting towards an error prone usage. --- .../benmanes/caffeine/cache/Expiry.java | 22 ++++++- .../caffeine/cache/TimerWheelTest.java | 3 +- gradle/dependencies.gradle | 12 ++-- .../benmanes/caffeine/jcache/CacheProxy.java | 63 +++++++++--------- .../benmanes/caffeine/jcache/Expirable.java | 2 +- .../caffeine/jcache/AbstractJCacheTest.java | 6 +- .../jcache/event/EventTypeFilterTest.java | 2 +- .../jcache/expiry/JCacheAccessExpiryTest.java | 64 +++++++++++++------ .../expiry/JCacheCreationExpiryTest.java | 28 ++++---- .../jcache/expiry/JCacheUpdateExpiryTest.java | 2 +- 10 files changed, 121 insertions(+), 83 deletions(-) diff --git a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/Expiry.java b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/Expiry.java index 59c197d324..c939183644 100644 --- a/caffeine/src/main/java/com/github/benmanes/caffeine/cache/Expiry.java +++ b/caffeine/src/main/java/com/github/benmanes/caffeine/cache/Expiry.java @@ -15,6 +15,8 @@ */ package com.github.benmanes.caffeine.cache; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; /** @@ -30,19 +32,27 @@ public interface Expiry { * Specifies that the entry should be automatically removed from the cache once the duration has * elapsed after the entry's creation. To indicate no expiration an entry may be given an * excessively long period, such as {@code Long#MAX_VALUE}. + *

+ * Note: The {@code currentTime} is supplied by the configured {@link Ticker} and by + * default does not relate to system or wall-clock time. When calculating the duration based on a + * time stamp, the current time should be obtained independently. * * @param key the key represented by this entry * @param value the value represented by this entry * @param currentTime the current time, in nanoseconds * @return the length of time before the entry expires, in nanoseconds */ - long expireAfterCreate(K key, V value, long currentTime); + long expireAfterCreate(@Nonnull K key, @Nonnull V value, long currentTime); /** * Specifies that the entry should be automatically removed from the cache once the duration has * elapsed after the replacement of its value. To indicate no expiration an entry may be given an * excessively long period, such as {@code Long#MAX_VALUE}. The {@code currentDuration} may be * returned to not modify the expiration time. + *

+ * Note: The {@code currentTime} is supplied by the configured {@link Ticker} and by + * default does not relate to system or wall-clock time. When calculating the duration based on a + * time stamp, the current time should be obtained independently. * * @param key the key represented by this entry * @param value the value represented by this entry @@ -50,13 +60,18 @@ public interface Expiry { * @param currentDuration the current duration, in nanoseconds * @return the length of time before the entry expires, in nanoseconds */ - long expireAfterUpdate(K key, V value, long currentTime, long currentDuration); + long expireAfterUpdate(@Nonnull K key, @Nonnull V value, + long currentTime, @Nonnegative long currentDuration); /** * Specifies that the entry should be automatically removed from the cache once the duration has * elapsed after its last read. To indicate no expiration an entry may be given an excessively * long period, such as {@code Long#MAX_VALUE}. The {@code currentDuration} may be returned to not * modify the expiration time. + *

+ * Note: The {@code currentTime} is supplied by the configured {@link Ticker} and by + * default does not relate to system or wall-clock time. When calculating the duration based on a + * time stamp, the current time should be obtained independently. * * @param key the key represented by this entry * @param value the value represented by this entry @@ -64,5 +79,6 @@ public interface Expiry { * @param currentDuration the current duration, in nanoseconds * @return the length of time before the entry expires, in nanoseconds */ - long expireAfterRead(K key, V value, long currentTime, long currentDuration); + long expireAfterRead(@Nonnull K key, @Nonnull V value, + long currentTime, @Nonnegative long currentDuration); } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java index 2b101e1128..4b3b31c909 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java @@ -15,6 +15,7 @@ */ package com.github.benmanes.caffeine.cache; +import static com.github.benmanes.caffeine.cache.TimerWheel.SPANS; import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -118,7 +119,7 @@ public void schedule_fuzzy(long clock, long nanos, long[] times) { public Object[][] providesFuzzySchedule() { long[] times = new long[5_000]; long clock = ThreadLocalRandom.current().nextLong(); - long bound = clock + TimeUnit.DAYS.toNanos(10); + long bound = clock + TimeUnit.DAYS.toNanos(1) + SPANS[SPANS.length - 1]; for (int i = 0; i < times.length; i++) { times[i] = ThreadLocalRandom.current().nextLong(clock + 1, bound); } diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 2c15b5953d..4fdc6defda 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -26,14 +26,14 @@ ext { versions = [ akka: '2.5.1', - commons_compress: '1.13', + commons_compress: '1.14', commons_lang3: '3.5', config: '1.3.1', error_prone_annotations: '2.0.19', fastutil: '7.2.0', flip_tables: '1.0.2', guava: '21.0', - javapoet: '1.8.0', + javapoet: '1.9.0', jcache: '1.0.0', jsr305: '3.0.2', jsr330: '1', @@ -50,7 +50,7 @@ ext { jctools: '2.0.1', junit: '4.12', mockito: '2.8.9', - pax_exam: '4.10.0', + pax_exam: '4.11.0', testng: '6.11', truth: '0.24', ] @@ -69,10 +69,10 @@ ext { ohc: '0.6.1', rapidoid: '5.3.4', slf4j: '1.7.25', - tcache: '1.0.0', + tcache: '1.0.1', ] plugin_versions = [ - buildscan: '1.7', + buildscan: '1.7.1', buildscan_recipes: '0.2.0', checkstyle: '7.7', coveralls: '2.8.1', @@ -83,7 +83,7 @@ ext { huntbugs_plugin: '0.3.5', jacoco: '0.7.9', jmh: '0.3.1', - jmh_report: '0.1.0', + jmh_report: '0.2.0', nexus: '2.3.1', pmd: '5.6.1', semantic_versioning: '1.1.0', diff --git a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/CacheProxy.java b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/CacheProxy.java index 387744aa3c..0ef03245d7 100644 --- a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/CacheProxy.java +++ b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/CacheProxy.java @@ -16,6 +16,8 @@ package com.github.benmanes.caffeine.jcache; import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import java.util.ArrayList; import java.util.HashMap; @@ -34,7 +36,6 @@ import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import javax.annotation.Nullable; import javax.cache.Cache; @@ -275,7 +276,7 @@ private void loadAllAndReplaceExisting(Set keys) { private void loadAllAndKeepExisting(Set keys) { List keysToLoad = keys.stream() .filter(key -> !cache.asMap().containsKey(key)) - .collect(Collectors.toList()); + .collect(toList()); Map result = cacheLoader.get().loadAll(keysToLoad); for (Map.Entry entry : result.entrySet()) { if ((entry.getKey() != null) && (entry.getValue() != null)) { @@ -352,10 +353,8 @@ protected V putNoCopyOrAwait(K key, V value, boolean publishToWriter, int[] puts expirable = null; } boolean created = (expirable == null); - long expireTimeMS = expireTimeMS(created - ? expiry::getExpiryForCreation - : expiry::getExpiryForUpdate); - if (expireTimeMS < 0) { + long expireTimeMS = getWriteExpireTimeMS(created); + if (expireTimeMS == Long.MIN_VALUE) { expireTimeMS = expirable.getExpireTimeMS(); } if (expireTimeMS == 0) { @@ -441,7 +440,7 @@ private boolean putIfAbsentNoAwait(K key, V value, boolean publishToWriter) { } absent[0] = true; - long expireTimeMS = expireTimeMS(expiry::getExpiryForCreation); + long expireTimeMS = getWriteExpireTimeMS(/* created */ true); if (expireTimeMS == 0) { return null; } @@ -593,8 +592,8 @@ public boolean replace(K key, V oldValue, V newValue) { if (oldValue.equals(expirable.get())) { publishToCacheWriter(writer::write, () -> new EntryProxy<>(key, expirable.get())); dispatcher.publishUpdated(this, key, expirable.get(), copyOf(newValue)); - long expireTimeMS = expireTimeMS(expiry::getExpiryForUpdate); - if (expireTimeMS < 0) { + long expireTimeMS = getWriteExpireTimeMS(/* created */ false); + if (expireTimeMS == Long.MIN_VALUE) { expireTimeMS = expirable.getExpireTimeMS(); } result = new Expirable<>(newValue, expireTimeMS); @@ -686,8 +685,8 @@ private V replaceNoCopyOrAwait(K key, V value) { } publishToCacheWriter(writer::write, () -> new EntryProxy<>(key, value)); - long expireTimeMS = expireTimeMS(expiry::getExpiryForUpdate); - if (expireTimeMS < 0) { + long expireTimeMS = getWriteExpireTimeMS(/* created */ false); + if (expireTimeMS == Long.MIN_VALUE) { expireTimeMS = expirable.getExpireTimeMS(); } dispatcher.publishUpdated(this, key, expirable.get(), copy); @@ -810,10 +809,7 @@ private Expirable postProcess(Expirable expirable, } return expirable; case READ: { - long expireTimeMS = expireTimeMS(expiry::getExpiryForAccess); - if (expireTimeMS >= 0) { - expirable.setExpireTimeMS(expireTimeMS); - } + setAccessExpirationTime(expirable, 0L); return expirable; } case CREATED: @@ -822,13 +818,13 @@ private Expirable postProcess(Expirable expirable, case LOADED: statistics.recordPuts(1L); dispatcher.publishCreated(this, entry.getKey(), entry.getValue()); - return new Expirable<>(entry.getValue(), expireTimeMS(expiry::getExpiryForCreation)); + return new Expirable<>(entry.getValue(), getWriteExpireTimeMS(/* created */ true)); case UPDATED: { statistics.recordPuts(1L); publishToCacheWriter(writer::write, () -> entry); dispatcher.publishUpdated(this, entry.getKey(), expirable.get(), entry.getValue()); - long expireTimeMS = expireTimeMS(expiry::getExpiryForUpdate); - if (expireTimeMS < 0) { + long expireTimeMS = getWriteExpireTimeMS(/* created */ false); + if (expireTimeMS == Long.MIN_VALUE) { expireTimeMS = expirable.getExpireTimeMS(); } return new Expirable<>(entry.getValue(), expireTimeMS); @@ -966,12 +962,12 @@ private void publishToCacheWriter(Consumer action, Supplier data) { /** Writes all of the entries to the cache writer if write-through is enabled. */ private CacheWriterException writeAllToCacheWriter(Map map) { - if (!configuration.isWriteThrough() || map.isEmpty()) { + if (!configuration.isWriteThrough() || map.isEmpty()) { return null; } List> entries = map.entrySet().stream() .map(entry -> new EntryProxy<>(entry.getKey(), entry.getValue())) - .collect(Collectors.toList()); + .collect(toList()); try { writer.writeAll(entries); return null; @@ -1038,11 +1034,11 @@ protected final void requireNotClosed() { * Returns a deep copy of the map if value-based caching is enabled. * * @param map the mapping of keys to expirable values - * @return a copy of the mappings if storing by value or the same instance if by reference + * @return a deep or shallow copy of the mappings depending on the store by value setting */ protected final Map copyMap(Map> map) { ClassLoader classLoader = cacheManager.getClassLoader(); - return map.entrySet().stream().collect(Collectors.toMap( + return map.entrySet().stream().collect(toMap( entry -> copier.copy(entry.getKey(), classLoader), entry -> copier.copy(entry.getValue().get(), classLoader))); } @@ -1073,8 +1069,8 @@ protected final void setAccessExpirationTime(Expirable expirable, long curren } else if (duration.isEternal()) { expirable.setExpireTimeMS(Long.MAX_VALUE); } else { - if (currentTimeMS == 0) { - currentTimeMS = ticker.read(); + if (currentTimeMS == 0L) { + currentTimeMS = currentTimeMillis(); } long expireTimeMS = duration.getAdjustedTime(currentTimeMS); expirable.setExpireTimeMS(expireTimeMS); @@ -1085,30 +1081,31 @@ protected final void setAccessExpirationTime(Expirable expirable, long curren } /** - * Returns the time when the entry will expire based on the supplied expiration function. + * Returns the time when the entry will expire. * - * @param expires the expiration function - * @return the time when the entry will expire, or negative if the time should not be changed + * @param created if the write is an insert or update + * @return the time when the entry will expire, zero if it should expire immediately, + * Long.MIN_VALUE if it should not be changed, or Long.MAX_VALUE if eternal */ - protected final long expireTimeMS(Supplier expires) { + protected final long getWriteExpireTimeMS(boolean created) { try { - Duration duration = expires.get(); + Duration duration = created ? expiry.getExpiryForCreation() : expiry.getExpiryForUpdate(); if (duration == null) { - return -1; + return Long.MIN_VALUE; } else if (duration.isZero()) { - return 0; + return 0L; } else if (duration.isEternal()) { return Long.MAX_VALUE; } return duration.getAdjustedTime(currentTimeMillis()); } catch (Exception e) { logger.log(Level.WARNING, "Failed to get the policy's expiration time", e); - return -1; + return Long.MIN_VALUE; } } /** An iterator to safely expose the cache entries. */ - private final class EntryIterator implements Iterator> { + final class EntryIterator implements Iterator> { final Iterator>> delegate = cache.asMap().entrySet().iterator(); Map.Entry> current; Map.Entry> cursor; diff --git a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/Expirable.java b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/Expirable.java index 5ca7a40279..fe9ab6b925 100644 --- a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/Expirable.java +++ b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/Expirable.java @@ -49,7 +49,7 @@ public void setExpireTimeMS(long expireTimeMS) { /** Returns if the value has expired and is eligible for eviction. */ public boolean hasExpired(long currentTimeMS) { - return (expireTimeMS <= currentTimeMS); + return (currentTimeMS - expireTimeMS) >= 0; } /** Returns if the value will never expire. */ diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/AbstractJCacheTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/AbstractJCacheTest.java index 6932eea0a6..8f6721f563 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/AbstractJCacheTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/AbstractJCacheTest.java @@ -44,6 +44,7 @@ */ @Test(singleThreaded = true) public abstract class AbstractJCacheTest { + protected static final long START_TIME_MS = System.currentTimeMillis(); protected static final long EXPIRY_DURATION = TimeUnit.MINUTES.toMillis(1); protected static final Integer KEY_1 = 1, VALUE_1 = -1; @@ -68,7 +69,7 @@ public void beforeClass() { @BeforeMethod(alwaysRun = true) public void before() { - ticker = new FakeTicker(); + ticker = new FakeTicker().advance(START_TIME_MS, TimeUnit.MILLISECONDS); jcache = (CacheProxy) cacheManager.createCache("jcache", getConfiguration()); jcacheLoading = (LoadingCacheProxy) cacheManager.createCache( "jcacheLoading", getLoadingConfiguration()); @@ -86,7 +87,8 @@ public void after() { /* ---------------- Utility methods ------------- */ @Nullable - protected static Expirable getExpirable(CacheProxy cache, Integer key) { + protected static Expirable getExpirable( + CacheProxy cache, Integer key) { return cache.cache.getIfPresent(key); } diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/event/EventTypeFilterTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/event/EventTypeFilterTest.java index e783249fe2..599792c0b4 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/event/EventTypeFilterTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/event/EventTypeFilterTest.java @@ -53,6 +53,6 @@ public void equals() { @Test public void hash() { - filter.hashCode(); + assertThat(filter.hashCode(), is(filter.hashCode())); } } diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheAccessExpiryTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheAccessExpiryTest.java index 87d9fa8829..de5acc91e6 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheAccessExpiryTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheAccessExpiryTest.java @@ -31,6 +31,7 @@ import javax.cache.processor.EntryProcessorResult; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.github.benmanes.caffeine.jcache.AbstractJCacheTest; @@ -72,6 +73,11 @@ protected CaffeineConfiguration getConfiguration() { return configuration; } + @DataProvider(name = "eternal") + public Object[] providesEternal() { + return new Object[] { true, false }; + } + /* ---------------- get -------------- */ @Test @@ -83,12 +89,15 @@ public void get_absent() { assertThat(getExpirable(jcache, KEY_1), is(nullValue())); } - @Test - public void get_present() { - assertThat(jcache.get(KEY_1), is(VALUE_1)); - + @Test(dataProvider = "eternal") + public void get_present(boolean eternal) { Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + if (eternal) { + expirable.setExpireTimeMS(Long.MAX_VALUE); + } + + assertThat(jcache.get(KEY_1), is(VALUE_1)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } /* ---------------- get (loading) -------------- */ @@ -104,12 +113,15 @@ public void get_loading_absent() { assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } - @Test - public void get_loading_present() { - assertThat(jcacheLoading.get(KEY_1), is(VALUE_1)); - + @Test(dataProvider = "eternal") + public void get_loading_present(boolean eternal) { Expirable expirable = getExpirable(jcacheLoading, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + if (eternal) { + expirable.setExpireTimeMS(Long.MAX_VALUE); + } + + assertThat(jcacheLoading.get(KEY_1), is(VALUE_1)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } /* ---------------- getAllPresent -------------- */ @@ -126,13 +138,20 @@ public void getAll_absent() { } } - @Test - public void getAll_present() { + @Test(dataProvider = "eternal") + public void getAll_present(boolean eternal) { + for (Integer key : keys) { + Expirable expirable = getExpirable(jcacheLoading, key); + if (eternal) { + expirable.setExpireTimeMS(Long.MAX_VALUE); + } + } + assertThat(jcache.getAll(keys), is(entries)); for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } } @@ -148,12 +167,15 @@ public void invoke_absent() { assertThat(getExpirable(jcache, KEY_1), is(nullValue())); } - @Test - public void invoke_present() { - assertThat(jcache.invoke(KEY_1, (entry, args) -> entry.getValue()), is(VALUE_1)); - + @Test(dataProvider = "eternal") + public void invoke_present(boolean eternal) { Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + if (eternal) { + expirable.setExpireTimeMS(Long.MAX_VALUE); + } + + assertThat(jcache.invoke(KEY_1, (entry, args) -> entry.getValue()), is(VALUE_1)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } /* ---------------- invokeAll -------------- */ @@ -180,7 +202,7 @@ public void invokeAll_present() { for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } } @@ -191,7 +213,7 @@ public void removeConditionally() { assertThat(jcache.remove(KEY_1, VALUE_2), is(false)); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } /* ---------------- conditional replace -------------- */ @@ -201,6 +223,6 @@ public void replaceConditionally() { assertThat(jcache.replace(KEY_1, VALUE_2, VALUE_3), is(false)); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } } diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheCreationExpiryTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheCreationExpiryTest.java index eec055e4d6..59c1cb1db3 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheCreationExpiryTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheCreationExpiryTest.java @@ -66,7 +66,7 @@ protected CaffeineConfiguration getConfiguration() { public void get_loading_absent() { assertThat(jcacheLoading.get(KEY_1), is(KEY_1)); Expirable expirable = getExpirable(jcacheLoading, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } @Test @@ -86,7 +86,7 @@ public void get_loading_present() { assertThat(jcacheLoading.get(KEY_1), is(VALUE_1)); Expirable expirable = getExpirable(jcacheLoading, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } /* ---------------- getAndPut -------------- */ @@ -96,7 +96,7 @@ public void getAndPut_absent() { assertThat(jcache.getAndPut(KEY_1, VALUE_1), is(nullValue())); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } @Test @@ -116,7 +116,7 @@ public void getAndPut_present() { assertThat(jcache.getAndPut(KEY_1, VALUE_2), is(VALUE_1)); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } /* ---------------- put -------------- */ @@ -126,7 +126,7 @@ public void put_absent() { jcache.put(KEY_1, VALUE_1); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } @Test @@ -146,7 +146,7 @@ public void put_present() { jcache.put(KEY_1, VALUE_2); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } /* ---------------- putAll -------------- */ @@ -157,7 +157,7 @@ public void putAll_absent() { for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } } @@ -181,7 +181,7 @@ public void putAll_present() { jcache.putAll(entries); for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } } @@ -192,7 +192,7 @@ public void putIfAbsent_absent() { jcache.putIfAbsent(KEY_1, VALUE_1); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } @Test @@ -212,7 +212,7 @@ public void putIfAbsent_present() { jcache.putIfAbsent(KEY_1, VALUE_2); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } /* ---------------- invoke -------------- */ @@ -225,7 +225,7 @@ public void invoke_absent() { }), is(nullValue())); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } @Test @@ -253,7 +253,7 @@ public void invoke_present() { }), is(nullValue())); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } /* ---------------- invokeAll -------------- */ @@ -267,7 +267,7 @@ public void invokeAll_absent() { for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(currentTimeMillis() + EXPIRY_DURATION)); } } @@ -299,7 +299,7 @@ public void invokeAll_present() { for (Integer key : keys) { Expirable expirable = getExpirable(jcache, key); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } } } diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheUpdateExpiryTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheUpdateExpiryTest.java index 1a9f23c993..34c3991610 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheUpdateExpiryTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/expiry/JCacheUpdateExpiryTest.java @@ -129,7 +129,7 @@ public void replaceConditionally_failed() { assertThat(jcache.replace(KEY_1, VALUE_2, VALUE_3), is(false)); Expirable expirable = getExpirable(jcache, KEY_1); - assertThat(expirable.getExpireTimeMS(), is(EXPIRY_DURATION)); + assertThat(expirable.getExpireTimeMS(), is(START_TIME_MS + EXPIRY_DURATION)); } @Test