Skip to content

Instantly share code, notes, and snippets.

@ksperling
Last active September 19, 2017 05:14
Show Gist options
  • Save ksperling/241c865526a2df9ad0dc9d02dac4393c to your computer and use it in GitHub Desktop.
Save ksperling/241c865526a2df9ad0dc9d02dac4393c to your computer and use it in GitHub Desktop.
package sandbox;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.github.benmanes.caffeine.cache.CacheWriter;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import org.junit.Test;
public class CaffeineEvictionTest {
private static class Value {
final int key;
boolean valid = true;
public Value(int key) {
this.key = key;
}
}
@Test
public void exercise() throws InterruptedException {
final int THREADS = 10, ITERATIONS = 100000, RANGE = 1000;
Lock[] locks = new Lock[RANGE];
for (int i=0; i<RANGE; i++) locks[i] = new ReentrantLock();
LoadingCache<Integer, Value> cache = Caffeine.newBuilder()
.maximumSize(RANGE / 10) // ensure plenty of evictions
.writer(new CacheWriter<Integer, Value>() {
@Override
public void write(Integer key, Value value) {
/* do nothing */
}
@Override
public void delete(Integer key, Value value, RemovalCause cause) {
Lock lock = locks[key];
lock.lock();
try {
value.valid = false;
} finally {
lock.unlock();
}
}
})
.build((k) -> new Value(k));
CountDownLatch latch = new CountDownLatch(THREADS);
AtomicInteger progress = new AtomicInteger();
AtomicReference<RuntimeException> failure = new AtomicReference<>();
for (int i=0; i<THREADS; i++) {
Random rnd = new Random(i);
new Thread(() -> {
try {
for (int j=0;j<ITERATIONS; j++) {
int key = rnd.nextInt(RANGE);
Lock lock = locks[key];
lock.lock();
try {
Value value = cache.get(key);
if (value.key != key) throw new IllegalStateException(String.format("cache.get(%d).key == %d", key, value.key));
else if (!value.valid) throw new IllegalStateException(String.format("cache.get(%d) invalid", key));
} finally {
lock.unlock();
}
int total = THREADS*ITERATIONS, done = progress.incrementAndGet();
if (done % (total / 10) == 0) System.err.printf("Test %d%% complete\n", done * 100 / total);
}
} catch (RuntimeException ex) {
failure.compareAndSet(null, new RuntimeException(Thread.currentThread().getName() + " failed", ex));
} finally {
latch.countDown();
}
}).start();
}
latch.await(30, TimeUnit.SECONDS);
RuntimeException ex = failure.get();
if (ex != null) throw ex;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment