From ac8e0491a9df75590c315063dbf1800e18a775d3 Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Fri, 26 Aug 2022 19:11:31 -0700 Subject: [PATCH] add test for overflow of the ring buffer read/write counters --- .../caffeine/cache/BoundedBufferTest.java | 34 ++++++++++++++----- .../caffeine/cache/BoundedLocalCacheTest.java | 4 +-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedBufferTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedBufferTest.java index a1e790bdb5..d7601684d4 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedBufferTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedBufferTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; +import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -31,18 +32,17 @@ * @author ben.manes@gmail.com (Ben Manes) */ public final class BoundedBufferTest { - static final String DUMMY = "test"; @DataProvider public Object[][] buffer() { - return new Object[][] {{ new BoundedBuffer() }}; + return new Object[][] {{ new BoundedBuffer() }}; } @Test(dataProvider = "buffer") - public void offer(BoundedBuffer buffer) { + public void offer(BoundedBuffer buffer) { ConcurrentTestHarness.timeTasks(10, () -> { for (int i = 0; i < 100; i++) { - buffer.offer(DUMMY); + buffer.offer(Boolean.TRUE); } }); assertThat(buffer.writes()).isGreaterThan(0); @@ -50,9 +50,9 @@ public void offer(BoundedBuffer buffer) { } @Test(dataProvider = "buffer") - public void drain(BoundedBuffer buffer) { + public void drain(BoundedBuffer buffer) { for (int i = 0; i < BoundedBuffer.BUFFER_SIZE; i++) { - buffer.offer(DUMMY); + buffer.offer(Boolean.TRUE); } long[] read = new long[1]; buffer.drainTo(e -> read[0]++); @@ -62,12 +62,12 @@ public void drain(BoundedBuffer buffer) { @Test(dataProvider = "buffer") @SuppressWarnings("ThreadPriorityCheck") - public void offerAndDrain(BoundedBuffer buffer) { + public void offerAndDrain(BoundedBuffer buffer) { var lock = new ReentrantLock(); var reads = new AtomicInteger(); ConcurrentTestHarness.timeTasks(10, () -> { for (int i = 0; i < 1000; i++) { - boolean shouldDrain = (buffer.offer(DUMMY) == Buffer.FULL); + boolean shouldDrain = (buffer.offer(Boolean.TRUE) == Buffer.FULL); if (shouldDrain && lock.tryLock()) { buffer.drainTo(e -> reads.incrementAndGet()); lock.unlock(); @@ -79,4 +79,22 @@ public void offerAndDrain(BoundedBuffer buffer) { assertThat(reads.longValue()).isEqualTo(buffer.reads()); assertThat(reads.longValue()).isEqualTo(buffer.writes()); } + + @Test + public void overflow() { + var buffer = new BoundedBuffer.RingBuffer(null); + buffer.writeCounter = Long.MAX_VALUE; + buffer.readCounter = Long.MAX_VALUE; + + buffer.offer(Boolean.TRUE); + var data = new ArrayList<>(); + buffer.drainTo(data::add); + + for (var e : buffer.buffer) { + assertThat(e).isNull(); + } + assertThat(data).containsExactly(Boolean.TRUE); + assertThat(buffer.readCounter).isEqualTo(Long.MIN_VALUE); + assertThat(buffer.writeCounter).isEqualTo(Long.MIN_VALUE); + } } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedLocalCacheTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedLocalCacheTest.java index ada8f5ed14..59353c3125 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedLocalCacheTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/BoundedLocalCacheTest.java @@ -687,7 +687,7 @@ public void evict_admit(BoundedLocalCache cache, CacheContext context) assertThat(cache.admit(candidate, victim)).isFalse(); } - // Allow + // Admit a small, random percentage of warm candidates to protect against hash flooding while (cache.frequencySketch().frequency(candidate) < ADMIT_HASHDOS_THRESHOLD) { cache.frequencySketch().increment(candidate); } @@ -701,8 +701,8 @@ public void evict_admit(BoundedLocalCache cache, CacheContext context) } } assertThat(allow).isGreaterThan(0); - assertThat(reject).isGreaterThan(0); assertThat(reject).isGreaterThan(allow); + assertThat(100.0 * allow / (allow + reject)).isIn(Range.open(0.5, 1.5)); } @Test(groups = "isolated")