|
Java example source code file (CacheExpirationTest.java)
This example Java source code file (CacheExpirationTest.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The CacheExpirationTest.java Java example source code
/*
* Copyright (C) 2011 The Guava Authors
*
* 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.google.common.cache;
import static com.google.common.cache.TestingCacheLoaders.identityLoader;
import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import com.google.common.cache.TestingCacheLoaders.IdentityLoader;
import com.google.common.cache.TestingRemovalListeners.CountingRemovalListener;
import com.google.common.cache.TestingRemovalListeners.QueuingRemovalListener;
import com.google.common.collect.Iterators;
import com.google.common.testing.FakeTicker;
import com.google.common.util.concurrent.Callables;
import junit.framework.TestCase;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Tests relating to cache expiration: make sure entries expire at the right times, make sure
* expired entries don't show up, etc.
*
* @author mike nonemacher
*/
@SuppressWarnings("deprecation") // tests of deprecated method
public class CacheExpirationTest extends TestCase {
private static final long EXPIRING_TIME = 1000;
private static final int VALUE_PREFIX = 12345;
private static final String KEY_PREFIX = "key prefix:";
public void testExpiration_expireAfterWrite() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterWrite(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
checkExpiration(cache, loader, ticker, removalListener);
}
public void testExpiration_expireAfterAccess() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterAccess(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
checkExpiration(cache, loader, ticker, removalListener);
}
private void checkExpiration(LoadingCache<String, Integer> cache, WatchedCreatorLoader loader,
FakeTicker ticker, CountingRemovalListener<String, Integer> removalListener) {
for (int i = 0; i < 10; i++) {
assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i));
}
for (int i = 0; i < 10; i++) {
loader.reset();
assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i));
assertFalse("Creator should not have been called @#" + i, loader.wasCalled());
}
CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker);
assertEquals("Map must be empty by now", 0, cache.size());
assertEquals("Eviction notifications must be received", 10,
removalListener.getCount());
CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker);
// ensure that no new notifications are sent
assertEquals("Eviction notifications must be received", 10,
removalListener.getCount());
}
public void testExpiringGet_expireAfterWrite() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterWrite(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
runExpirationTest(cache, loader, ticker, removalListener);
}
public void testExpiringGet_expireAfterAccess() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterAccess(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
runExpirationTest(cache, loader, ticker, removalListener);
}
private void runExpirationTest(LoadingCache<String, Integer> cache, WatchedCreatorLoader loader,
FakeTicker ticker, CountingRemovalListener<String, Integer> removalListener) {
for (int i = 0; i < 10; i++) {
assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i));
}
for (int i = 0; i < 10; i++) {
loader.reset();
assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i));
assertFalse("Loader should NOT have been called @#" + i, loader.wasCalled());
}
// wait for entries to expire, but don't call expireEntries
ticker.advance(EXPIRING_TIME * 10, MILLISECONDS);
// add a single unexpired entry
cache.getUnchecked(KEY_PREFIX + 11);
// collections views shouldn't expose expired entries
assertEquals(1, Iterators.size(cache.asMap().entrySet().iterator()));
assertEquals(1, Iterators.size(cache.asMap().keySet().iterator()));
assertEquals(1, Iterators.size(cache.asMap().values().iterator()));
CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker);
for (int i = 0; i < 11; i++) {
assertFalse(cache.asMap().containsKey(KEY_PREFIX + i));
}
assertEquals(11, removalListener.getCount());
for (int i = 0; i < 10; i++) {
assertFalse(cache.asMap().containsKey(KEY_PREFIX + i));
loader.reset();
assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i));
assertTrue("Creator should have been called @#" + i, loader.wasCalled());
}
// expire new values we just created
CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker);
assertEquals("Eviction notifications must be received", 21,
removalListener.getCount());
CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker);
// ensure that no new notifications are sent
assertEquals("Eviction notifications must be received", 21,
removalListener.getCount());
}
public void testRemovalListener_expireAfterWrite() {
FakeTicker ticker = new FakeTicker();
final AtomicInteger evictionCount = new AtomicInteger();
final AtomicInteger applyCount = new AtomicInteger();
final AtomicInteger totalSum = new AtomicInteger();
RemovalListener<Integer, AtomicInteger> removalListener =
new RemovalListener<Integer, AtomicInteger>() {
@Override
public void onRemoval(RemovalNotification<Integer, AtomicInteger> notification) {
if (notification.wasEvicted()) {
evictionCount.incrementAndGet();
totalSum.addAndGet(notification.getValue().get());
}
}
};
CacheLoader<Integer, AtomicInteger> loader = new CacheLoader() {
@Override public AtomicInteger load(Integer key) {
applyCount.incrementAndGet();
return new AtomicInteger();
}
};
LoadingCache<Integer, AtomicInteger> cache = CacheBuilder.newBuilder()
.removalListener(removalListener)
.expireAfterWrite(10, MILLISECONDS)
.ticker(ticker)
.build(loader);
// Increment 100 times
for (int i = 0; i < 100; ++i) {
cache.getUnchecked(10).incrementAndGet();
ticker.advance(1, MILLISECONDS);
}
assertEquals(evictionCount.get() + 1, applyCount.get());
int remaining = cache.getUnchecked(10).get();
assertEquals(100, totalSum.get() + remaining);
}
public void testRemovalScheduler_expireAfterWrite() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterWrite(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME);
}
public void testRemovalScheduler_expireAfterAccess() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterAccess(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME);
}
public void testRemovalScheduler_expireAfterBoth() {
FakeTicker ticker = new FakeTicker();
CountingRemovalListener<String, Integer> removalListener = countingRemovalListener();
WatchedCreatorLoader loader = new WatchedCreatorLoader();
LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
.expireAfterAccess(EXPIRING_TIME, MILLISECONDS)
.expireAfterWrite(EXPIRING_TIME, MILLISECONDS)
.removalListener(removalListener)
.ticker(ticker)
.build(loader);
runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME);
}
public void testExpirationOrder_access() {
// test lru within a single segment
FakeTicker ticker = new FakeTicker();
IdentityLoader<Integer> loader = identityLoader();
LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.expireAfterAccess(11, MILLISECONDS)
.ticker(ticker)
.build(loader);
for (int i = 0; i < 10; i++) {
cache.getUnchecked(i);
ticker.advance(1, MILLISECONDS);
}
Set<Integer> keySet = cache.asMap().keySet();
assertThat(keySet).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// 0 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
// reorder
getAll(cache, asList(0, 1, 2));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(2, MILLISECONDS);
assertThat(keySet).containsExactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2);
// 3 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(4, 5, 6, 7, 8, 9, 0, 1, 2);
// reorder
getAll(cache, asList(5, 7, 9));
CacheTesting.drainRecencyQueues(cache);
assertThat(keySet).containsExactly(4, 6, 8, 0, 1, 2, 5, 7, 9);
// 4 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(6, 8, 0, 1, 2, 5, 7, 9);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(6, 8, 0, 1, 2, 5, 7, 9);
// 6 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(8, 0, 1, 2, 5, 7, 9);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(8, 0, 1, 2, 5, 7, 9);
// 8 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(0, 1, 2, 5, 7, 9);
}
public void testExpirationOrder_write() throws ExecutionException {
// test lru within a single segment
FakeTicker ticker = new FakeTicker();
IdentityLoader<Integer> loader = identityLoader();
LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.expireAfterWrite(11, MILLISECONDS)
.ticker(ticker)
.build(loader);
for (int i = 0; i < 10; i++) {
cache.getUnchecked(i);
ticker.advance(1, MILLISECONDS);
}
Set<Integer> keySet = cache.asMap().keySet();
assertThat(keySet).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// 0 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9);
// get doesn't stop 1 from expiring
getAll(cache, asList(0, 1, 2));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(2, 3, 4, 5, 6, 7, 8, 9, 0);
// get(K, Callable) doesn't stop 2 from expiring
cache.get(2, Callables.returning(-2));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(3, 4, 5, 6, 7, 8, 9, 0);
// asMap.put saves 3
cache.asMap().put(3, -3);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(4, 5, 6, 7, 8, 9, 0, 3);
// asMap.replace saves 4
cache.asMap().replace(4, -4);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(5, 6, 7, 8, 9, 0, 3, 4);
// 5 expires
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(6, 7, 8, 9, 0, 3, 4);
}
public void testExpirationOrder_writeAccess() throws ExecutionException {
// test lru within a single segment
FakeTicker ticker = new FakeTicker();
IdentityLoader<Integer> loader = identityLoader();
LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.expireAfterWrite(5, MILLISECONDS)
.expireAfterAccess(3, MILLISECONDS)
.ticker(ticker)
.build(loader);
for (int i = 0; i < 5; i++) {
cache.getUnchecked(i);
}
ticker.advance(1, MILLISECONDS);
for (int i = 5; i < 10; i++) {
cache.getUnchecked(i);
}
ticker.advance(1, MILLISECONDS);
Set<Integer> keySet = cache.asMap().keySet();
assertThat(keySet).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
// get saves 1, 3; 0, 2, 4 expire
getAll(cache, asList(1, 3));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(5, 6, 7, 8, 9, 1, 3);
// get saves 6, 8; 5, 7, 9 expire
getAll(cache, asList(6, 8));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(1, 3, 6, 8);
// get fails to save 1, put saves 3
cache.asMap().put(3, -3);
getAll(cache, asList(1));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(6, 8, 3);
// get(K, Callable) fails to save 8, replace saves 6
cache.asMap().replace(6, -6);
cache.get(8, Callables.returning(-8));
CacheTesting.drainRecencyQueues(cache);
ticker.advance(1, MILLISECONDS);
assertThat(keySet).containsExactly(3, 6);
}
public void testExpiration_invalidateAll() {
FakeTicker ticker = new FakeTicker();
QueuingRemovalListener<Integer, Integer> listener =
TestingRemovalListeners.queuingRemovalListener();
Cache<Integer, Integer> cache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.MINUTES)
.removalListener(listener)
.ticker(ticker)
.build();
cache.put(1, 1);
ticker.advance(10, TimeUnit.MINUTES);
cache.invalidateAll();
assertThat(listener.poll().getCause()).isEqualTo(RemovalCause.EXPIRED);
}
private void runRemovalScheduler(LoadingCache<String, Integer> cache,
CountingRemovalListener<String, Integer> removalListener,
WatchedCreatorLoader loader,
FakeTicker ticker, String keyPrefix, long ttl) {
int shift1 = 10 + VALUE_PREFIX;
loader.setValuePrefix(shift1);
// fill with initial data
for (int i = 0; i < 10; i++) {
assertEquals(Integer.valueOf(i + shift1), cache.getUnchecked(keyPrefix + i));
}
assertEquals(10, CacheTesting.expirationQueueSize(cache));
assertEquals(0, removalListener.getCount());
// wait, so that entries have just 10 ms to live
ticker.advance(ttl * 2 / 3, MILLISECONDS);
assertEquals(10, CacheTesting.expirationQueueSize(cache));
assertEquals(0, removalListener.getCount());
int shift2 = shift1 + 10;
loader.setValuePrefix(shift2);
// fill with new data - has to live for 20 ms more
for (int i = 0; i < 10; i++) {
cache.invalidate(keyPrefix + i);
assertEquals("key: " + keyPrefix + i,
Integer.valueOf(i + shift2), cache.getUnchecked(keyPrefix + i));
}
assertEquals(10, CacheTesting.expirationQueueSize(cache));
assertEquals(10, removalListener.getCount()); // these are the invalidated ones
// old timeouts must expire after this wait
ticker.advance(ttl * 2 / 3, MILLISECONDS);
assertEquals(10, CacheTesting.expirationQueueSize(cache));
assertEquals(10, removalListener.getCount());
// check that new values are still there - they still have 10 ms to live
for (int i = 0; i < 10; i++) {
loader.reset();
assertEquals(Integer.valueOf(i + shift2), cache.getUnchecked(keyPrefix + i));
assertFalse("Creator should NOT have been called @#" + i, loader.wasCalled());
}
assertEquals(10, removalListener.getCount());
}
private static void getAll(LoadingCache<Integer, Integer> cache, List keys) {
for (int i : keys) {
cache.getUnchecked(i);
}
}
private static class WatchedCreatorLoader extends CacheLoader<String, Integer> {
boolean wasCalled = false; // must be set in load()
String keyPrefix = KEY_PREFIX;
int valuePrefix = VALUE_PREFIX;
public WatchedCreatorLoader() {
}
public void reset() {
wasCalled = false;
}
public boolean wasCalled() {
return wasCalled;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public void setValuePrefix(int valuePrefix) {
this.valuePrefix = valuePrefix;
}
@Override public Integer load(String key) {
wasCalled = true;
return valuePrefix + Integer.parseInt(key.substring(keyPrefix.length()));
}
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java CacheExpirationTest.java source code file:
|