This is an automated email from the ASF dual-hosted git repository. maedhroz pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit 87d79f30a0f42bd3b3105145376450eb7b47a073 Merge: cdb67f62ff ddfba19f9e Author: Caleb Rackliffe <[email protected]> AuthorDate: Wed Mar 11 16:06:29 2026 -0500 Merge branch 'cassandra-5.0' into trunk * cassandra-5.0: Randomize Memtable type/allocation type and SSTable format in Simulator tests .../config/CassandraRelevantProperties.java | 2 +- .../cassandra/simulator/ClusterSimulation.java | 117 ++++++++++++++++++++- .../systems/SimulatedFutureActionScheduler.java | 7 ++ .../simulator/test/ShortPaxosSimulationTest.java | 8 +- .../simulator/test/SimulationTestBase.java | 71 ++++++++++--- .../simulator/test/TrivialSimulationTest.java | 9 +- 6 files changed, 189 insertions(+), 25 deletions(-) diff --cc src/java/org/apache/cassandra/config/CassandraRelevantProperties.java index 9184b78395,0c81d63afb..05875726e3 --- a/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java +++ b/src/java/org/apache/cassandra/config/CassandraRelevantProperties.java @@@ -528,11 -480,8 +528,12 @@@ public enum CassandraRelevantPropertie SERIALIZATION_EMPTY_TYPE_NONEMPTY_BEHAVIOR("cassandra.serialization.emptytype.nonempty_behavior"), SET_SEP_THREAD_NAME("cassandra.set_sep_thread_name", "true"), SHUTDOWN_ANNOUNCE_DELAY_IN_MS("cassandra.shutdown_announce_in_ms", "2000"), + SIMULATOR_ITERATIONS("simulator.iterations", "3"), + SIMULATOR_SEED("cassandra.simulator.seed"), + SIMULATOR_STARTED("cassandra.simulator.started"), SIZE_RECORDER_INTERVAL("cassandra.size_recorder_interval", "300"), + SKIP_AUTH_SETUP("cassandra.skip_auth_setup", "false"), + SKIP_GC_INSPECTOR("cassandra.skip_gc_inspector", "false"), /** * Do not try to calculate optimal streaming candidates. This can take a lot of time in some configs specially @@@ -559,7 -502,7 +560,6 @@@ SNAPSHOT_MIN_ALLOWED_TTL_SECONDS("cassandra.snapshot.min_allowed_ttl_seconds", "60"), SSL_ENABLE("ssl.enable"), SSL_STORAGE_PORT("cassandra.ssl_storage_port"), -- SSTABLE_FORMAT_DEFAULT("cassandra.sstable.format.default"), START_GOSSIP("cassandra.start_gossip", "true"), START_NATIVE_TRANSPORT("cassandra.start_native_transport"), STORAGE_DIR("cassandra.storagedir"), diff --cc test/simulator/main/org/apache/cassandra/simulator/ClusterSimulation.java index ada4e51a34,1bc900a13f..8925c180ae --- a/test/simulator/main/org/apache/cassandra/simulator/ClusterSimulation.java +++ b/test/simulator/main/org/apache/cassandra/simulator/ClusterSimulation.java @@@ -22,8 -22,9 +22,9 @@@ import java.io.IOException import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.EnumMap; + import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; @@@ -38,7 -39,9 +39,10 @@@ import java.util.function.Supplier import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.FutureCallback; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + +import org.apache.cassandra.auth.PasswordSaltSupplier; import org.apache.cassandra.concurrent.ExecutorFactory; import org.apache.cassandra.config.CassandraRelevantProperties; import org.apache.cassandra.config.ParameterizedClass; @@@ -121,11 -117,8 +125,13 @@@ import static org.apache.cassandra.util @SuppressWarnings("RedundantCast") public class ClusterSimulation<S extends Simulation> implements AutoCloseable { + private static final Logger logger = LoggerFactory.getLogger(ClusterSimulation.class); + + static + { + CassandraRelevantProperties.TEST_STORAGE_COMPATIBILITY_MODE.setEnum(StorageCompatibilityMode.NONE); + } + public static final Class<?>[] SHARE = new Class[] { AsyncFunction.class, @@@ -217,34 -195,10 +223,37 @@@ protected HeapPool.Logged.Listener memoryListener; protected SimulatedTime.Listener timeListener = (i1, i2) -> {}; protected LongConsumer onThreadLocalRandomCheck; + protected String transactionalMode = "off"; + protected FutureActionSchedulerFactory futureActionSchedulerFactory; + protected PerVerbFutureActionSchedulersFactory perVerbFutureActionSchedulersFactory; + protected String memtableType = null; + protected String memtableAllocationType = null; + protected String sstableFormat = null; + public Builder<S> failures(Failures failures) + { + this.failures = failures; + return this; + } + + public Builder<S> writeTimeoutNanos(long nanos) + { + this.writeTimeoutNanos = nanos; + return this; + } + + public Builder<S> readTimeoutNanos(long nanos) + { + this.readTimeoutNanos = nanos; + return this; + } + + public Builder<S> requestTimeoutNanos(long nanos) + { + this.requestTimeoutNanos = nanos; + return this; + } + public Debug debug() { return debug; @@@ -612,17 -526,24 +621,35 @@@ return this; } + public Builder<S> transactionalMode(String mode) + { + this.transactionalMode = mode; + return this; + } + + public TransactionalMode transactionalMode() + { + return TransactionalMode.fromString(transactionalMode); + } + + public Builder<S> memtableType(String type) + { + this.memtableType = type; + return this; + } + + public Builder<S> memtableAllocationType(String type) + { + this.memtableAllocationType = type; + return this; + } + + public Builder<S> sstableFormat(String format) + { + this.sstableFormat = format; + return this; + } + public abstract ClusterSimulation<S> create(long seed) throws IOException; } @@@ -767,8 -682,68 +794,67 @@@ execution = new SimulatedExecution(); + // Track randomized configuration for consolidated logging + Map<String, String> randomizedConfig = new LinkedHashMap<>(); + randomizedConfig.put("nodes", String.valueOf(numOfNodes)); + randomizedConfig.put("dcs", String.valueOf(numOfDcs)); + + // Log replication factors + StringBuilder rfString = new StringBuilder(); + for (int i = 0; i < numOfDcs; ++i) + { + if (i > 0) + rfString.append(","); + rfString.append("dc").append(i).append(":").append(initialRf[i]); + } + randomizedConfig.put("replication_factors", rfString.toString()); + + // Randomize memtable type + String memtableType; + if (builder.memtableType != null) + { + memtableType = builder.memtableType; + } + else + { + String[] memtableTypes = {"TrieMemtable", "SkipListMemtable"}; + memtableType = memtableTypes[random.uniform(0, memtableTypes.length)]; + } + randomizedConfig.put("memtable", memtableType); + + // Randomize memtable allocation type (heap-based only to avoid InterruptibleChannel issues with offheap) + String memtableAllocationType; + if (builder.memtableAllocationType != null) + { + memtableAllocationType = builder.memtableAllocationType; + } + else + { + String[] allocationTypes = { + "heap_buffers", // Slab allocator (pooled memory) + "unslabbed_heap_buffers" // Direct heap allocation (no pooling) + }; + memtableAllocationType = allocationTypes[random.uniform(0, allocationTypes.length)]; + } + randomizedConfig.put("memtable_allocation_type", memtableAllocationType); + + // Randomize SSTable format + String sstableFormat; + if (builder.sstableFormat != null) + { + sstableFormat = builder.sstableFormat; + } + else + { + String[] formats = {"big", "bti"}; + sstableFormat = formats[random.uniform(0, formats.length)]; + } + randomizedConfig.put("sstable_format", sstableFormat); - CassandraRelevantProperties.SSTABLE_FORMAT_DEFAULT.setString(sstableFormat); + KindOfSequence kindOfDriftSequence = Choices.uniform(KindOfSequence.values()).choose(random); KindOfSequence kindOfDiscontinuitySequence = Choices.uniform(KindOfSequence.values()).choose(random); + randomizedConfig.put("clock_drift_sequence", kindOfDriftSequence.toString()); + randomizedConfig.put("clock_discontinuity_sequence", kindOfDiscontinuitySequence.toString()); time = new SimulatedTime(numOfNodes, random, 1577836800000L /*Jan 1st UTC*/, builder.clockDriftNanos, kindOfDriftSequence, kindOfDiscontinuitySequence.period(builder.clockDiscontinuitIntervalNanos, random), builder.timeListener); @@@ -778,29 -753,15 +864,28 @@@ }); Predicate<String> sharedClassPredicate = getSharedClassPredicate(ISOLATE, SHARE, ANY, SIMULATION); - InterceptAsClassTransformer interceptClasses = new InterceptAsClassTransformer(builder.monitorDelayChance.asSupplier(random), builder.nemesisChance.asSupplier(random), NemesisFieldSelectors.get(), ClassLoader.getSystemClassLoader(), sharedClassPredicate.negate()); + DeterministicChanceSupplier monitorDelayChance; { + long monitorDelayChanceSeed = random.uniform(0, Long.MAX_VALUE); + monitorDelayChance = hash -> { + RandomSource subRandom = new RandomSource.Default(); + subRandom.reset(monitorDelayChanceSeed * 31 + hash); + return builder.monitorDelayChance.asSupplier(subRandom); + }; + } + DeterministicChanceSupplier nemesisChance; { + long nemesisChanceSeed = random.uniform(0, Long.MAX_VALUE); + nemesisChance = hash -> { + RandomSource subRandom = new RandomSource.Default(); + subRandom.reset(nemesisChanceSeed * 31 + hash); + return builder.nemesisChance.asSupplier(subRandom); + }; + } + + InterceptAsClassTransformer interceptClasses = new InterceptAsClassTransformer(monitorDelayChance, nemesisChance, NemesisFieldSelectors.get(), ClassLoader.getSystemClassLoader(), sharedClassPredicate.negate()); threadLocalRandomCheck = new ThreadLocalRandomCheck(builder.onThreadLocalRandomCheck); - Failures failures = new Failures(); + Failures failures = builder.failures; ThreadAllocator threadAllocator = new ThreadAllocator(random, builder.threadCount, numOfNodes); - - List<String> allowedDiskAccessModes = Arrays.asList("mmap", "mmap_index_only", "standard"); - String disk_access_mode = allowedDiskAccessModes.get(random.uniform(0, allowedDiskAccessModes.size() - 1)); - randomizedConfig.put("disk_access_mode", disk_access_mode); - boolean commitlogCompressed = random.decide(.5f); cluster = snitch.setup(Cluster.build(numOfNodes) .withRoot(fs.getPath("/cassandra")) .withSharedClasses(sharedClassPredicate) @@@ -812,17 -772,26 +897,32 @@@ .set("cas_contention_timeout", String.format("%dms", NANOSECONDS.toMillis(builder.contentionTimeoutNanos))) .set("request_timeout", String.format("%dms", NANOSECONDS.toMillis(builder.requestTimeoutNanos))) .set("memtable_heap_space", "1MiB") - .set("memtable_allocation_type", builder.memoryListener != null ? "unslabbed_heap_buffers_logged" : "heap_buffers") + .set("memtable_allocation_type", builder.memoryListener != null ? "unslabbed_heap_buffers_logged" : memtableAllocationType) .set("file_cache_size", "16MiB") .set("use_deterministic_table_id", true) - .set("disk_access_mode", disk_access_mode) + .set("accord.queue_submission_model", "ASYNC") + .set("accord.range_migration", "explicit") + .set("disk_access_mode", "standard") .set("failure_detector", SimulatedFailureDetector.Instance.class.getName()) - .set("commitlog_sync", "batch"); + .set("commitlog_compression", new ParameterizedClass(LZ4Compressor.class.getName(), emptyMap())) + .set("commitlog_sync", "batch") + .set("accord.journal.flush_mode", "BATCH") - .set("accord.command_store_shard_count", "4"); ++ .set("accord.command_store_shard_count", "4") ++ .set("sstable", Map.of("selected_format", sstableFormat)); + + if (memtableType.equals("TrieMemtable")) + { + config.set("memtable", Map.of( + "configurations", Map.of( + "default", Map.of("class_name", "TrieMemtable")))); + } + else + { + config.set("memtable", Map.of( + "configurations", Map.of( + "default", Map.of("class_name", "SkipListMemtable")))); + } + // TODO: Add remove() to IInstanceConfig if (config instanceof InstanceConfig) { @@@ -913,28 -876,23 +1013,37 @@@ DirectStreamingConnectionFactory.setup(cluster); delivery = new SimulatedMessageDelivery(cluster); failureDetector = new SimulatedFailureDetector(cluster); - SimulatedFutureActionScheduler futureActionScheduler = builder.futureActionScheduler(numOfNodes, time, random); - simulated = new SimulatedSystems(random, time, delivery, execution, ballots, failureDetector, snitch, futureActionScheduler, builder.debug, failures); - simulated.register(futureActionScheduler); - - RunnableActionScheduler scheduler = builder.schedulerFactory.create(random); + FutureActionScheduler futureActionScheduler = builder.futureActionScheduler(numOfNodes, time, random); + Map<Verb, FutureActionScheduler> perVerbFutureActionScheduler = builder.perVerbFutureActionSchedulers(numOfNodes, time, random, futureActionScheduler); + simulated = new SimulatedSystems(random, time, delivery, execution, ballots, failureDetector, snitch, futureActionScheduler, perVerbFutureActionScheduler, builder.debug, failures); + if (futureActionScheduler instanceof SimulatedFutureActionScheduler) + simulated.register((SimulatedFutureActionScheduler) futureActionScheduler); + + scheduler = builder.schedulerFactory.create(random); + // TODO (required): we aren't passing paxos variant change parameter anymore - options = new ClusterActions.Options(builder.topologyChangeLimit, Choices.uniform(KindOfSequence.values()).choose(random).period(builder.topologyChangeIntervalNanos, random), + KindOfSequence topologyChangeSequence = Choices.uniform(KindOfSequence.values()).choose(random); - ClusterActions.Options options = new ClusterActions.Options(builder.topologyChangeLimit, topologyChangeSequence.period(builder.topologyChangeIntervalNanos, random), - Choices.random(random, builder.topologyChanges), - minRf, initialRf, maxRf, null); - simulation = factory.create(simulated, scheduler, cluster, options); ++ options = new ClusterActions.Options(builder.topologyChangeLimit, topologyChangeSequence.period(builder.topologyChangeIntervalNanos, random), + Choices.random(random, builder.topologyChanges), + builder.consensusChangeLimit, Choices.uniform(KindOfSequence.values()).choose(random).period(builder.consensusChangeIntervalNanos, random), + Choices.random(random, builder.consensusChanges), + minRf, initialRf, maxRf, null); + this.factory = factory; + // Add remaining randomization tracking - randomizedConfig.put("network_scheduler", futureActionScheduler.getKind().toString()); ++ if (futureActionScheduler instanceof SimulatedFutureActionScheduler) ++ randomizedConfig.put("network_scheduler", ((SimulatedFutureActionScheduler) futureActionScheduler).getKind().toString()); + randomizedConfig.put("runnable_scheduler", scheduler.getClass().getSimpleName()); + randomizedConfig.put("topology_change_sequence", topologyChangeSequence.toString()); + + logger.warn("Seed 0x{} - Randomized config: {}", Long.toHexString(seed), randomizedConfig); ++ + // during cluster shutdown ignore all failures as there is no reason to track them + onPreShutdown.add(() -> {simulated.failures.ignoreFailures(); return null;}); + } + + public S simulation() + { + return factory.create(simulated, scheduler, cluster, options); } public synchronized void close() throws IOException diff --cc test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java index 4f281dd7e8,006d39f8f7..7eb6584a6a --- a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java @@@ -22,99 -25,21 +22,103 @@@ import org.junit.Test import org.apache.cassandra.simulator.paxos.PaxosSimulationRunner; + import static org.apache.cassandra.simulator.test.SimulationTestBase.DEFAULT_ITERATIONS; + +/** + * In order to run these tests in your IDE, you need to first build a simulator jara + * + * ant simulator-jars + * + * And then run your test using the following settings (omit add-* if you are running on jdk8): + * + -Dstorage-config=$MODULE_DIR$/test/conf + -Djava.awt.headless=true + -javaagent:$MODULE_DIR$/lib/jamm-0.4.0.jar + -ea + -Dcassandra.debugrefcount=true + -Xss384k + -XX:SoftRefLRUPolicyMSPerMB=0 + -XX:ActiveProcessorCount=2 + -XX:HeapDumpPath=build/test + -Dcassandra.test.driver.connection_timeout_ms=10000 + -Dcassandra.test.driver.read_timeout_ms=24000 + -Dcassandra.memtable_row_overhead_computation_step=100 + -Dcassandra.test.use_prepared=true + -Dcassandra.test.sstableformatdevelopment=true + -Djava.security.egd=file:/dev/urandom + -Dcassandra.testtag=.jdk11 + -Dcassandra.keepBriefBrief=true + -Dcassandra.allow_simplestrategy=true + -Dcassandra.strict.runtime.checks=true + -Dcassandra.reads.thresholds.coordinator.defensive_checks_enabled=true + -Dcassandra.test.flush_local_schema_changes=false + -Dcassandra.test.messagingService.nonGracefulShutdown=true + -Dcassandra.use_nix_recursive_delete=true + -Dcie-cassandra.disable_schema_drop_log=true + -Dlogback.configurationFile=file://$MODULE_DIR$/test/conf/logback-simulator.xml + -Dcassandra.ring_delay_ms=10000 + -Dcassandra.tolerate_sstable_size=true + -Dcassandra.skip_sync=true + -Dcassandra.debugrefcount=false + -Dcassandra.test.simulator.determinismcheck=strict + -Dcassandra.test.simulator.print_asm=none + -javaagent:$MODULE_DIR$/build/test/lib/jars/simulator-asm.jar + -Xbootclasspath/a:$MODULE_DIR$/build/test/lib/jars/simulator-bootstrap.jar + -XX:ActiveProcessorCount=4 + -XX:-TieredCompilation + -XX:-BackgroundCompilation + -XX:CICompilerCount=1 + -XX:Tier4CompileThreshold=1000 + -XX:ReservedCodeCacheSize=256M + -Xmx16G + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED + --add-exports java.base/jdk.internal.ref=ALL-UNNAMED + --add-exports java.base/sun.nio.ch=ALL-UNNAMED + --add-exports java.management.rmi/com.sun.jmx.remote.internal.rmi=ALL-UNNAMED + --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED + --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED + --add-exports java.sql/java.sql=ALL-UNNAMED + --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED + --add-opens java.base/java.lang.module=ALL-UNNAMED + --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/jdk.internal.loader=ALL-UNNAMED + --add-opens java.base/jdk.internal.ref=ALL-UNNAMED + --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED + --add-opens java.base/jdk.internal.math=ALL-UNNAMED + --add-opens java.base/jdk.internal.module=ALL-UNNAMED + --add-opens java.base/jdk.internal.util.jar=ALL-UNNAMED + --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED + --add-opens jdk.management.jfr/jdk.management.jfr=ALL-UNNAMED + --add-opens java.desktop/com.sun.beans.introspect=ALL-UNNAMED + */ public class ShortPaxosSimulationTest { @Test - public void simulationTest() throws IOException + public void simulationTest() { - PaxosSimulationRunner.main(new String[] { "run", "-n", "3..6", "-t", "1000", "-c", "2", "--cluster-action-limit", "2", "-s", "30", "--simulations", String.valueOf(DEFAULT_ITERATIONS) }); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "run", + "--variant", "v2", + "-n", "3..6", + "-t", "1000", + "-c", "2", + "--cluster-action-limit", "2", - "-s", "30" }); ++ "-s", "30", ++ "--simulations", String.valueOf(DEFAULT_ITERATIONS) }); } @Test - @Ignore("fails due to OOM DirectMemory - unclear why") - public void selfReconcileTest() throws IOException + public void selfReconcileTest() { - PaxosSimulationRunner.main(new String[] { "reconcile", "-n", "3..6", "-t", "1000", "-c", "2", "--cluster-action-limit", "2", "-s", "30", "--with-self", "--simulations", String.valueOf(DEFAULT_ITERATIONS) }); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "reconcile", + "-n", "3..6", + "-t", "1000", + "-c", "2", + "--cluster-action-limit", "2", + "-s", "30", + "--with-self", + "--with-rng", "0", - "--with-time", "0",}); ++ "--with-time", "0", ++ "--simulations", String.valueOf(DEFAULT_ITERATIONS) }); } } diff --cc test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java index 195a4f23a5,682fe9f167..6c87b01e78 --- a/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java @@@ -78,13 -65,10 +78,14 @@@ import org.apache.cassandra.utils.Clock import org.apache.cassandra.utils.CloseableIterator; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_GLOBAL; +import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_APPROX; +import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_PRECISE; + import static org.apache.cassandra.config.CassandraRelevantProperties.SIMULATOR_ITERATIONS; -import static org.apache.cassandra.simulator.ActionSchedule.Mode.STREAM_LIMITED; +import static org.apache.cassandra.simulator.ActionSchedule.Mode.TIME_LIMITED; import static org.apache.cassandra.simulator.ActionSchedule.Mode.UNLIMITED; import static org.apache.cassandra.simulator.ClusterSimulation.ISOLATE; import static org.apache.cassandra.simulator.ClusterSimulation.SHARE; @@@ -96,29 -80,20 +97,31 @@@ import static org.apache.cassandra.util public class SimulationTestBase { - private static final Logger logger = LoggerFactory.getLogger(SimulationTestBase.class); + public static final int DEFAULT_ITERATIONS = SIMULATOR_ITERATIONS.getInt(); + - static abstract class DTestClusterSimulation implements Simulation + @BeforeClass + public static void beforeAll() + { + // Disallow time on the bootstrap classloader + for (CassandraRelevantProperties property : Arrays.asList(CLOCK_GLOBAL, CLOCK_MONOTONIC_APPROX, CLOCK_MONOTONIC_PRECISE)) + property.setString("org.apache.cassandra.simulator.systems.SimulatedTime$Delegating"); + try { Clock.Global.nanoTime(); } catch (IllegalStateException e) {} // make sure static initializer gets called + } + + // Don't use loggers before invoking simulator it messes up initialization order +// private static final Logger logger = LoggerFactory.getLogger(Logger.class); + + + static abstract class SimpleSimulation extends AbstractSimulation { - final SimulatedSystems simulated; - final RunnableActionScheduler scheduler; - final Cluster cluster; + protected SimpleSimulation(SimulatedSystems simulated, RunnableActionScheduler scheduler, Cluster cluster) + { + super(simulated, scheduler, cluster); + } - public DTestClusterSimulation(SimulatedSystems simulated, RunnableActionScheduler scheduler, Cluster cluster) + protected SimpleSimulation(SimulatedSystems simulated, RunnableActionScheduler scheduler, Cluster cluster, ClusterActions.Options options) { - this.simulated = simulated; - this.scheduler = scheduler; - this.cluster = cluster; + super(simulated, scheduler, cluster, options); } public Action executeQuery(int node, String query, ConsistencyLevel cl, Object... bindings) @@@ -198,157 -144,62 +201,180 @@@ } } - public static void simulate(Function<DTestClusterSimulation, ActionList> init, - Function<DTestClusterSimulation, ActionList> test, - Consumer<ClusterSimulation.Builder<DTestClusterSimulation>> configure) throws IOException + static class DTestClusterSimulationBuilder extends ClusterSimulation.Builder<SimpleSimulation> { - simulate(init, test, configure, 1); + protected final Function<SimpleSimulation, ActionList> init; + protected final Function<SimpleSimulation, ActionList> test; + protected final Function<SimpleSimulation, ActionList> teardown; + protected final BiConsumer<RandomSource, IInstanceConfig> configUpdater; + + DTestClusterSimulationBuilder(Function<SimpleSimulation, ActionList> init, + Function<SimpleSimulation, ActionList> test, + Function<SimpleSimulation, ActionList> teardown, + BiConsumer<RandomSource, IInstanceConfig> configUpdater) + { + this.init = init; + this.test = test; + this.teardown = teardown; + this.configUpdater = configUpdater; + } + + public ClusterSimulation<SimpleSimulation> create(long seed) throws IOException + { + RandomSource random = new RandomSource.Default(); + random.reset(seed); + + return new ClusterSimulation<>(random, seed, 1, this, + c -> configUpdater.accept(random, c), + (simulated, scheduler, cluster, options) -> new SimpleSimulation(simulated, scheduler, cluster) + { + protected ActionList initialize() + { + return init.apply(this); + } + + protected ActionList teardown() + { + return teardown.apply(this); + } + + protected ActionList execute() + { + return test.apply(this); + } + }); + } } - public static void simulate(Function<DTestClusterSimulation, ActionList> init, - Function<DTestClusterSimulation, ActionList> test, - Consumer<ClusterSimulation.Builder<DTestClusterSimulation>> configure, - int iterations) throws IOException + static void simulate(Function<SimpleSimulation, ActionList> init, + Function<SimpleSimulation, ActionList> test, + Function<SimpleSimulation, ActionList> teardown, + Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure) throws IOException { - SimulationRunner.beforeAll(); - long seed = System.currentTimeMillis(); - class Factory extends ClusterSimulation.Builder<DTestClusterSimulation> + simulate(init, test, teardown, configure, (i1, i2) -> {}); + } + ++ static void simulate(Function<SimpleSimulation, ActionList> init, ++ Function<SimpleSimulation, ActionList> test, ++ Function<SimpleSimulation, ActionList> teardown, ++ Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure, ++ int iterations) throws IOException ++ { ++ simulate(System::currentTimeMillis, new DTestClusterSimulationBuilder(init, test, teardown, (i1, i2) -> {}), ++ configure, iterations); ++ } ++ + @SuppressWarnings("unused") + static void simulate(long seed, + Function<SimpleSimulation, ActionList> init, + Function<SimpleSimulation, ActionList> test, + Function<SimpleSimulation, ActionList> teardown, + Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure) throws IOException + { + simulate(seed, init, test, teardown, configure, (i1, i2) -> {}); + } + + static void simulate(Function<SimpleSimulation, ActionList> init, + Function<SimpleSimulation, ActionList> test, + Function<SimpleSimulation, ActionList> teardown, + Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure, + BiConsumer<RandomSource, IInstanceConfig> configUpdater) throws IOException + { + simulate(new DTestClusterSimulationBuilder(init, test, teardown, configUpdater), + configure); + } + + @SuppressWarnings("unused") + static void simulate(long seed, + Function<SimpleSimulation, ActionList> init, + Function<SimpleSimulation, ActionList> test, + Function<SimpleSimulation, ActionList> teardown, + Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure, + BiConsumer<RandomSource, IInstanceConfig> configUpdater) throws IOException + { + simulate(() -> seed, new DTestClusterSimulationBuilder(init, test, teardown, configUpdater), + configure); + } + + public static <T extends Simulation> void simulate(ClusterSimulation.Builder<T> factory, + Consumer<ClusterSimulation.Builder<T>> configure) throws IOException + { + simulate(System::currentTimeMillis, factory, configure); + } + + public static <T extends Simulation> void simulate(long seed, ClusterSimulation.Builder<T> factory) throws IOException + { + simulate(() -> seed, factory, i ->{}); + } + + public static <T extends Simulation> void simulate(ClusterSimulation.SimulationFactory<T> factory) throws IOException + { + simulate(System.currentTimeMillis(), factory); + } + + public static <T extends Simulation> void simulate(long seed, ClusterSimulation.SimulationFactory<T> factory) throws IOException + { + simulate(seed, factory, b -> {}); + } + + public static <T extends Simulation> void simulate(ClusterSimulation.SimulationFactory<T> factory, Consumer<ClusterSimulation.Builder<T>> configure) throws IOException + { + simulate(System.currentTimeMillis(), factory, configure); + } + + public static <T extends Simulation> void simulate(long seed, ClusterSimulation.SimulationFactory<T> factory, Consumer<ClusterSimulation.Builder<T>> configure) throws IOException + { + BasicSimulationBuilder<T> builder = new BasicSimulationBuilder<>() { - public ClusterSimulation<DTestClusterSimulation> create(long seed) throws IOException + @Override + T create(SimulatedSystems simulated, RunnableActionScheduler scheduler, Cluster cluster, ClusterActions.Options options) { - RandomSource random = new RandomSource.Default(); - random.reset(seed); - return new ClusterSimulation<>(random, seed, 1, this, - (c) -> {}, - (simulated, scheduler, cluster, options) -> new DTestClusterSimulation(simulated, scheduler, cluster) { - - protected ActionList initialize() - { - return init.apply(this); - } - - protected ActionList execute() - { - return test.apply(this); - } - }); + return factory.create(simulated, scheduler, cluster, options); } - } + }; + simulate(() -> seed, builder, configure); + } + + public static <T extends Simulation> void simulate(LongSupplier seedGen, + ClusterSimulation.Builder<T> factory, + Consumer<ClusterSimulation.Builder<T>> configure) throws IOException ++ { ++ simulate(seedGen, factory, configure, 1); ++ } + - Factory factory = new Factory(); ++ public static <T extends Simulation> void simulate(LongSupplier seedGen, ++ ClusterSimulation.Builder<T> factory, ++ Consumer<ClusterSimulation.Builder<T>> configure, ++ int iterations) throws IOException + { + SimulationRunner.beforeAll(); + long seed = seedGen.getAsLong(); + // Development seed: + //long seed = 1687184561194L; + System.out.printf("Simulation seed: %dL%n", seed); configure.accept(factory); - try (ClusterSimulation<?> cluster = factory.create(seed)) + for (int i = 0; i < iterations; i++) { - try (Simulation simulation = cluster.simulation()) + long currentSeed = seed + i; - logger.info("Running iteration {} of {} with seed {}L", i + 1, iterations, currentSeed); ++ System.out.printf("Running iteration %d of %d with seed %dL%n", i + 1, iterations, currentSeed); + try (ClusterSimulation<?> cluster = factory.create(currentSeed)) { - simulation.run(); - try ++ try (Simulation simulation = cluster.simulation()) + { - cluster.simulation.run(); ++ simulation.run(); + } + catch (Throwable t) + { - throw new AssertionError(String.format("Failed on seed 0x%s (base seed 0x%s + %d)", - Long.toHexString(currentSeed), Long.toHexString(seed), i), t); ++ throw new SimulationException(currentSeed, t); + } } + catch (Throwable t) + { - throw new SimulationException(seed, t); ++ if (t instanceof SimulationException) ++ throw t; ++ throw new SimulationException(currentSeed, t); + } } - catch (Throwable t) - { - if (t instanceof SimulationException) - throw t; - throw new SimulationException(seed, t); - } } public static void simulate(IIsolatedExecutor.SerializableRunnable run, @@@ -361,7 -218,20 +393,20 @@@ public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables, IIsolatedExecutor.SerializableRunnable check) { - simulate(runnables, check, System.currentTimeMillis()); + simulate(runnables, check, 1); + } + + public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables, + IIsolatedExecutor.SerializableRunnable check, + int iterations) + { + long seed = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) + { + long currentSeed = seed + i; - logger.info("Running iteration {} of {} with seed {}L", i + 1, iterations, currentSeed); ++ System.out.printf("Running iteration %d of %d with seed %dL%n", i + 1, iterations, currentSeed); + simulate(runnables, check, currentSeed); + } } public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables, diff --cc test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java index 404606c1a4,1872bed12f..8d94c7a2c3 --- a/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/TrivialSimulationTest.java @@@ -34,13 -38,7 +34,13 @@@ import static org.apache.cassandra.simu public class TrivialSimulationTest extends SimulationTestBase { + @Test + public void identityHashMapTest() + { + simulate(arr(() -> new IdentityHashMap<>().put(1, 1)), - () -> {}); ++ () -> {}, DEFAULT_ITERATIONS); + } + @Test public void trivialTest() throws IOException // for demonstration/experiment purposes { @@@ -81,8 -81,13 +82,6 @@@ }); } }), - () -> {}); + () -> {}, DEFAULT_ITERATIONS); } - -- - @Test - public void identityHashMapTest() - { - simulate(arr(() -> new IdentityHashMap<>().put(1, 1)), - () -> {}, DEFAULT_ITERATIONS); - } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
