Skip to content

Commit 87d79f3

Browse files
committed
Merge branch 'cassandra-5.0' into trunk
* cassandra-5.0: Randomize Memtable type/allocation type and SSTable format in Simulator tests
2 parents cdb67f6 + ddfba19 commit 87d79f3

6 files changed

Lines changed: 189 additions & 25 deletions

File tree

src/java/org/apache/cassandra/config/CassandraRelevantProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ public enum CassandraRelevantProperties
528528
SERIALIZATION_EMPTY_TYPE_NONEMPTY_BEHAVIOR("cassandra.serialization.emptytype.nonempty_behavior"),
529529
SET_SEP_THREAD_NAME("cassandra.set_sep_thread_name", "true"),
530530
SHUTDOWN_ANNOUNCE_DELAY_IN_MS("cassandra.shutdown_announce_in_ms", "2000"),
531+
SIMULATOR_ITERATIONS("simulator.iterations", "3"),
531532
SIMULATOR_SEED("cassandra.simulator.seed"),
532533
SIMULATOR_STARTED("cassandra.simulator.started"),
533534
SIZE_RECORDER_INTERVAL("cassandra.size_recorder_interval", "300"),
@@ -559,7 +560,6 @@ public enum CassandraRelevantProperties
559560
SNAPSHOT_MIN_ALLOWED_TTL_SECONDS("cassandra.snapshot.min_allowed_ttl_seconds", "60"),
560561
SSL_ENABLE("ssl.enable"),
561562
SSL_STORAGE_PORT("cassandra.ssl_storage_port"),
562-
SSTABLE_FORMAT_DEFAULT("cassandra.sstable.format.default"),
563563
START_GOSSIP("cassandra.start_gossip", "true"),
564564
START_NATIVE_TRANSPORT("cassandra.start_native_transport"),
565565
STORAGE_DIR("cassandra.storagedir"),

test/simulator/main/org/apache/cassandra/simulator/ClusterSimulation.java

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.Collections;
2626
import java.util.EnumMap;
27+
import java.util.LinkedHashMap;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.TreeMap;
@@ -38,6 +39,9 @@
3839
import com.google.common.util.concurrent.AsyncFunction;
3940
import com.google.common.util.concurrent.FutureCallback;
4041

