From 889ae2cd780b08720feef6a01051275b5e3f7546 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 2 Oct 2025 19:09:09 +0530 Subject: [PATCH 1/4] Remove log and env_logger in favor of tracing - Deleted `log` and `env_logger` from simulator dependencies - Migrated remaining `log::error!` and `log::trace!` calls to `tracing` macros --- Cargo.lock | 2 -- simulator/Cargo.toml | 2 -- simulator/generation/plan.rs | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8af968be4..cbfe78d9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2351,13 +2351,11 @@ dependencies = [ "clap", "dirs 6.0.0", "either", - "env_logger 0.11.7", "garde", "hex", "indexmap 2.11.1", "itertools 0.14.0", "json5", - "log", "notify", "parking_lot", "rand 0.9.2", diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index a5d4daba8..09401f2cc 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -18,8 +18,6 @@ path = "main.rs" turso_core = { workspace = true, features = ["simulator"]} rand = { workspace = true } rand_chacha = { workspace = true } -log = "0.4.20" -env_logger = { workspace = true } regex = { workspace = true } regex-syntax = { workspace = true, default-features = false, features = [ "unicode", diff --git a/simulator/generation/plan.rs b/simulator/generation/plan.rs index 1f164a01d..3c07d73e3 100644 --- a/simulator/generation/plan.rs +++ b/simulator/generation/plan.rs @@ -21,6 +21,7 @@ use sql_generation::{ table::SimValue, }, }; +use tracing::error; use turso_core::{Connection, Result, StepResult}; use crate::{ @@ -121,7 +122,7 @@ impl InteractionPlan { let _ = plan[j].split_off(k); break; } - log::error!("Comparing '{}' with '{}'", interactions[i], plan[j][k]); + error!("Comparing '{}' with '{}'", interactions[i], plan[j][k]); if interactions[i].contains(plan[j][k].to_string().as_str()) { i += 1; k += 1; From 460b87fdfb25217d3e4eaf9c7abe464a5e73add4 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 2 Oct 2025 19:09:56 +0530 Subject: [PATCH 2/4] Refactor simulator logger initialization - Changed `init_logger()` to return `anyhow::Result<()>` - Removed deprecated usage of `with_ansi` --- simulator/main.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/simulator/main.rs b/simulator/main.rs index ec63062ea..369bf94ad 100644 --- a/simulator/main.rs +++ b/simulator/main.rs @@ -34,7 +34,7 @@ mod runner; mod shrink; fn main() -> anyhow::Result<()> { - init_logger(); + init_logger()?; let mut cli_opts = SimulatorCLI::parse(); cli_opts.validate()?; @@ -622,17 +622,16 @@ fn run_simulation_default( result } -fn init_logger() { +fn init_logger() -> anyhow::Result<()> { let file = OpenOptions::new() .create(true) .write(true) .truncate(true) - .open("simulator.log") - .unwrap(); + .open("simulator.log")?; let requires_ansi = std::io::stdout().is_terminal(); - let _ = tracing_subscriber::registry() + tracing_subscriber::registry() .with( tracing_subscriber::fmt::layer() .with_ansi(requires_ansi) @@ -642,17 +641,17 @@ fn init_logger() { ) .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"))) .with( - #[allow(deprecated)] tracing_subscriber::fmt::layer() .with_writer(file) .with_ansi(false) - .fmt_fields(format::PrettyFields::new().with_ansi(false)) // with_ansi is deprecated, but I cannot find another way to remove ansi codes + .fmt_fields(format::PrettyFields::new()) .with_line_number(true) .without_time() .with_thread_ids(false) .map_fmt_fields(|f| f.debug_alt()), ) - .try_init(); + .try_init()?; + Ok(()) } fn banner() { From 46fab876347938b42a6a9831281a29577018674e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 2 Oct 2025 19:12:46 +0530 Subject: [PATCH 3/4] Replaced manual validation in `SimulatorCLI::validate` with Clap features: - Added `conflicts_with` for mutually exclusive flags - Removed redundant default values for bool flags. - Dropped manual validation checks in favor of Clap's built-in parsing guarantees. --- simulator/profiles/io.rs | 2 +- simulator/runner/cli.rs | 71 ++++++++++++--------------------- simulator/runner/env.rs | 5 ++- simulator/runner/file.rs | 2 +- simulator/runner/io.rs | 4 +- simulator/runner/memory/file.rs | 4 +- simulator/runner/memory/io.rs | 4 +- 7 files changed, 37 insertions(+), 55 deletions(-) diff --git a/simulator/profiles/io.rs b/simulator/profiles/io.rs index 4bf44683a..cf7e8885a 100644 --- a/simulator/profiles/io.rs +++ b/simulator/profiles/io.rs @@ -33,7 +33,7 @@ pub struct LatencyProfile { pub enable: bool, #[garde(range(min = 0, max = 100))] /// Added IO latency probability - pub latency_probability: usize, + pub latency_probability: u8, #[garde(custom(max_dependent(&self.max_tick)))] /// Minimum tick time in microseconds for simulated time pub min_tick: u64, diff --git a/simulator/runner/cli.rs b/simulator/runner/cli.rs index 1db597223..c1b8b52ba 100644 --- a/simulator/runner/cli.rs +++ b/simulator/runner/cli.rs @@ -12,28 +12,31 @@ use crate::profiles::ProfileType; #[command(name = "limbo-simulator")] #[command(author, version, about, long_about = None)] pub struct SimulatorCLI { - #[clap(short, long, help = "set seed for reproducible runs", default_value = None)] + #[clap(short, long, help = "set seed for reproducible runs", conflicts_with = "load")] pub seed: Option, #[clap( short, long, - help = "enable doublechecking, run the simulator with the plan twice and check output equality" + help = "enable doublechecking, run the simulator with the plan twice and check output equality", + conflicts_with = "differential" )] pub doublecheck: bool, #[clap( short = 'n', long, help = "change the maximum size of the randomly generated sequence of interactions", - default_value_t = 5000 + default_value_t = 5000, + value_parser = clap::value_parser!(u32).range(1..) )] - pub maximum_tests: usize, + pub maximum_tests: u32, #[clap( short = 'k', long, help = "change the minimum size of the randomly generated sequence of interactions", - default_value_t = 1000 + default_value_t = 1000, + value_parser = clap::value_parser!(u32).range(1..) )] - pub minimum_tests: usize, + pub minimum_tests: u32, #[clap( short = 't', long, @@ -41,7 +44,7 @@ pub struct SimulatorCLI { default_value_t = 60 * 60 // default to 1 hour )] pub maximum_time: usize, - #[clap(short = 'l', long, help = "load plan from the bug base")] + #[clap(short = 'l', long, help = "load plan from the bug base", conflicts_with = "seed")] pub load: Option, #[clap( short = 'w', @@ -49,7 +52,7 @@ pub struct SimulatorCLI { help = "enable watch mode that reruns the simulation on file changes" )] pub watch: bool, - #[clap(long, help = "run differential testing between sqlite and Limbo")] + #[clap(long, help = "run differential testing between sqlite and Limbo", conflicts_with = "doublecheck")] pub differential: bool, #[clap( long, @@ -58,19 +61,19 @@ pub struct SimulatorCLI { pub enable_brute_force_shrinking: bool, #[clap(subcommand)] pub subcommand: Option, - #[clap(long, help = "disable BugBase", default_value_t = false)] + #[clap(long, help = "disable BugBase")] pub disable_bugbase: bool, - #[clap(long, help = "disable heuristic shrinking", default_value_t = false)] + #[clap(long, help = "disable heuristic shrinking")] pub disable_heuristic_shrinking: bool, - #[clap(long, help = "disable UPDATE Statement", default_value_t = false)] + #[clap(long, help = "disable UPDATE Statement")] pub disable_update: bool, - #[clap(long, help = "disable DELETE Statement", default_value_t = false)] + #[clap(long, help = "disable DELETE Statement")] pub disable_delete: bool, - #[clap(long, help = "disable CREATE Statement", default_value_t = false)] + #[clap(long, help = "disable CREATE Statement")] pub disable_create: bool, - #[clap(long, help = "disable CREATE INDEX Statement", default_value_t = false)] + #[clap(long, help = "disable CREATE INDEX Statement")] pub disable_create_index: bool, - #[clap(long, help = "disable DROP Statement", default_value_t = false)] + #[clap(long, help = "disable DROP Statement")] pub disable_drop: bool, #[clap( long, @@ -84,11 +87,11 @@ pub struct SimulatorCLI { default_value_t = false )] pub disable_double_create_failure: bool, - #[clap(long, help = "disable Select-Limit Property", default_value_t = false)] + #[clap(long, help = "disable Select-Limit Property")] pub disable_select_limit: bool, - #[clap(long, help = "disable Delete-Select Property", default_value_t = false)] + #[clap(long, help = "disable Delete-Select Property")] pub disable_delete_select: bool, - #[clap(long, help = "disable Drop-Select Property", default_value_t = false)] + #[clap(long, help = "disable Drop-Select Property")] pub disable_drop_select: bool, #[clap( long, @@ -110,12 +113,12 @@ pub struct SimulatorCLI { pub disable_union_all_preserves_cardinality: bool, #[clap(long, help = "disable FsyncNoWait Property", default_value_t = true)] pub disable_fsync_no_wait: bool, - #[clap(long, help = "disable FaultyQuery Property", default_value_t = false)] + #[clap(long, help = "disable FaultyQuery Property")] pub disable_faulty_query: bool, - #[clap(long, help = "disable Reopen-Database fault", default_value_t = false)] + #[clap(long, help = "disable Reopen-Database fault")] pub disable_reopen_database: bool, - #[clap(long = "latency-prob", help = "added IO latency probability")] - pub latency_probability: Option, + #[clap(long = "latency-prob", help = "added IO latency probability", value_parser = clap::value_parser!(u8).range(0..=100))] + pub latency_probability: Option, #[clap(long, help = "Minimum tick time in microseconds for simulated time")] pub min_tick: Option, #[clap(long, help = "Maximum tick time in microseconds for simulated time")] @@ -177,13 +180,6 @@ pub enum SimulatorCommand { impl SimulatorCLI { pub fn validate(&mut self) -> anyhow::Result<()> { - if self.minimum_tests < 1 { - anyhow::bail!("minimum size must be at least 1"); - } - if self.maximum_tests < 1 { - anyhow::bail!("maximum size must be at least 1"); - } - if self.minimum_tests > self.maximum_tests { tracing::warn!( "minimum size '{}' is greater than '{}' maximum size, setting both to '{}'", @@ -191,22 +187,7 @@ impl SimulatorCLI { self.maximum_tests, self.maximum_tests ); - self.minimum_tests = self.maximum_tests - 1; - } - - if self.seed.is_some() && self.load.is_some() { - anyhow::bail!("Cannot set seed and load plan at the same time"); - } - - if self.latency_probability.is_some_and(|prob| prob > 100) { - anyhow::bail!( - "latency probability must be a number between 0 and 100. Got `{}`", - self.latency_probability.unwrap() - ); - } - - if self.doublecheck && self.differential { - anyhow::bail!("Cannot run doublecheck and differential testing at the same time"); + self.minimum_tests = self.maximum_tests; } Ok(()) diff --git a/simulator/runner/env.rs b/simulator/runner/env.rs index 9a23663b0..383dc9ad9 100644 --- a/simulator/runner/env.rs +++ b/simulator/runner/env.rs @@ -12,6 +12,7 @@ use rand_chacha::ChaCha8Rng; use sql_generation::generation::GenerationContext; use sql_generation::model::query::transaction::Rollback; use sql_generation::model::table::Table; +use tracing::trace; use turso_core::Database; use crate::generation::Shadow; @@ -297,7 +298,7 @@ impl SimulatorEnv { let mut opts = SimulatorOpts { seed, - ticks: rng.random_range(cli_opts.minimum_tests..=cli_opts.maximum_tests), + ticks: rng.random_range(cli_opts.minimum_tests as usize..=cli_opts.maximum_tests as usize), max_tables: rng.random_range(0..128), disable_select_optimizer: cli_opts.disable_select_optimizer, disable_insert_values_select: cli_opts.disable_insert_values_select, @@ -418,7 +419,7 @@ impl SimulatorEnv { } if self.connections[connection_index].is_connected() { - log::trace!( + trace!( "Connection {connection_index} is already connected, skipping reconnection" ); return; diff --git a/simulator/runner/file.rs b/simulator/runner/file.rs index 635de2bd2..96507a2e2 100644 --- a/simulator/runner/file.rs +++ b/simulator/runner/file.rs @@ -37,7 +37,7 @@ pub(crate) struct SimulatorFile { pub(crate) rng: RefCell, - pub latency_probability: usize, + pub latency_probability: u8, pub sync_completion: RefCell>, pub queued_io: RefCell>, diff --git a/simulator/runner/io.rs b/simulator/runner/io.rs index 63c350ae2..8eccd470a 100644 --- a/simulator/runner/io.rs +++ b/simulator/runner/io.rs @@ -16,7 +16,7 @@ pub(crate) struct SimulatorIO { pub(crate) rng: RefCell, pub(crate) page_size: usize, seed: u64, - latency_probability: usize, + latency_probability: u8, clock: Arc, } @@ -27,7 +27,7 @@ impl SimulatorIO { pub(crate) fn new( seed: u64, page_size: usize, - latency_probability: usize, + latency_probability: u8, min_tick: u64, max_tick: u64, ) -> Result { diff --git a/simulator/runner/memory/file.rs b/simulator/runner/memory/file.rs index e40fdfbb3..395597a8c 100644 --- a/simulator/runner/memory/file.rs +++ b/simulator/runner/memory/file.rs @@ -52,7 +52,7 @@ pub struct MemorySimFile { pub closed: Cell, io_tracker: RefCell, pub rng: RefCell, - pub latency_probability: usize, + pub latency_probability: u8, clock: Arc, fault: Cell, } @@ -65,7 +65,7 @@ impl MemorySimFile { callbacks: CallbackQueue, fd: Fd, seed: u64, - latency_probability: usize, + latency_probability: u8, clock: Arc, ) -> Self { Self { diff --git a/simulator/runner/memory/io.rs b/simulator/runner/memory/io.rs index 124ff2caf..007398a10 100644 --- a/simulator/runner/memory/io.rs +++ b/simulator/runner/memory/io.rs @@ -124,7 +124,7 @@ pub struct MemorySimIO { pub nr_run_once_faults: Cell, pub page_size: usize, seed: u64, - latency_probability: usize, + latency_probability: u8, clock: Arc, } @@ -135,7 +135,7 @@ impl MemorySimIO { pub fn new( seed: u64, page_size: usize, - latency_probability: usize, + latency_probability: u8, min_tick: u64, max_tick: u64, ) -> Self { From ff381c103677ec9108778547c42ad6fecc89617d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 2 Oct 2025 19:30:57 +0530 Subject: [PATCH 4/4] clippy'ed --- simulator/runner/cli.rs | 20 +++++++++++++++++--- simulator/runner/env.rs | 10 ++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/simulator/runner/cli.rs b/simulator/runner/cli.rs index c1b8b52ba..6dec4b46d 100644 --- a/simulator/runner/cli.rs +++ b/simulator/runner/cli.rs @@ -12,7 +12,12 @@ use crate::profiles::ProfileType; #[command(name = "limbo-simulator")] #[command(author, version, about, long_about = None)] pub struct SimulatorCLI { - #[clap(short, long, help = "set seed for reproducible runs", conflicts_with = "load")] + #[clap( + short, + long, + help = "set seed for reproducible runs", + conflicts_with = "load" + )] pub seed: Option, #[clap( short, @@ -44,7 +49,12 @@ pub struct SimulatorCLI { default_value_t = 60 * 60 // default to 1 hour )] pub maximum_time: usize, - #[clap(short = 'l', long, help = "load plan from the bug base", conflicts_with = "seed")] + #[clap( + short = 'l', + long, + help = "load plan from the bug base", + conflicts_with = "seed" + )] pub load: Option, #[clap( short = 'w', @@ -52,7 +62,11 @@ pub struct SimulatorCLI { help = "enable watch mode that reruns the simulation on file changes" )] pub watch: bool, - #[clap(long, help = "run differential testing between sqlite and Limbo", conflicts_with = "doublecheck")] + #[clap( + long, + help = "run differential testing between sqlite and Limbo", + conflicts_with = "doublecheck" + )] pub differential: bool, #[clap( long, diff --git a/simulator/runner/env.rs b/simulator/runner/env.rs index 383dc9ad9..52b57052a 100644 --- a/simulator/runner/env.rs +++ b/simulator/runner/env.rs @@ -298,7 +298,8 @@ impl SimulatorEnv { let mut opts = SimulatorOpts { seed, - ticks: rng.random_range(cli_opts.minimum_tests as usize..=cli_opts.maximum_tests as usize), + ticks: rng + .random_range(cli_opts.minimum_tests as usize..=cli_opts.maximum_tests as usize), max_tables: rng.random_range(0..128), disable_select_optimizer: cli_opts.disable_select_optimizer, disable_insert_values_select: cli_opts.disable_insert_values_select, @@ -312,8 +313,7 @@ impl SimulatorEnv { disable_fsync_no_wait: cli_opts.disable_fsync_no_wait, disable_faulty_query: cli_opts.disable_faulty_query, page_size: 4096, // TODO: randomize this too - max_interactions: rng.random_range(cli_opts.minimum_tests..=cli_opts.maximum_tests) - as u32, + max_interactions: rng.random_range(cli_opts.minimum_tests..=cli_opts.maximum_tests), max_time_simulation: cli_opts.maximum_time, disable_reopen_database: cli_opts.disable_reopen_database, }; @@ -419,9 +419,7 @@ impl SimulatorEnv { } if self.connections[connection_index].is_connected() { - trace!( - "Connection {connection_index} is already connected, skipping reconnection" - ); + trace!("Connection {connection_index} is already connected, skipping reconnection"); return; }