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 7564113966..a0f744aed0 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 @@ -38,7 +38,6 @@ import java.util.NoSuchElementException; import java.util.Random; import java.util.TreeMap; -import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.IntStream; @@ -76,7 +75,6 @@ public final class TimerWheelTest { @BeforeMethod public void beforeMethod() throws Exception { - Reset.setThreadLocalRandom(random.nextInt(), random.nextInt()); MockitoAnnotations.openMocks(this).close(); timerWheel = new TimerWheel<>(); } @@ -140,7 +138,6 @@ public void advance(long clock) { public void advance_overflow() { when(cache.evictEntry(captor.capture(), any(), anyLong())).thenReturn(true); - var timerWheel = new TimerWheel(); timerWheel.nanos = -TimeUnit.DAYS.toNanos(365) / 2; timerWheel.schedule(new Timer(timerWheel.nanos + SPANS[0])); @@ -150,11 +147,10 @@ public void advance_overflow() { @Test(dataProvider = "clock") public void advance_backwards(long clock) { - var timerWheel = new TimerWheel(); timerWheel.nanos = clock; for (int i = 0; i < 1_000; i++) { - long duration = ThreadLocalRandom.current().nextLong(TimeUnit.DAYS.toNanos(10)); + long duration = random.nextLong(TimeUnit.DAYS.toNanos(10)); timerWheel.schedule(new Timer(clock + duration)); } for (int i = 0; i < TimerWheel.BUCKETS.length; i++) { @@ -164,6 +160,31 @@ public void advance_backwards(long clock) { verifyNoInteractions(cache); } + @Test(dataProvider = "clock") + public void advance_reschedule(long clock) { + when(cache.evictEntry(captor.capture(), any(), anyLong())).thenReturn(true); + timerWheel.nanos = clock; + + var t15 = new Timer(clock + TimeUnit.SECONDS.toNanos(15)); + var t80 = new Timer(clock + TimeUnit.SECONDS.toNanos(80)); + timerWheel.schedule(t15); + timerWheel.schedule(t80); + + // discard T15, T80 in wheel[1] + timerWheel.advance(cache, clock + TimeUnit.SECONDS.toNanos(45)); + assertThat(captor.getAllValues()).containsExactly(t15); + assertThat(timerWheel).hasSize(1); + + // verify not discarded, T80 in wheel[0] + timerWheel.advance(cache, clock + TimeUnit.SECONDS.toNanos(70)); + assertThat(timerWheel).hasSize(1); + + // verify discarded T80 + timerWheel.advance(cache, clock + TimeUnit.SECONDS.toNanos(90)); + assertThat(captor.getAllValues()).containsExactly(t15, t80); + assertThat(timerWheel).isEmpty(); + } + @Test public void advance_exception() { doThrow(new IllegalArgumentException()) @@ -287,12 +308,12 @@ public Iterator providesSchedule() { @DataProvider(name = "fuzzySchedule") public Object[][] providesFuzzySchedule() { long[] times = new long[5_000]; - long clock = ThreadLocalRandom.current().nextLong(); + long clock = random.nextLong(); 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); + times[i] = random.nextLong(clock + 1, bound); } - long duration = ThreadLocalRandom.current().nextLong(clock + 1, bound); + long duration = random.nextLong(clock + 1, bound); return new Object[][] {{ clock, duration, times }}; } @@ -414,8 +435,8 @@ public Iterator providesCascade() { var args = new ArrayList(); for (int i = 1; i < SPANS.length - 1; i++) { long span = SPANS[i]; - long timeout = ThreadLocalRandom.current().nextLong(span + 1, 2 * span); - long duration = ThreadLocalRandom.current().nextLong(span + 1, timeout - 1); + long timeout = random.nextLong(span + 1, 2 * span); + long duration = random.nextLong(span + 1, timeout - 1); for (long clock : CLOCKS) { args.add(new Object[] { clock, duration, timeout, i}); } @@ -469,12 +490,11 @@ public void iterator_fixed(long clock) { @Test(invocationCount = 25) public void iterator_random() { - int range = ThreadLocalRandom.current().nextInt(0, 1000); - timerWheel.nanos = ThreadLocalRandom.current().nextLong( + int range = random.nextInt(0, 1000); + timerWheel.nanos = random.nextLong( TimeUnit.MILLISECONDS.toNanos(500), TimeUnit.DAYS.toNanos(7)); var input = IntStream.range(0, range).mapToLong(i -> { - return ThreadLocalRandom.current().nextLong( - TimeUnit.SECONDS.toNanos(1), TimeUnit.DAYS.toNanos(7)); + return random.nextLong(TimeUnit.SECONDS.toNanos(1), TimeUnit.DAYS.toNanos(7)); }).boxed().sorted().collect(toImmutableList()); for (long time : input) { timerWheel.schedule(new Timer(time)); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1da85ab283..b3b83e6ca0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,13 +2,13 @@ asm = "9.6" auto-value = "1.10.4" awaitility = "4.2.0" -bcel = "6.6.1" +bcel = "6.8.0" bnd = "6.4.0" bouncycastle = "1.70" cache2k = "2.6.1.Final" caffeine = "3.1.8" checker-framework = "3.41.0" -checkstyle = "10.12.5" +checkstyle = "10.12.6" coherence = "22.06.2" commons-collections4 = "4.4" commons-compress = "1.25.0" @@ -19,7 +19,7 @@ commons-text = "1.11.0" concurrentlinkedhashmap = "1.4.2" config = "1.4.3" coveralls = "2.12.2" -dependency-check = "9.0.3" +dependency-check = "9.0.4" eclipse-collections = "12.0.0.M3" ehcache3 = "3.10.8" errorprone-core = "2.23.0" @@ -82,7 +82,7 @@ snakeyaml = "2.2" sonarqube = "4.4.1.3373" spotbugs-contrib = "7.6.3" spotbugs-core = "4.8.2" -spotbugs-plugin = "6.0.1" +spotbugs-plugin = "6.0.2" stream = "2.9.8" tcache = "2.0.1" testng = "7.8.0" diff --git a/gradle/plugins/src/main/kotlin/analyze/object-layout-caffeine-conventions.gradle.kts b/gradle/plugins/src/main/kotlin/analyze/object-layout-caffeine-conventions.gradle.kts index 493e47a154..70f4738f47 100644 --- a/gradle/plugins/src/main/kotlin/analyze/object-layout-caffeine-conventions.gradle.kts +++ b/gradle/plugins/src/main/kotlin/analyze/object-layout-caffeine-conventions.gradle.kts @@ -5,6 +5,7 @@ plugins { val objectLayout: Configuration by configurations.creating dependencies { + objectLayout(project) objectLayout(libs.java.`object`.layout) } @@ -18,17 +19,17 @@ modes.forEach { (mode, details) -> tasks.register(mode) { group = "Object Layout" description = details + classpath(objectLayout) dependsOn(tasks.compileJava) mainClass = "org.openjdk.jol.Main" incompatibleWithConfigurationCache() - classpath(objectLayout, sourceSets.main.map { it.runtimeClasspath }) doFirst { var className = findProperty("className") as String? if (className == null) { throw GradleException( "Usage: $name -PclassName=com.github.benmanes.caffeine.cache.[CLASS_NAME]") - } else if (!className.startsWith("com")) { + } else if (!className.startsWith("com") && !className.startsWith("java")) { className = "com.github.benmanes.caffeine.cache.$className" } args(name, className) diff --git a/gradle/plugins/src/main/kotlin/quality/checkstyle-caffeine-conventions.gradle.kts b/gradle/plugins/src/main/kotlin/quality/checkstyle-caffeine-conventions.gradle.kts index 5e5ffc1b5a..dcbfbee400 100644 --- a/gradle/plugins/src/main/kotlin/quality/checkstyle-caffeine-conventions.gradle.kts +++ b/gradle/plugins/src/main/kotlin/quality/checkstyle-caffeine-conventions.gradle.kts @@ -4,6 +4,13 @@ plugins { val checkstyleConfig: Configuration by configurations.creating +configurations.checkstyle.configure { + resolutionStrategy.dependencySubstitution { + substitute(module("com.google.collections:google-collections")) + .using(module(libs.guava.asProvider().get().toString())) + } +} + dependencies { checkstyleConfig(libs.checkstyle) { isTransitive = false