42+
import org.slf4j.Logger;
43+
import org.slf4j.LoggerFactory;
44+
4145
import org.apache.cassandra.auth.PasswordSaltSupplier;
4246
import org.apache.cassandra.concurrent.ExecutorFactory;
4347
import org.apache.cassandra.config.CassandraRelevantProperties;
@@ -121,6 +125,8 @@
121125
@SuppressWarnings("RedundantCast")
122126
public class ClusterSimulation<S extends Simulation> implements AutoCloseable
123127
{
128+
private static final Logger logger = LoggerFactory.getLogger(ClusterSimulation.class);
129+
124130
static
125131
{
126132
CassandraRelevantProperties.TEST_STORAGE_COMPATIBILITY_MODE.setEnum(StorageCompatibilityMode.NONE);
@@ -220,6 +226,9 @@ public static abstract class Builder<S extends Simulation>
220226
protected String transactionalMode = "off";
221227
protected FutureActionSchedulerFactory futureActionSchedulerFactory;
222228
protected PerVerbFutureActionSchedulersFactory perVerbFutureActionSchedulersFactory;
229+
protected String memtableType = null;
230+
protected String memtableAllocationType = null;
231+
protected String sstableFormat = null;
223232

224233
public Builder<S> failures(Failures failures)
225234
{
@@ -623,6 +632,24 @@ public TransactionalMode transactionalMode()
623632
return TransactionalMode.fromString(transactionalMode);
624633
}
625634

635+
public Builder<S> memtableType(String type)
636+
{
637+
this.memtableType = type;
638+
return this;
639+
}
640+
641+
public Builder<S> memtableAllocationType(String type)
642+
{
643+
this.memtableAllocationType = type;
644+
return this;
645+
}
646+
647+
public Builder<S> sstableFormat(String format)
648+
{
649+
this.sstableFormat = format;
650+
return this;
651+
}
652+
626653
public abstract ClusterSimulation<S> create(long seed) throws IOException;
627654
}
628655

@@ -767,8 +794,67 @@ public ClusterSimulation(RandomSource random, long seed, int uniqueNum,
767794

768795
execution = new SimulatedExecution();
769796

797+
// Track randomized configuration for consolidated logging
798+
Map<String, String> randomizedConfig = new LinkedHashMap<>();
799+
randomizedConfig.put("nodes", String.valueOf(numOfNodes));
800+
randomizedConfig.put("dcs", String.valueOf(numOfDcs));
801+
802+
// Log replication factors
803+
StringBuilder rfString = new StringBuilder();
804+
for (int i = 0; i < numOfDcs; ++i)
805+
{
806+
if (i > 0)
807+
rfString.append(",");
808+
rfString.append("dc").append(i).append(":").append(initialRf[i]);
809+
}
810+
randomizedConfig.put("replication_factors", rfString.toString());
811+
812+
// Randomize memtable type
813+
String memtableType;
814+
if (builder.memtableType != null)
815+
{
816+
memtableType = builder.memtableType;
817+
}
818+
else
819+
{
820+
String[] memtableTypes = {"TrieMemtable", "SkipListMemtable"};
821+
memtableType = memtableTypes[random.uniform(0, memtableTypes.length)];
822+
}
823+
randomizedConfig.put("memtable", memtableType);
824+
825+
// Randomize memtable allocation type (heap-based only to avoid InterruptibleChannel issues with offheap)
826+
String memtableAllocationType;
827+
if (builder.memtableAllocationType != null)
828+
{
829+
memtableAllocationType = builder.memtableAllocationType;
830+
}
831+
else
832+
{
833+
String[] allocationTypes = {
834+
"heap_buffers", // Slab allocator (pooled memory)
835+
"unslabbed_heap_buffers" // Direct heap allocation (no pooling)
836+
};
837+
memtableAllocationType = allocationTypes[random.uniform(0, allocationTypes.length)];
838+
}
839+
randomizedConfig.put("memtable_allocation_type", memtableAllocationType);
840+
841+
// Randomize SSTable format
842+
String sstableFormat;
843+
if (builder.sstableFormat != null)
844+
{
845+
sstableFormat = builder.sstableFormat;
846+
}
847+
else
848+
{
849+
String[] formats = {"big", "bti"};
850+
sstableFormat = formats[random.uniform(0, formats.length)];
851+
}
852+
randomizedConfig.put("sstable_format", sstableFormat);
853+
770854
KindOfSequence kindOfDriftSequence = Choices.uniform(KindOfSequence.values()).choose(random);
771855
KindOfSequence kindOfDiscontinuitySequence = Choices.uniform(KindOfSequence.values()).choose(random);
856+
randomizedConfig.put("clock_drift_sequence", kindOfDriftSequence.toString());
857+
randomizedConfig.put("clock_discontinuity_sequence", kindOfDiscontinuitySequence.toString());
772858
time = new SimulatedTime(numOfNodes, random, 1577836800000L /*Jan 1st UTC*/, builder.clockDriftNanos, kindOfDriftSequence,
773859
kindOfDiscontinuitySequence.period(builder.clockDiscontinuitIntervalNanos, random),
774860
builder.timeListener);
@@ -800,7 +886,6 @@ public ClusterSimulation(RandomSource random, long seed, int uniqueNum,
800886

801887
Failures failures = builder.failures;
802888
ThreadAllocator threadAllocator = new ThreadAllocator(random, builder.threadCount, numOfNodes);
803-
804889
cluster = snitch.setup(Cluster.build(numOfNodes)
805890
.withRoot(fs.getPath("/cassandra"))
806891
.withSharedClasses(sharedClassPredicate)
@@ -812,7 +897,7 @@ public ClusterSimulation(RandomSource random, long seed, int uniqueNum,
812897
.set("cas_contention_timeout", String.format("%dms", NANOSECONDS.toMillis(builder.contentionTimeoutNanos)))
813898
.set("request_timeout", String.format("%dms", NANOSECONDS.toMillis(builder.requestTimeoutNanos)))
814899
.set("memtable_heap_space", "1MiB")
815-
.set("memtable_allocation_type", builder.memoryListener != null ? "unslabbed_heap_buffers_logged" : "heap_buffers")
900+
.set("memtable_allocation_type", builder.memoryListener != null ? "unslabbed_heap_buffers_logged" : memtableAllocationType)
816901
.set("file_cache_size", "16MiB")
817902
.set("use_deterministic_table_id", true)
818903
.set("accord.queue_submission_model", "ASYNC")
@@ -822,7 +907,22 @@ public ClusterSimulation(RandomSource random, long seed, int uniqueNum,
822907
.set("commitlog_compression", new ParameterizedClass(LZ4Compressor.class.getName(), emptyMap()))
823908
.set("commitlog_sync", "batch")
824909
.set("accord.journal.flush_mode", "BATCH")
825-
.set("accord.command_store_shard_count", "4");
910+
.set("accord.command_store_shard_count", "4")
911+
.set("sstable", Map.of("selected_format", sstableFormat));
912+
913+
if (memtableType.equals("TrieMemtable"))
914+
{
915+
config.set("memtable", Map.of(
916+
"configurations", Map.of(
917+
"default", Map.of("class_name", "TrieMemtable"))));
918+
}
919+
else
920+
{
921+
config.set("memtable", Map.of(
922+
"configurations", Map.of(
923+
"default", Map.of("class_name", "SkipListMemtable"))));
924+
}
925+
826926
// TODO: Add remove() to IInstanceConfig
827927
if (config instanceof InstanceConfig)
828928
{
@@ -921,13 +1021,22 @@ public void afterStartup(IInstance i)
9211021

9221022
scheduler = builder.schedulerFactory.create(random);
9231023
// TODO (required): we aren't passing paxos variant change parameter anymore
924-
options = new ClusterActions.Options(builder.topologyChangeLimit, Choices.uniform(KindOfSequence.values()).choose(random).period(builder.topologyChangeIntervalNanos, random),
1024+
KindOfSequence topologyChangeSequence = Choices.uniform(KindOfSequence.values()).choose(random);
1025+
options = new ClusterActions.Options(builder.topologyChangeLimit, topologyChangeSequence.period(builder.topologyChangeIntervalNanos, random),
9251026
Choices.random(random, builder.topologyChanges),
9261027
builder.consensusChangeLimit, Choices.uniform(KindOfSequence.values()).choose(random).period(builder.consensusChangeIntervalNanos, random),
9271028
Choices.random(random, builder.consensusChanges),
9281029
minRf, initialRf, maxRf, null);
9291030
this.factory = factory;
9301031

1032+
// Add remaining randomization tracking
1033+
if (futureActionScheduler instanceof SimulatedFutureActionScheduler)
1034+
randomizedConfig.put("network_scheduler", ((SimulatedFutureActionScheduler) futureActionScheduler).getKind().toString());
1035+
randomizedConfig.put("runnable_scheduler", scheduler.getClass().getSimpleName());
1036+
randomizedConfig.put("topology_change_sequence", topologyChangeSequence.toString());
1037+
1038+
logger.warn("Seed 0x{} - Randomized config: {}", Long.toHexString(seed), randomizedConfig);
1039+
9311040
// during cluster shutdown ignore all failures as there is no reason to track them
9321041
onPreShutdown.add(() -> {simulated.failures.ignoreFailures(); return null;});
9331042
}

test/simulator/main/org/apache/cassandra/simulator/systems/SimulatedFutureActionScheduler.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public Scheduler(SchedulerConfig config, RandomSource random, KindOfSequence kin
6464
final int nodeCount;
6565
final RandomSource random;
6666
final SimulatedTime time;
67+
final KindOfSequence kind;
6768

6869
// TODO (feature): should we produce more than two simultaneous partitions?
6970
final BitSet isInDropPartition = new BitSet();
@@ -83,6 +84,7 @@ public Scheduler(SchedulerConfig config, RandomSource random, KindOfSequence kin
8384

8485
public SimulatedFutureActionScheduler(KindOfSequence kind, int nodeCount, RandomSource random, SimulatedTime time, NetworkConfig network, SchedulerConfig scheduler)
8586
{
87+
this.kind = kind;
8688
this.nodeCount = nodeCount;
8789
this.random = random;
8890
this.time = time;
@@ -193,4 +195,9 @@ public void onChange(Topology newTopology)
193195
if (oldTopology == null || (newTopology.quorumRf < oldTopology.quorumRf && newTopology.quorumRf < isInDropPartition.cardinality()))
194196
recompute();
195197
}
198+
199+
public KindOfSequence getKind()
200+
{
201+
return kind;
202+
}
196203
}

test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import org.apache.cassandra.simulator.paxos.PaxosSimulationRunner;
2424

25+
import static org.apache.cassandra.simulator.test.SimulationTestBase.DEFAULT_ITERATIONS;
26+
2527
/**
2628
* In order to run these tests in your IDE, you need to first build a simulator jara
2729
*
@@ -100,7 +102,8 @@ public void simulationTest()
100102
"-t", "1000",
101103
"-c", "2",
102104
"--cluster-action-limit", "2",
103-
"-s", "30" });
105+
"-s", "30",
106+
"--simulations", String.valueOf(DEFAULT_ITERATIONS) });
104107
}
105108

106109
@Test
@@ -114,7 +117,8 @@ public void selfReconcileTest()
114117
"-s", "30",
115118
"--with-self",
116119
"--with-rng", "0",
117-
"--with-time", "0",});
120+
"--with-time", "0",
121+
"--simulations", String.valueOf(DEFAULT_ITERATIONS) });
118122
}
119123
}
120124

test/simulator/test/org/apache/cassandra/simulator/test/SimulationTestBase.java

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_GLOBAL;
8585
import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_APPROX;
8686
import static org.apache.cassandra.config.CassandraRelevantProperties.CLOCK_MONOTONIC_PRECISE;
87+
import static org.apache.cassandra.config.CassandraRelevantProperties.SIMULATOR_ITERATIONS;
8788
import static org.apache.cassandra.simulator.ActionSchedule.Mode.TIME_LIMITED;
8889
import static org.apache.cassandra.simulator.ActionSchedule.Mode.UNLIMITED;
8990
import static org.apache.cassandra.simulator.ClusterSimulation.ISOLATE;
@@ -96,6 +97,8 @@
9697

9798
public class SimulationTestBase
9899
{
100+
public static final int DEFAULT_ITERATIONS = SIMULATOR_ITERATIONS.getInt();
101+
99102
@BeforeClass
100103
public static void beforeAll()
101104
{
@@ -251,6 +254,16 @@ static void simulate(Function<SimpleSimulation, ActionList> init,
251254
simulate(init, test, teardown, configure, (i1, i2) -> {});
252255
}
253256

257+
static void simulate(Function<SimpleSimulation, ActionList> init,
258+
Function<SimpleSimulation, ActionList> test,
259+
Function<SimpleSimulation, ActionList> teardown,
260+
Consumer<ClusterSimulation.Builder<SimpleSimulation>> configure,
261+
int iterations) throws IOException
262+
{
263+
simulate(System::currentTimeMillis, new DTestClusterSimulationBuilder(init, test, teardown, (i1, i2) -> {}),
264+
configure, iterations);
265+
}
266+
254267
@SuppressWarnings("unused")
255268
static void simulate(long seed,
256269
Function<SimpleSimulation, ActionList> init,
@@ -325,43 +338,75 @@ T create(SimulatedSystems simulated, RunnableActionScheduler scheduler, Cluster
325338
public static <T extends Simulation> void simulate(LongSupplier seedGen,
326339
ClusterSimulation.Builder<T> factory,
327340
Consumer<ClusterSimulation.Builder<T>> configure) throws IOException
341+
{
342+
simulate(seedGen, factory, configure, 1);
343+
}
344+
345+
public static <T extends Simulation> void simulate(LongSupplier seedGen,
346+
ClusterSimulation.Builder<T> factory,
347+
Consumer<ClusterSimulation.Builder<T>> configure,
348+
int iterations) throws IOException
328349
{
329350
SimulationRunner.beforeAll();
330351
long seed = seedGen.getAsLong();
331352
// Development seed:
332353
//long seed = 1687184561194L;
333354
System.out.printf("Simulation seed: %dL%n", seed);
334355
configure.accept(factory);
335-
try (ClusterSimulation<?> cluster = factory.create(seed))
356+
for (int i = 0; i < iterations; i++)
336357
{
337-
try (Simulation simulation = cluster.simulation())
358+
long currentSeed = seed + i;
359+
System.out.printf("Running iteration %d of %d with seed %dL%n", i + 1, iterations, currentSeed);
360+
try (ClusterSimulation<?> cluster = factory.create(currentSeed))
338361
{
339-
simulation.run();
362+
try (Simulation simulation = cluster.simulation())
363+
{
364+
simulation.run();
365+
}
366+
catch (Throwable t)
367+
{
368+
throw new SimulationException(currentSeed, t);
369+
}
340370
}
341371
catch (Throwable t)
342372
{
343-
throw new SimulationException(seed, t);
373+
if (t instanceof SimulationException)
374+
throw t;
375+
throw new SimulationException(currentSeed, t);
344376
}
345377
}
346-
catch (Throwable t)
347-
{
348-
if (t instanceof SimulationException)
349-
throw t;
350-
throw new SimulationException(seed, t);
351-
}
352378
}
353379

354380
public static void simulate(IIsolatedExecutor.SerializableRunnable run,
355381
IIsolatedExecutor.SerializableRunnable check)
356382
{
357-
simulate(new IIsolatedExecutor.SerializableRunnable[]{run},
358-
check);
383+
simulate(new IIsolatedExecutor.SerializableRunnable[]{run}, check, 1);
384+
}
385+
386+
public static void simulate(IIsolatedExecutor.SerializableRunnable run,
387+
IIsolatedExecutor.SerializableRunnable check,
388+
int iterations)
389+
{
390+
simulate(new IIsolatedExecutor.SerializableRunnable[]{run}, check, iterations);
359391
}
360392

361393
public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables,
362394
IIsolatedExecutor.SerializableRunnable check)
363395
{
364-
simulate(runnables, check, System.currentTimeMillis());
396+
simulate(runnables, check, 1);
397+
}
398+
399+
public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables,
400+
IIsolatedExecutor.SerializableRunnable check,
401+
int iterations)
402+
{
403+
long seed = System.currentTimeMillis();
404+
for (int i = 0; i < iterations; i++)
405+
{
406+
long currentSeed = seed + i;
407+
System.out.printf("Running iteration %d of %d with seed %dL%n", i + 1, iterations, currentSeed);
408+
simulate(runnables, check, currentSeed);
409+
}
365410
}
366411

367412
public static void simulate(IIsolatedExecutor.SerializableRunnable[] runnables,

0 commit comments

Comments
 (0)