From a8d2600061b9fd064a528881b159b3a73e530507 Mon Sep 17 00:00:00 2001 From: nivy Date: Thu, 18 Dec 2025 13:30:29 -0800 Subject: [PATCH 1/2] CASSANDRA-21087: Fix non-determinism of repair fuzz tests by passing randomizer to RetryStrategy --- .../apache/cassandra/config/RetrySpec.java | 7 +++- .../cassandra/service/RetryStrategyTest.java | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/java/org/apache/cassandra/config/RetrySpec.java b/src/java/org/apache/cassandra/config/RetrySpec.java index ff9b58f827ae..184e6a11c243 100644 --- a/src/java/org/apache/cassandra/config/RetrySpec.java +++ b/src/java/org/apache/cassandra/config/RetrySpec.java @@ -22,12 +22,15 @@ import javax.annotation.Nullable; +import accord.utils.RandomSource; import org.apache.cassandra.config.DurationSpec.LongMillisecondsBound; import org.apache.cassandra.repair.SharedContext; import org.apache.cassandra.service.RetryStrategy; import org.apache.cassandra.service.TimeoutStrategy.LatencySourceFactory; import org.apache.cassandra.service.WaitStrategy; +import static org.apache.cassandra.service.RetryStrategy.randomizers; + public class RetrySpec { public static class MaxAttempt @@ -161,7 +164,9 @@ public static WaitStrategy toStrategy(SharedContext ctx, RetrySpec spec) { if (!spec.isEnabled()) return WaitStrategy.None.INSTANCE; - return RetryStrategy.parse(spec.baseSleepTime.toMilliseconds() + "ms * 2^attempts <= " + spec.maxSleepTime.toMilliseconds() + "ms,retries=" + (spec.maxAttempts.value - 1), LatencySourceFactory.none()); + RandomSource randomSource = RandomSource.wrap(ctx.random().get()); + RetryStrategy.WaitRandomizer randomizer = randomizers(randomSource).uniform(); + return RetryStrategy.parse((int) (0.5 * spec.baseSleepTime.toMilliseconds()) + "ms * 2^attempts ... " + (int) (1.5 * spec.baseSleepTime.toMilliseconds()) + "ms * 2^attempts <= " + spec.maxSleepTime.toMilliseconds() + "ms,retries=" + (spec.maxAttempts.value - 1), LatencySourceFactory.none(), randomizer); } @Override diff --git a/test/unit/org/apache/cassandra/service/RetryStrategyTest.java b/test/unit/org/apache/cassandra/service/RetryStrategyTest.java index 26c3633a5b89..eeba28fc8e81 100644 --- a/test/unit/org/apache/cassandra/service/RetryStrategyTest.java +++ b/test/unit/org/apache/cassandra/service/RetryStrategyTest.java @@ -18,12 +18,19 @@ package org.apache.cassandra.service; +import java.util.Random; +import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; +import java.util.function.Supplier; import org.junit.Test; import accord.utils.Gen; import accord.utils.RandomTestRunner; +import org.apache.cassandra.config.DurationSpec; +import org.apache.cassandra.config.RetrySpec; +import org.apache.cassandra.repair.SharedContext; +import org.assertj.core.api.Assertions; public class RetryStrategyTest { @@ -64,6 +71,33 @@ public void fuzzParser() }); } + @Test + public void testSeededWaitRandomizer() + { + RetrySpec spec = new RetrySpec(new RetrySpec.MaxAttempt(10), + new DurationSpec.LongMillisecondsBound("200ms"), + new DurationSpec.LongMillisecondsBound("1000ms")); + long wait1 = RetrySpec.toStrategy(sharedContext(100), spec).computeWait(1, TimeUnit.MILLISECONDS); + long wait2 = RetrySpec.toStrategy(sharedContext(100), spec).computeWait(1, TimeUnit.MILLISECONDS); + long wait3 = RetrySpec.toStrategy(sharedContext(200), spec).computeWait(1, TimeUnit.MILLISECONDS); + Assertions.assertThat(wait1).isEqualTo(wait2); + Assertions.assertThat(wait1).isNotEqualTo(wait3); + } + + private static SharedContext sharedContext(long seed) + { + return new SharedContext.ForwardingSharedContext(SharedContext.Global.instance) + { + private final Random seededRandom = new Random(seed); + + @Override + public Supplier random() + { + return () -> seededRandom; + } + }; + } + private static class TestLatencySourceFactory implements TimeoutStrategy.LatencySourceFactory { From 5d1e3e14a4a2c5219caddecb26aa8dd28f4430e2 Mon Sep 17 00:00:00 2001 From: nivy Date: Thu, 8 Jan 2026 14:53:19 -0800 Subject: [PATCH 2/2] Fix style --- .../org/apache/cassandra/service/RetryStrategyTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/unit/org/apache/cassandra/service/RetryStrategyTest.java b/test/unit/org/apache/cassandra/service/RetryStrategyTest.java index eeba28fc8e81..ac3ec1abac37 100644 --- a/test/unit/org/apache/cassandra/service/RetryStrategyTest.java +++ b/test/unit/org/apache/cassandra/service/RetryStrategyTest.java @@ -72,7 +72,7 @@ public void fuzzParser() } @Test - public void testSeededWaitRandomizer() + public void seededWaitRandomizer() { RetrySpec spec = new RetrySpec(new RetrySpec.MaxAttempt(10), new DurationSpec.LongMillisecondsBound("200ms"), @@ -88,12 +88,10 @@ private static SharedContext sharedContext(long seed) { return new SharedContext.ForwardingSharedContext(SharedContext.Global.instance) { - private final Random seededRandom = new Random(seed); - @Override public Supplier random() { - return () -> seededRandom; + return () -> new Random(seed); } }; }