Fix ShortPaxosSimulationTest and AccordSimulationRunner do not execute from the cli

patch by Maxim Muzafarov; reviewed by Ariel Weisberg for CASSANDRA-20805
This commit is contained in:
Maxim Muzafarov 2025-07-31 00:14:46 +02:00
parent b2037e473f
commit ca1dca902c
No known key found for this signature in database
GPG Key ID: 7FEC714D84388C16
10 changed files with 100 additions and 50 deletions

View File

@ -1,4 +1,5 @@
5.1
* Fix ShortPaxosSimulationTest and AccordSimulationRunner do not execute from the cli (CASSANDRA-20805)
* Allow overriding arbitrary settings via environment variables (CASSANDRA-20749)
* Optimize MessagingService.getVersionOrdinal (CASSANDRA-20816)
* Optimize TrieMemtable#getFlushSet (CASSANDRA-20760)

View File

@ -498,6 +498,8 @@ public class SimulationRunner
public static void checkArgumentAllowed(List<Integer> values, int... allowed)
{
if (values == null || values.isEmpty())
return;
values.forEach(v -> checkArgumentAllowed(v, allowed));
}

View File

@ -21,15 +21,17 @@ package org.apache.cassandra.simulator;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import io.netty.util.concurrent.FastThreadLocal;
import org.apache.cassandra.utils.concurrent.Threads;
import picocli.CommandLine;
public class SimulatorUtils
{
@ -51,12 +53,12 @@ public class SimulatorUtils
FastThreadLocal.destroy();
}
public static void verifyAndlogSimulatorArgs(String[] args)
private static void verifyAndlogSimulatorArgs(List<String> args)
{
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
final List<String> jvmArgs = runtimeMxBean.getInputArguments();
System.err.printf("JVM Args: %s%n", jvmArgs.stream().collect(Collectors.joining("\" \"", "\"", "\"")));
System.err.printf("Command Args: %s%n", Arrays.stream(args).collect(Collectors.joining("\" \"", "\"", "\"")));
System.err.printf("Command Args: %s%n", args.stream().collect(Collectors.joining("\" \"", "\"", "\"")));
assert jvmArgs.stream().anyMatch(arg -> arg.startsWith("-Xbootclasspath/a") && arg.endsWith("simulator-bootstrap.jar")) :
"must launch JVM with -Xbootclasspath/a:simulator-bootstrap.jar";
@ -81,4 +83,30 @@ public class SimulatorUtils
if (!jvmArgs.stream().anyMatch(arg -> arg.equals("-Dcassandra.simulator.skiplog4jreload=true")))
System.err.println("JVM Argument -Dcassandra.simulator.skiplog4jreload=true not set, non-determinism possible");
}
public static CommandLine prepareRunner(Object command, CommandLine.IFactory factory, Consumer<Exception> exceptionHandler)
{
CommandLine cli = new CommandLine(command, factory);
cli.setExecutionStrategy(parseResult -> {
verifyAndlogSimulatorArgs(parseResult.originalArgs());
return new CommandLine.RunLast().execute(parseResult);
});
return exceptionHandler == null ? cli :
cli.setExecutionExceptionHandler((ex, commandLine, fullParseResult) -> {
if (ex != null) exceptionHandler.accept(ex);
return commandLine.getCommandSpec().exitCodeOnExecutionException();
});
}
public static void executeWithExceptionThrowing(Object command, CommandLine.IFactory factory, String[] args)
{
AtomicReference<Exception> cause = new AtomicReference<>();
int exitCode;
if ((exitCode = prepareRunner(command, factory, cause::set).execute(args)) == 0)
return;
if (cause.get() == null)
throw new RuntimeException("Simulation failed with exit code: " + exitCode);
else
throw new RuntimeException("Simulation failed with exit code: " + exitCode, cause.get());
}
}

View File

@ -33,7 +33,6 @@ import picocli.CommandLine.Command;
@Command(name = "accord",
description = "Run an Accord simulation",
helpCommand = true,
subcommands = { CommandLine.HelpCommand.class,
AccordSimulationRunner.Run.class,
AccordSimulationRunner.Record.class,
@ -94,16 +93,22 @@ public class AccordSimulationRunner extends SimulationRunner
// for simple unit tests so we can simply invoke main()
private static final AtomicInteger uniqueNum = new AtomicInteger();
private static CommandLine.IFactory simulationFactory()
{
return new PaxosSimulationRunner.InjectPaxosClusterSimulationFactory(new AccordClusterSimulation.Builder()
.unique(uniqueNum.getAndIncrement()));
}
public static void executeWithExceptionThrowing(String[] args)
{
SimulatorUtils.executeWithExceptionThrowing(AccordSimulationRunner.class, simulationFactory(), args);
}
/**
* See {@link org.apache.cassandra.simulator} package info for execution tips
*/
public static void main(String[] args) throws IOException
{
SimulatorUtils.verifyAndlogSimulatorArgs(args);
AccordClusterSimulation.Builder builder = new AccordClusterSimulation.Builder();
builder.unique(uniqueNum.getAndIncrement());
CommandLine commandLine = new CommandLine(AccordSimulationRunner.class, new PaxosSimulationRunner.InjectPaxosClusterSimulationFactory(builder));
commandLine.execute(args);
System.exit(SimulatorUtils.prepareRunner(AccordSimulationRunner.class, simulationFactory(), null).execute(args));
}
}

View File

@ -22,7 +22,6 @@ import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject;
import org.apache.cassandra.config.Config;
@ -30,14 +29,12 @@ import org.apache.cassandra.distributed.api.ConsistencyLevel;
import org.apache.cassandra.simulator.ClusterSimulation;
import org.apache.cassandra.simulator.SimulationRunner;
import org.apache.cassandra.simulator.SimulatorUtils;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "paxos",
description = "Run a paxos simulation",
helpCommand = true,
subcommands = { CommandLine.HelpCommand.class,
PaxosSimulationRunner.Run.class,
PaxosSimulationRunner.VersionCommand.class,
@ -201,16 +198,22 @@ public class PaxosSimulationRunner extends SimulationRunner implements Runnable
}
}
private static CommandLine.IFactory simulationFactory()
{
return new InjectPaxosClusterSimulationFactory(new PaxosClusterSimulation.Builder()
.unique(uniqueNum.getAndIncrement()));
}
public static void executeWithExceptionThrowing(String[] args)
{
SimulatorUtils.executeWithExceptionThrowing(PaxosSimulationRunner.class, simulationFactory(), args);
}
/**
* See {@link org.apache.cassandra.simulator} package info for execution tips
*/
public static void main(String[] args) throws IOException
{
SimulatorUtils.verifyAndlogSimulatorArgs(args);
PaxosClusterSimulation.Builder builder = new PaxosClusterSimulation.Builder();
builder.unique(uniqueNum.getAndIncrement());
CommandLine commandLine = new CommandLine(PaxosSimulationRunner.class, new InjectPaxosClusterSimulationFactory(builder));
commandLine.execute(args);
System.exit(SimulatorUtils.prepareRunner(PaxosSimulationRunner.class, simulationFactory(), null).execute(args));
}
}

