@Test(dataProvider = "caches") @CacheSpec(population = { Population.SINGLETON, Population.PARTIAL, Population.FULL }) public void put_replace(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { CompletableFuture<Integer> value = CompletableFuture.completedFuture(context.absentValue()); for (Integer key : context.firstMiddleLastKeys()) { cache.put(key, value); assertThat(cache.get(key), is(futureOf(context.absentValue()))); } assertThat(cache.synchronous().estimatedSize(), is(context.initialSize())); int count = context.firstMiddleLastKeys().size(); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.REPLACED)); }
@Test(dataProvider = "caches") @CacheSpec(keys = ReferenceType.WEAK, values = ReferenceType.STRONG, expireAfterAccess = Expire.DISABLED, expireAfterWrite = Expire.DISABLED, maximumSize = Maximum.DISABLED, weigher = CacheWeigher.DEFAULT, population = Population.FULL, stats = Stats.ENABLED, removalListener = Listener.CONSUMING) public void put(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { Integer key = context.absentKey(); context.clear(); GcFinalization.awaitFullGc(); cache.put(key, CompletableFuture.completedFuture(context.absentValue())); long count = context.initialSize(); assertThat(cache.synchronous().estimatedSize(), is(1L)); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.COLLECTED)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, maximumSize = Maximum.FULL, weigher = CacheWeigher.COLLECTION, population = Population.EMPTY, keys = ReferenceType.STRONG, values = ReferenceType.STRONG) @SuppressWarnings("FutureReturnValueIgnored") public void put_asyncWeight(AsyncLoadingCache<Integer, List<Integer>> cache, CacheContext context, Eviction<?, ?> eviction) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<List<Integer>> valueFuture = CompletableFuture.supplyAsync(() -> { Awaits.await().untilTrue(ready); return ImmutableList.of(1, 2, 3, 4, 5); }); valueFuture.whenComplete((r, e) -> done.set(true)); cache.put(context.absentKey(), valueFuture); assertThat(eviction.weightedSize().getAsLong(), is(0L)); assertThat(cache.synchronous().estimatedSize(), is(1L)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> eviction.weightedSize().getAsLong(), is(5L)); Awaits.await().until(() -> cache.synchronous().estimatedSize(), is(1L)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, maximumSize = Maximum.TEN, weigher = CacheWeigher.VALUE, population = Population.EMPTY, keys = ReferenceType.STRONG, values = ReferenceType.STRONG, removalListener = Listener.CONSUMING) @SuppressWarnings("FutureReturnValueIgnored") public void evict_weighted_async(AsyncLoadingCache<Integer, Integer> cache, CacheContext context, Eviction<?, ?> eviction) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<Integer> valueFuture = CompletableFuture.supplyAsync(() -> { Awaits.await().untilTrue(ready); return 6; }); valueFuture.whenComplete((r, e) -> done.set(true)); cache.put(5, CompletableFuture.completedFuture(5)); cache.put(4, CompletableFuture.completedFuture(4)); cache.put(6, valueFuture); assertThat(eviction.weightedSize().getAsLong(), is(9L)); assertThat(cache.synchronous().estimatedSize(), is(3L)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(context::consumedNotifications, hasSize(1)); Awaits.await().until(() -> cache.synchronous().estimatedSize(), is(2L)); Awaits.await().until(() -> eviction.weightedSize().getAsLong(), is(10L)); assertThat(context, hasEvictionWeight(5L)); assertThat(context, hasRemovalNotifications(context, 1, RemovalCause.SIZE)); verifyWriter(context, (verifier, writer) -> verifier.deletions(1, RemovalCause.SIZE)); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.FULL, mustExpireWithAnyOf = { AFTER_ACCESS, AFTER_WRITE, VARIABLE }, expiry = { CacheExpiry.DISABLED, CacheExpiry.CREATE, CacheExpiry.WRITE, CacheExpiry.ACCESS }, expireAfterAccess = {Expire.DISABLED, Expire.ONE_MINUTE}, expiryTime = Expire.ONE_MINUTE, expireAfterWrite = {Expire.DISABLED, Expire.ONE_MINUTE}) public void put_insert(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { context.ticker().advance(1, TimeUnit.MINUTES); cache.put(context.firstKey(), CompletableFuture.completedFuture(context.absentValue())); runVariableExpiration(context); long count = context.initialSize(); assertThat(cache.synchronous().estimatedSize(), is(1L)); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.EXPIRED)); }
@Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, maximumSize = Maximum.ZERO, weigher = CacheWeigher.COLLECTION, population = Population.EMPTY, keys = ReferenceType.STRONG, values = ReferenceType.STRONG) @SuppressWarnings("FutureReturnValueIgnored") public void evict_zero_async(AsyncLoadingCache<Integer, List<Integer>> cache, CacheContext context, Eviction<?, ?> eviction) { AtomicBoolean ready = new AtomicBoolean(); AtomicBoolean done = new AtomicBoolean(); CompletableFuture<List<Integer>> valueFuture = CompletableFuture.supplyAsync(() -> { Awaits.await().untilTrue(ready); return ImmutableList.of(1, 2, 3, 4, 5); }); valueFuture.whenComplete((r, e) -> done.set(true)); cache.put(context.absentKey(), valueFuture); assertThat(eviction.weightedSize().getAsLong(), is(0L)); assertThat(cache.synchronous().estimatedSize(), is(1L)); ready.set(true); Awaits.await().untilTrue(done); Awaits.await().until(() -> eviction.weightedSize().getAsLong(), is(0L)); Awaits.await().until(() -> cache.synchronous().estimatedSize(), is(0L)); assertThat(context, hasRemovalNotifications(context, 1, RemovalCause.SIZE)); verifyWriter(context, (verifier, writer) -> verifier.deletions(1, RemovalCause.SIZE)); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.FULL, expiryTime = Expire.ONE_MINUTE, expiry = CacheExpiry.CREATE) public void put_replace(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { CompletableFuture<Integer> future = CompletableFuture.completedFuture(context.absentValue()); context.ticker().advance(30, TimeUnit.SECONDS); cache.put(context.firstKey(), future); cache.put(context.absentKey(), future); context.consumedNotifications().clear(); // Ignore replacement notification context.ticker().advance(45, TimeUnit.SECONDS); assertThat(cache.getIfPresent(context.firstKey()), is(nullValue())); assertThat(cache.getIfPresent(context.middleKey()), is(nullValue())); assertThat(cache.getIfPresent(context.absentKey()), is(futureOf(context.absentValue()))); assertThat(cache.synchronous().estimatedSize(), is(1L)); long count = context.initialSize(); assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.EXPIRED)); verifyWriter(context, (verifier, writer) -> verifier.deletions(count, RemovalCause.EXPIRED)); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.FULL, expiryTime = Expire.ONE_MINUTE, mustExpireWithAnyOf = { AFTER_ACCESS, AFTER_WRITE, VARIABLE }, expiry = { CacheExpiry.DISABLED, CacheExpiry.WRITE, CacheExpiry.ACCESS }, expireAfterAccess = {Expire.DISABLED, Expire.ONE_MINUTE}, expireAfterWrite = {Expire.DISABLED, Expire.ONE_MINUTE}) public void put_replace(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { CompletableFuture<Integer> future = CompletableFuture.completedFuture(context.absentValue()); context.ticker().advance(30, TimeUnit.SECONDS); cache.put(context.firstKey(), future); cache.put(context.absentKey(), future); context.consumedNotifications().clear(); // Ignore replacement notification context.ticker().advance(45, TimeUnit.SECONDS); assertThat(cache.getIfPresent(context.firstKey()), is(futureOf(context.absentValue()))); assertThat(cache.getIfPresent(context.absentKey()), is(futureOf(context.absentValue()))); assertThat(cache.getIfPresent(context.middleKey()), is(nullValue())); assertThat(cache.synchronous().estimatedSize(), is(2L)); long count = context.initialSize() - 1; assertThat(cache, hasRemovalNotifications(context, count, RemovalCause.EXPIRED)); verifyWriter(context, (verifier, writer) -> verifier.deletions(count, RemovalCause.EXPIRED)); }
@Test(dataProvider = "caches") @CacheSpec(population = Population.EMPTY, removalListener = Listener.CONSUMING, mustExpireWithAnyOf = { AFTER_ACCESS, AFTER_WRITE, VARIABLE }, expiry = { CacheExpiry.DISABLED, CacheExpiry.CREATE, CacheExpiry.WRITE, CacheExpiry.ACCESS }, expireAfterAccess = {Expire.DISABLED, Expire.ONE_MINUTE}, expiryTime = Expire.ONE_MINUTE, expireAfterWrite = {Expire.DISABLED, Expire.ONE_MINUTE}) @SuppressWarnings("FutureReturnValueIgnored") public void put_insert_async(AsyncLoadingCache<Integer, Integer> cache, CacheContext context) { CompletableFuture<Integer> future = new CompletableFuture<Integer>(); cache.put(context.absentKey(), future); context.ticker().advance(2, TimeUnit.MINUTES); cache.synchronous().cleanUp(); assertThat(cache, hasRemovalNotifications(context, 0, RemovalCause.EXPIRED)); future.complete(context.absentValue()); context.ticker().advance(30, TimeUnit.SECONDS); assertThat(cache.getIfPresent(context.absentKey()), is(future)); context.ticker().advance(1, TimeUnit.MINUTES); assertThat(cache.getIfPresent(context.absentKey()), is(nullValue())); cache.synchronous().cleanUp(); assertThat(cache, hasRemovalNotifications(context, 1, RemovalCause.EXPIRED)); verifyWriter(context, (verifier, writer) -> verifier.deletions(1, RemovalCause.EXPIRED)); }
@Override public CompletableFuture<Void> write(String raw, UserAgentIngredients ingredients) { return CompletableFuture.runAsync(() -> caffeine.put(raw, CompletableFuture.completedFuture(ingredients))); }
@Override public void put(final K key, final V value) { requireNonNull(key); requireNonNull(value); // non-blocking. // synchronousCacheView.put has same implementation with extra null check on value. asyncLoadingCache.put(key, CompletableFuture.completedFuture(value)); }
private Caching<ImmutableSubjectData> clearListener(final String name) { Caching<ImmutableSubjectData> ret = newData -> { cache.get().put(name, CompletableFuture.completedFuture(newData)); listeners.call(name, newData); }; cacheHolders.put(name, ret); return ret; }