read Profile file from path or use predefined profiles

This commit is contained in:
pedrocarlo
2025-08-28 12:33:37 -03:00
parent a1407869d4
commit 962666831b
20 changed files with 350 additions and 69 deletions

74
Cargo.lock generated
View File

@@ -2000,6 +2000,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]]
name = "julian_day_converter"
version = "0.4.5"
@@ -2182,6 +2193,7 @@ dependencies = [
"garde",
"hex",
"itertools 0.14.0",
"json5",
"log",
"notify",
"rand 0.9.2",
@@ -2193,6 +2205,7 @@ dependencies = [
"serde",
"serde_json",
"sql_generation",
"strum",
"tracing",
"tracing-subscriber",
"turso_core",
@@ -2690,6 +2703,50 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pest"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
dependencies = [
"memchr",
"thiserror 2.0.12",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "pest_meta"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
dependencies = [
"pest",
"sha2",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
@@ -3530,6 +3587,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -4374,6 +4442,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "ucd-trie"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
name = "uncased"
version = "0.9.10"

1
simulator/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
configs/custom

View File

@@ -4,7 +4,7 @@
name = "limbo_sim"
version.workspace = true
authors.workspace = true
edition.workspace = true
edition = "2024"
license.workspace = true
repository.workspace = true
description = "The Limbo deterministic simulator"
@@ -40,3 +40,5 @@ sql_generation = { workspace = true }
turso_parser = { workspace = true }
schemars = { workspace = true }
garde = { workspace = true, features = ["derive", "serde"] }
json5 = { version = "0.4.1" }
strum = { workspace = true }

View File

@@ -26,7 +26,7 @@ impl GenerationContext for SimulatorEnv {
}
fn opts(&self) -> &sql_generation::generation::Opts {
&self.gen_opts
&self.profile.query.gen_opts
}
}
@@ -36,6 +36,6 @@ impl GenerationContext for &mut SimulatorEnv {
}
fn opts(&self) -> &sql_generation::generation::Opts {
&self.gen_opts
&self.profile.query.gen_opts
}
}

View File

@@ -9,25 +9,25 @@ use std::{
use serde::{Deserialize, Serialize};
use sql_generation::{
generation::{frequency, query::SelectFree, Arbitrary, ArbitraryFrom, GenerationContext},
generation::{Arbitrary, ArbitraryFrom, GenerationContext, frequency, query::SelectFree},
model::{
query::{update::Update, Create, CreateIndex, Delete, Drop, Insert, Select},
query::{Create, CreateIndex, Delete, Drop, Insert, Select, update::Update},
table::SimValue,
},
};
use turso_core::{Connection, Result, StepResult};
use crate::{
SimulatorEnv,
generation::Shadow,
model::Query,
runner::{
env::{SimConnection, SimulationType, SimulatorTables},
io::SimulatorIO,
},
SimulatorEnv,
};
use super::property::{remaining, Property};
use super::property::{Property, remaining};
pub(crate) type ResultSet = Result<Vec<Vec<SimValue>>>;

View File

@@ -1,18 +1,18 @@
use serde::{Deserialize, Serialize};
use sql_generation::{
generation::{frequency, pick, pick_index, Arbitrary, ArbitraryFrom, GenerationContext},
generation::{Arbitrary, ArbitraryFrom, GenerationContext, frequency, pick, pick_index},
model::{
query::{
Create, Delete, Drop, Insert, Select,
predicate::Predicate,
select::{CompoundOperator, CompoundSelect, ResultColumn, SelectBody, SelectInner},
transaction::{Begin, Commit, Rollback},
update::Update,
Create, Delete, Drop, Insert, Select,
},
table::SimValue,
},
};
use turso_core::{types, LimboError};
use turso_core::{LimboError, types};
use turso_parser::ast::{self, Distinctness};
use crate::{
@@ -305,7 +305,10 @@ impl Property {
for row in rows {
for (i, (col, val)) in update.set_values.iter().enumerate() {
if &row[i] != val {
return Ok(Err(format!("updated row {} has incorrect value for column {col}: expected {val}, got {}", i, row[i])));
return Ok(Err(format!(
"updated row {} has incorrect value for column {col}: expected {val}, got {}",
i, row[i]
)));
}
}
}
@@ -384,7 +387,10 @@ impl Property {
if found {
Ok(Ok(()))
} else {
Ok(Err(format!("row [{:?}] not found in table", row.iter().map(|v| v.to_string()).collect::<Vec<String>>())))
Ok(Err(format!(
"row [{:?}] not found in table",
row.iter().map(|v| v.to_string()).collect::<Vec<String>>()
)))
}
}
Err(err) => Err(LimboError::InternalError(err.to_string())),
@@ -858,15 +864,22 @@ impl Property {
match (select_result_set, select_tlp_result_set) {
(Ok(select_rows), Ok(select_tlp_rows)) => {
if select_rows.len() != select_tlp_rows.len() {
return Ok(Err(format!("row count mismatch: select returned {} rows, select_tlp returned {} rows", select_rows.len(), select_tlp_rows.len())));
return Ok(Err(format!(
"row count mismatch: select returned {} rows, select_tlp returned {} rows",
select_rows.len(),
select_tlp_rows.len()
)));
}
// Check if any row in select_rows is not in select_tlp_rows
for row in select_rows.iter() {
if !select_tlp_rows.iter().any(|r| r == row) {
tracing::debug!(
"select and select_tlp returned different rows, ({}) is in select but not in select_tlp",
row.iter().map(|v| v.to_string()).collect::<Vec<String>>().join(", ")
);
"select and select_tlp returned different rows, ({}) is in select but not in select_tlp",
row.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(", ")
);
return Ok(Err(format!(
"row mismatch: row [{}] exists in select results but not in select_tlp results",
print_row(row)
@@ -877,9 +890,12 @@ impl Property {
for row in select_tlp_rows.iter() {
if !select_rows.iter().any(|r| r == row) {
tracing::debug!(
"select and select_tlp returned different rows, ({}) is in select_tlp but not in select",
row.iter().map(|v| v.to_string()).collect::<Vec<String>>().join(", ")
);
"select and select_tlp returned different rows, ({}) is in select_tlp but not in select",
row.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(", ")
);
return Ok(Err(format!(
"row mismatch: row [{}] exists in select_tlp but not in select",
@@ -939,7 +955,9 @@ impl Property {
if union_count == count1 + count2 {
Ok(Ok(()))
} else {
Ok(Err(format!("UNION ALL should preserve cardinality but it didn't: {count1} + {count2} != {union_count}")))
Ok(Err(format!(
"UNION ALL should preserve cardinality but it didn't: {count1} + {count2} != {union_count}"
)))
}
}
(Err(e), _, _) | (_, Err(e), _) | (_, _, Err(e)) => {

View File

@@ -1,8 +1,8 @@
use crate::model::Query;
use rand::Rng;
use sql_generation::{
generation::{frequency, Arbitrary, ArbitraryFrom, GenerationContext},
model::query::{update::Update, Create, Delete, Insert, Select},
generation::{Arbitrary, ArbitraryFrom, GenerationContext, frequency},
model::query::{Create, Delete, Insert, Select, update::Update},
};
use super::property::Remaining;

View File

@@ -8,19 +8,20 @@ use rand::prelude::*;
use runner::bugbase::{Bug, BugBase, LoadedBug};
use runner::cli::{SimulatorCLI, SimulatorCommand};
use runner::env::SimulatorEnv;
use runner::execution::{execute_plans, Execution, ExecutionHistory, ExecutionResult};
use runner::execution::{Execution, ExecutionHistory, ExecutionResult, execute_plans};
use runner::{differential, watch};
use std::any::Any;
use std::backtrace::Backtrace;
use std::fs::OpenOptions;
use std::io::{IsTerminal, Write};
use std::path::Path;
use std::sync::{mpsc, Arc, Mutex};
use std::sync::{Arc, Mutex, mpsc};
use tracing_subscriber::EnvFilter;
use tracing_subscriber::field::MakeExt;
use tracing_subscriber::fmt::format;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use crate::profiles::Profile;
use crate::runner::doublecheck;
use crate::runner::env::{Paths, SimulationPhase, SimulationType};
@@ -35,6 +36,10 @@ fn main() -> anyhow::Result<()> {
let mut cli_opts = SimulatorCLI::parse();
cli_opts.validate()?;
let profile = Profile::parse_from_type(cli_opts.profile.clone())?;
tracing::debug!(sim_profile = ?profile);
dbg!(&profile);
match cli_opts.subcommand {
Some(SimulatorCommand::List) => {
let mut bugbase = BugBase::load()?;
@@ -44,7 +49,7 @@ fn main() -> anyhow::Result<()> {
banner();
for i in 0..n {
println!("iteration {i}");
let result = testing_main(&cli_opts);
let result = testing_main(&cli_opts, &profile);
if result.is_err() && short_circuit {
println!("short circuiting after {i} iterations");
return result;
@@ -91,7 +96,7 @@ fn main() -> anyhow::Result<()> {
let results = bugs
.into_iter()
.map(|cli_opts| testing_main(&cli_opts))
.map(|cli_opts| testing_main(&cli_opts, &profile))
.collect::<Vec<_>>();
let (successes, failures): (Vec<_>, Vec<_>) =
@@ -103,12 +108,12 @@ fn main() -> anyhow::Result<()> {
}
None => {
banner();
testing_main(&cli_opts)
testing_main(&cli_opts, &profile)
}
}
}
fn testing_main(cli_opts: &SimulatorCLI) -> anyhow::Result<()> {
fn testing_main(cli_opts: &SimulatorCLI, profile: &Profile) -> anyhow::Result<()> {
let mut bugbase = if cli_opts.disable_bugbase {
None
} else {
@@ -116,7 +121,7 @@ fn testing_main(cli_opts: &SimulatorCLI) -> anyhow::Result<()> {
Some(BugBase::load()?)
};
let (seed, mut env, plans) = setup_simulation(bugbase.as_mut(), cli_opts);
let (seed, mut env, plans) = setup_simulation(bugbase.as_mut(), cli_opts, profile);
if cli_opts.watch {
watch_mode(env).unwrap();
@@ -471,6 +476,7 @@ impl SandboxedResult {
fn setup_simulation(
bugbase: Option<&mut BugBase>,
cli_opts: &SimulatorCLI,
profile: &Profile,
) -> (u64, SimulatorEnv, Vec<InteractionPlan>) {
if let Some(seed) = &cli_opts.load {
let seed = seed.parse::<u64>().expect("seed should be a number");
@@ -484,7 +490,13 @@ fn setup_simulation(
if !paths.base.exists() {
std::fs::create_dir_all(&paths.base).unwrap();
}
let env = SimulatorEnv::new(bug.seed(), cli_opts, paths, SimulationType::Default);
let env = SimulatorEnv::new(
bug.seed(),
cli_opts,
paths,
SimulationType::Default,
profile,
);
let plan = match bug {
Bug::Loaded(LoadedBug { plan, .. }) => plan.clone(),
@@ -528,7 +540,7 @@ fn setup_simulation(
Paths::new(&dir)
};
let mut env = SimulatorEnv::new(seed, cli_opts, paths, SimulationType::Default);
let mut env = SimulatorEnv::new(seed, cli_opts, paths, SimulationType::Default, profile);
tracing::info!("Generating database interaction plan...");

View File

@@ -5,14 +5,14 @@ use itertools::Itertools;
use serde::{Deserialize, Serialize};
use sql_generation::model::{
query::{
Create, CreateIndex, Delete, Drop, EmptyContext, Insert, Select,
select::{CompoundOperator, FromClause, ResultColumn, SelectInner},
transaction::{Begin, Commit, Rollback},
update::Update,
Create, CreateIndex, Delete, Drop, EmptyContext, Insert, Select,
},
table::{JoinTable, JoinType, SimValue, Table, TableContext},
};
use turso_parser::ast::{fmt::ToTokens, Distinctness};
use turso_parser::ast::{Distinctness, fmt::ToTokens};
use crate::{generation::Shadow, runner::env::SimulatorTables};
@@ -282,10 +282,11 @@ impl Shadow for SelectInner {
Ok(join_table)
} else {
assert!(self
.columns
.iter()
.all(|col| matches!(col, ResultColumn::Expr(_))));
assert!(
self.columns
.iter()
.all(|col| matches!(col, ResultColumn::Expr(_)))
);
// If `WHERE` is false, just return an empty table
if !self.where_clause.test(&[], &Table::anonymous(vec![])) {

View File

@@ -1,8 +1,16 @@
use std::fmt::Display;
use std::{
fmt::Display,
fs,
path::{Path, PathBuf},
str::FromStr,
};
use anyhow::Context;
use garde::Validate;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sql_generation::generation::Opts;
use strum::EnumString;
use crate::profiles::{io::IOProfile, query::QueryProfile};
@@ -10,6 +18,7 @@ mod io;
mod query;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct Profile {
#[garde(skip)]
/// Experimental MVCC feature
@@ -30,6 +39,83 @@ impl Default for Profile {
}
}
impl Profile {
pub fn write_heavy() -> Self {
Profile {
query: QueryProfile {
gen_opts: Opts {
// TODO: in the future tweak blob size for bigger inserts
// TODO: increase number of rows increased as well
..Default::default()
},
delete: false,
update: false,
..Default::default()
},
..Default::default()
}
}
pub fn parse_from_type(profile_type: ProfileType) -> anyhow::Result<Self> {
let profile = match profile_type {
ProfileType::Default => Profile::default(),
ProfileType::WriteHeavy => Self::write_heavy(),
ProfileType::Custom(path) => {
Self::parse(path).with_context(|| "failed to parse JSON profile")?
}
};
Ok(profile)
}
// TODO: in the future handle extension and composability of profiles here
pub fn parse(path: impl AsRef<Path>) -> anyhow::Result<Self> {
let contents = fs::read_to_string(path)?;
// use json5 so we can support comments and trailing commas
let profile = json5::from_str(&contents)?;
Ok(profile)
}
}
#[derive(
Debug,
Default,
Clone,
Serialize,
Deserialize,
EnumString,
PartialEq,
Eq,
PartialOrd,
Ord,
strum::Display,
strum::VariantNames,
)]
#[serde(rename_all = "snake_case")]
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
pub enum ProfileType {
#[default]
Default,
WriteHeavy,
#[strum(disabled)]
Custom(PathBuf),
}
impl ProfileType {
pub fn parse(s: &str) -> anyhow::Result<Self> {
if let Ok(prof) = ProfileType::from_str(s) {
Ok(prof)
} else if let path = PathBuf::from(s)
&& path.exists()
{
Ok(ProfileType::Custom(path))
} else {
Err(anyhow::anyhow!(
"failed identifying predifined profile or custom profile path"
))
}
}
}
/// Minimum value of field is dependent on another field in the struct
fn min_dependent<T: PartialOrd + Display>(min: &T) -> impl FnOnce(&T, &()) -> garde::Result + '_ {
move |value, _| {

View File

@@ -6,7 +6,7 @@ use std::{
time::SystemTime,
};
use anyhow::{anyhow, Context};
use anyhow::{Context, anyhow};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

View File

@@ -1,6 +1,13 @@
use clap::{command, Parser};
use clap::{
Arg, Command, Error, Parser,
builder::{PossibleValue, TypedValueParser, ValueParserFactory},
command,
error::{ContextKind, ContextValue, ErrorKind},
};
use serde::{Deserialize, Serialize};
use crate::profiles::ProfileType;
#[derive(Parser, Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord)]
#[command(name = "limbo-simulator")]
#[command(author, version, about, long_about = None)]
@@ -135,6 +142,9 @@ pub struct SimulatorCLI {
default_value_t = false
)]
pub keep_files: bool,
#[clap(long, default_value_t = ProfileType::Default)]
/// Profile selector for Simulation run
pub profile: ProfileType,
}
#[derive(Parser, Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Ord)]
@@ -206,3 +216,70 @@ impl SimulatorCLI {
Ok(())
}
}
#[derive(Clone)]
pub struct ProfileTypeParser;
impl TypedValueParser for ProfileTypeParser {
type Value = ProfileType;
fn parse_ref(
&self,
cmd: &Command,
arg: Option<&Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, Error> {
let s = value
.to_str()
.ok_or_else(|| Error::new(ErrorKind::InvalidUtf8).with_cmd(cmd))?;
ProfileType::parse(s).map_err(|_| {
let mut err = Error::new(ErrorKind::InvalidValue).with_cmd(cmd);
if let Some(arg) = arg {
err.insert(
ContextKind::InvalidArg,
ContextValue::String(arg.to_string()),
);
}
err.insert(
ContextKind::InvalidValue,
ContextValue::String(s.to_string()),
);
err.insert(
ContextKind::ValidValue,
ContextValue::Strings(
self.possible_values()
.unwrap()
.map(|s| s.get_name().to_string())
.collect(),
),
);
err
})
}
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
use strum::VariantNames;
Some(Box::new(
Self::Value::VARIANTS
.into_iter()
.map(|variant| {
// Custom variant should be listed as a Custom path
if variant.eq_ignore_ascii_case("custom") {
"CUSTOM_PATH"
} else {
variant
}
})
.map(|s| PossibleValue::new(s)),
))
}
}
impl ValueParserFactory for ProfileType {
type Parser = ProfileTypeParser;
fn value_parser() -> Self::Parser {
ProfileTypeParser
}
}

View File

@@ -4,18 +4,18 @@ use sql_generation::{generation::pick_index, model::table::SimValue};
use turso_core::Value;
use crate::{
InteractionPlan,
generation::{
plan::{Interaction, InteractionPlanState, ResultSet},
Shadow as _,
plan::{Interaction, InteractionPlanState, ResultSet},
},
model::Query,
runner::execution::ExecutionContinuation,
InteractionPlan,
};
use super::{
env::{SimConnection, SimulatorEnv},
execution::{execute_interaction, Execution, ExecutionHistory, ExecutionResult},
execution::{Execution, ExecutionHistory, ExecutionResult, execute_interaction},
};
pub(crate) fn run_simulation(
@@ -249,7 +249,9 @@ fn execute_plan(
match (limbo_values, rusqlite_values) {
(Ok(limbo_values), Ok(rusqlite_values)) => {
if limbo_values != rusqlite_values {
tracing::error!("returned values from limbo and rusqlite results do not match");
tracing::error!(
"returned values from limbo and rusqlite results do not match"
);
let diff = limbo_values
.iter()
.zip(rusqlite_values.iter())
@@ -303,7 +305,9 @@ fn execute_plan(
tracing::warn!("rusqlite error {}", rusqlite_err);
}
(Ok(limbo_result), Err(rusqlite_err)) => {
tracing::error!("limbo and rusqlite results do not match, limbo returned values but rusqlite failed");
tracing::error!(
"limbo and rusqlite results do not match, limbo returned values but rusqlite failed"
);
tracing::error!("limbo values {:?}", limbo_result);
tracing::error!("rusqlite error {}", rusqlite_err);
return Err(turso_core::LimboError::InternalError(
@@ -311,7 +315,9 @@ fn execute_plan(
));
}
(Err(limbo_err), Ok(_)) => {
tracing::error!("limbo and rusqlite results do not match, limbo failed but rusqlite returned values");
tracing::error!(
"limbo and rusqlite results do not match, limbo failed but rusqlite returned values"
);
tracing::error!("limbo error {}", limbo_err);
return Err(turso_core::LimboError::InternalError(
"limbo and rusqlite results do not match".into(),

View File

@@ -6,13 +6,13 @@ use std::{
use sql_generation::generation::pick_index;
use crate::{
generation::plan::InteractionPlanState, runner::execution::ExecutionContinuation,
InteractionPlan,
InteractionPlan, generation::plan::InteractionPlanState,
runner::execution::ExecutionContinuation,
};
use super::{
env::{SimConnection, SimulatorEnv},
execution::{execute_interaction, Execution, ExecutionHistory, ExecutionResult},
execution::{Execution, ExecutionHistory, ExecutionResult, execute_interaction},
};
pub(crate) fn run_simulation(
@@ -207,7 +207,9 @@ fn execute_plan(
match (limbo_values, doublecheck_values) {
(Ok(limbo_values), Ok(doublecheck_values)) => {
if limbo_values != doublecheck_values {
tracing::error!("returned values from limbo and doublecheck results do not match");
tracing::error!(
"returned values from limbo and doublecheck results do not match"
);
tracing::debug!("limbo values {:?}", limbo_values);
tracing::debug!(
"doublecheck values {:?}",
@@ -231,7 +233,9 @@ fn execute_plan(
}
}
(Ok(limbo_result), Err(doublecheck_err)) => {
tracing::error!("limbo and doublecheck results do not match, limbo returned values but doublecheck failed");
tracing::error!(
"limbo and doublecheck results do not match, limbo returned values but doublecheck failed"
);
tracing::error!("limbo values {:?}", limbo_result);
tracing::error!("doublecheck error {}", doublecheck_err);
return Err(turso_core::LimboError::InternalError(
@@ -239,7 +243,9 @@ fn execute_plan(
));
}
(Err(limbo_err), Ok(_)) => {
tracing::error!("limbo and doublecheck results do not match, limbo failed but doublecheck returned values");
tracing::error!(
"limbo and doublecheck results do not match, limbo failed but doublecheck returned values"
);
tracing::error!("limbo error {}", limbo_err);
return Err(turso_core::LimboError::InternalError(
"limbo and doublecheck results do not match".into(),

View File

@@ -7,10 +7,10 @@ use std::sync::Arc;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use sql_generation::generation::Opts;
use sql_generation::model::table::Table;
use turso_core::Database;
use crate::profiles::Profile;
use crate::runner::io::SimulatorIO;
use super::cli::SimulatorCLI;
@@ -60,7 +60,7 @@ impl Deref for SimulatorTables {
pub(crate) struct SimulatorEnv {
pub(crate) opts: SimulatorOpts,
pub gen_opts: Opts,
pub profile: Profile,
pub(crate) connections: Vec<SimConnection>,
pub(crate) io: Arc<SimulatorIO>,
pub(crate) db: Option<Arc<Database>>,
@@ -87,7 +87,7 @@ impl SimulatorEnv {
paths: self.paths.clone(),
type_: self.type_,
phase: self.phase,
gen_opts: self.gen_opts.clone(),
profile: self.profile.clone(),
}
}
@@ -164,6 +164,7 @@ impl SimulatorEnv {
cli_opts: &SimulatorCLI,
paths: Paths,
simulation_type: SimulationType,
profile: &Profile,
) -> Self {
let mut rng = ChaCha8Rng::seed_from_u64(seed);
@@ -294,11 +295,6 @@ impl SimulatorEnv {
.map(|_| SimConnection::Disconnected)
.collect::<Vec<_>>();
let gen_opts = Opts {
indexes: opts.experimental_indexes,
..Default::default()
};
SimulatorEnv {
opts,
tables: SimulatorTables::new(),
@@ -309,7 +305,7 @@ impl SimulatorEnv {
db: Some(db),
type_: simulation_type,
phase: SimulationPhase::Test,
gen_opts,
profile: profile.clone(),
}
}

View File

@@ -5,8 +5,8 @@ use tracing::instrument;
use turso_core::{Connection, LimboError, Result, StepResult};
use crate::generation::{
plan::{Interaction, InteractionPlan, InteractionPlanState, ResultSet},
Shadow as _,
plan::{Interaction, InteractionPlan, InteractionPlanState, ResultSet},
};
use super::env::{SimConnection, SimulatorEnv};

View File

@@ -6,10 +6,10 @@ use std::{
use rand::Rng as _;
use rand_chacha::ChaCha8Rng;
use tracing::{instrument, Level};
use tracing::{Level, instrument};
use turso_core::{File, Result};
use crate::runner::{clock::SimulatorClock, FAULT_ERROR_MSG};
use crate::runner::{FAULT_ERROR_MSG, clock::SimulatorClock};
pub(crate) struct SimulatorFile {
pub path: String,
pub(crate) inner: Arc<dyn File>,
@@ -201,7 +201,9 @@ impl File for SimulatorFile {
self.nr_sync_calls.set(self.nr_sync_calls.get() + 1);
if self.fault.get() {
// TODO: Enable this when https://github.com/tursodatabase/turso/issues/2091 is fixed.
tracing::debug!("ignoring sync fault because it causes false positives with current simulator design");
tracing::debug!(
"ignoring sync fault because it causes false positives with current simulator design"
);
self.fault.set(false);
}
let c = if let Some(latency) = self.generate_latency_duration() {

View File

@@ -5,7 +5,7 @@ use std::{
use rand::{RngCore, SeedableRng};
use rand_chacha::ChaCha8Rng;
use turso_core::{Clock, Instant, OpenFlags, PlatformIO, Result, IO};
use turso_core::{Clock, IO, Instant, OpenFlags, PlatformIO, Result};
use crate::runner::{clock::SimulatorClock, file::SimulatorFile};

View File

@@ -10,7 +10,7 @@ use crate::{
use super::{
env::{SimConnection, SimulatorEnv},
execution::{execute_interaction, Execution, ExecutionHistory, ExecutionResult},
execution::{Execution, ExecutionHistory, ExecutionResult, execute_interaction},
};
pub(crate) fn run_simulation(

View File

@@ -1,4 +1,5 @@
use crate::{
SandboxedResult, SimulatorEnv,
generation::{
plan::{Interaction, InteractionPlan, Interactions},
property::Property,
@@ -6,7 +7,6 @@ use crate::{
model::Query,
run_simulation,
runner::execution::Execution,
SandboxedResult, SimulatorEnv,
};
use std::sync::{Arc, Mutex};