View File

@ -49,7 +49,7 @@ import static org.apache.cassandra.simulator.RandomSource.Choices.uniform;
// TODO (cleanup): when we encounter an exception and unwind the simulation, we should restore normal time to go with normal waits etc.
public class SimulatedTime
{
private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile)[-:][0-9]+");
private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile)[-:][0-9]+|RMI Scheduler\\(\\d+\\)");
@Shared(scope = Shared.Scope.SIMULATION)
public interface Listener

View File

@ -18,8 +18,6 @@
package org.apache.cassandra.simulator.test;
import java.io.IOException;
import org.junit.Test;
import org.apache.cassandra.simulator.paxos.AccordSimulationRunner;
@ -94,8 +92,13 @@ import org.apache.cassandra.simulator.paxos.AccordSimulationRunner;
public class ShortAccordSimulationTest
{
@Test
public void simulationTest() throws IOException
public void simulationTest()
{
AccordSimulationRunner.main(new String[] { "run", "-n", "3..6", "-t", "1000", "--cluster-action-limit", "-1", "-c", "2", "-s", "30"});
AccordSimulationRunner.executeWithExceptionThrowing(new String[]{ "run",
"-n", "3..6",
"-t", "1000",
"--cluster-action-limit", "-1",
"-c", "2",
"-s", "30" });
}
}

View File

@ -18,8 +18,6 @@
package org.apache.cassandra.simulator.test;
import java.io.IOException;
import org.junit.Ignore;
import org.junit.Test;
@ -97,17 +95,17 @@ public class ShortPaxosMigrationFromAccordSimulationTest
{
@Test
@Ignore
public void casOnAccordSimulationTestAccordStart() throws IOException
public void casOnAccordSimulationTestAccordStart()
{
PaxosSimulationRunner.main(new String[] { "run",
"--transactional-mode", "full",
"--seed", "0x2b091cc62b96a2eb",
"-n", "3..6",
"-t", "1000",
"--cluster-action-limit", "-1",
"--consensus-action-limit", "1",
"--consensus-actions", "ACCORD_MIGRATE",
"-c", "2"});
PaxosSimulationRunner.executeWithExceptionThrowing(new String[]{ "run",
"--transactional-mode", "full",
"--seed", "0x2b091cc62b96a2eb",
"-n", "3..6",
"-t", "1000",
"--cluster-action-limit", "-1",
"--consensus-action-limit", "1",
"--consensus-actions", "ACCORD_MIGRATE",
"-c", "2" });
}
}

View File

@ -98,14 +98,14 @@ public class ShortPaxosMigrationToAccordSimulationTest
@Ignore
public void casOnAccordSimulationTestPaxosStart() throws IOException
{
PaxosSimulationRunner.main(new String[] { "run",
"--transactional-mode", "off",
"-n", "3..6",
"-t", "1000",
"--cluster-action-limit", "-1",
"--consensus-action-limit", "1",
"--consensus-actions", "ACCORD_MIGRATE",
"-c", "2"});
PaxosSimulationRunner.executeWithExceptionThrowing(new String[]{ "run",
"--transactional-mode", "off",
"-n", "3..6",
"-t", "1000",
"--cluster-action-limit", "-1",
"--consensus-action-limit", "1",
"--consensus-actions", "ACCORD_MIGRATE",
"-c", "2" });
}
}

View File

@ -18,8 +18,6 @@
package org.apache.cassandra.simulator.test;
import java.io.IOException;
import org.junit.Ignore;
import org.junit.Test;
@ -95,16 +93,28 @@ import org.apache.cassandra.simulator.paxos.PaxosSimulationRunner;
public class ShortPaxosSimulationTest
{
@Test
public void simulationTest() throws IOException
public void simulationTest()
{
PaxosSimulationRunner.main(new String[] { "run", "--variant", "v2", "-n", "3..6", "-t", "1000", "-c", "2", "--cluster-action-limit", "2", "-s", "30" });
PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "run",
"--variant", "v2",
"-n", "3..6",
"-t", "1000",
"-c", "2",
"--cluster-action-limit", "2",
"-s", "30" });
}
@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" });
PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "reconcile",
"-n", "3..6",
"-t", "1000",
"-c", "2",
"--cluster-action-limit", "2",
"-s", "30",
"--with-self" });
}
}