diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 462ceaec7..31a54f1e6 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -22,4 +22,4 @@ log = "0.4.20" tempfile = "3.0.7" env_logger = "0.10.1" anarchist-readable-name-generator-lib = "0.1.2" -clap = { version = "4.5", features = ["derive"] } \ No newline at end of file +clap = { version = "4.5", features = ["derive"] } diff --git a/simulator/generation/mod.rs b/simulator/generation/mod.rs index 07a93492b..68f9c84fe 100644 --- a/simulator/generation/mod.rs +++ b/simulator/generation/mod.rs @@ -1,5 +1,10 @@ +use std::{ + iter::Sum, + ops::{Add, Sub, SubAssign}, +}; + use anarchist_readable_name_generator_lib::readable_name_custom; -use rand::Rng; +use rand::{distributions::uniform::SampleUniform, Rng}; pub mod plan; pub mod query; @@ -13,12 +18,17 @@ pub trait ArbitraryFrom { fn arbitrary_from(rng: &mut R, t: &T) -> Self; } -pub(crate) fn frequency<'a, T, R: rand::Rng>( - choices: Vec<(usize, Box T + 'a>)>, +pub(crate) fn frequency< + 'a, + T, + R: rand::Rng, + N: Sum + PartialOrd + Copy + Default + SampleUniform + SubAssign, +>( + choices: Vec<(N, Box T + 'a>)>, rng: &mut R, ) -> T { - let total = choices.iter().map(|(weight, _)| weight).sum::(); - let mut choice = rng.gen_range(0..total); + let total = choices.iter().map(|(weight, _)| *weight).sum::(); + let mut choice = rng.gen_range(N::default()..total); for (weight, f) in choices { if choice < weight { diff --git a/simulator/generation/plan.rs b/simulator/generation/plan.rs index 1857b4a00..759ff5e2b 100644 --- a/simulator/generation/plan.rs +++ b/simulator/generation/plan.rs @@ -9,7 +9,7 @@ use crate::{ query::{Create, Insert, Predicate, Query, Select}, table::Value, }, - SimConnection, SimulatorEnv, SimulatorOpts, + SimConnection, SimulatorEnv, }; use crate::generation::{frequency, Arbitrary, ArbitraryFrom}; @@ -45,14 +45,15 @@ pub(crate) struct InteractionStats { pub(crate) read_count: usize, pub(crate) write_count: usize, pub(crate) delete_count: usize, + pub(crate) create_count: usize, } impl Display for InteractionStats { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "Read: {}, Write: {}, Delete: {}", - self.read_count, self.write_count, self.delete_count + "Read: {}, Write: {}, Delete: {}, Create: {}", + self.read_count, self.write_count, self.delete_count, self.create_count ) } } @@ -135,6 +136,7 @@ impl InteractionPlan { let mut read = 0; let mut write = 0; let mut delete = 0; + let mut create = 0; for interaction in &self.plan { match interaction { @@ -142,7 +144,7 @@ impl InteractionPlan { Query::Select(_) => read += 1, Query::Insert(_) => write += 1, Query::Delete(_) => delete += 1, - Query::Create(_) => {} + Query::Create(_) => create += 1, }, Interaction::Assertion(_) => {} Interaction::Fault(_) => {} @@ -153,6 +155,7 @@ impl InteractionPlan { read_count: read, write_count: write, delete_count: delete, + create_count: create, } } } @@ -400,17 +403,21 @@ impl ArbitraryFrom<(&SimulatorEnv, InteractionStats)> for Interactions { rng: &mut R, (env, stats): &(&SimulatorEnv, InteractionStats), ) -> Self { - let remaining_read = - ((((env.opts.max_interactions * env.opts.read_percent) as f64) / 100.0) as usize) - .saturating_sub(stats.read_count); - let remaining_write = ((((env.opts.max_interactions * env.opts.write_percent) as f64) - / 100.0) as usize) - .saturating_sub(stats.write_count); + let remaining_read = ((env.opts.max_interactions as f64 * env.opts.read_percent / 100.0) + - (stats.read_count as f64)) + .max(0.0); + let remaining_write = ((env.opts.max_interactions as f64 * env.opts.write_percent / 100.0) + - (stats.write_count as f64)) + .max(0.0); + let remaining_create = ((env.opts.max_interactions as f64 * env.opts.create_percent + / 100.0) + - (stats.create_count as f64)) + .max(0.0); frequency( vec![ ( - usize::min(remaining_read, remaining_write), + f64::min(remaining_read, remaining_write), Box::new(|rng: &mut R| property_insert_select(rng, env)), ), ( @@ -422,12 +429,12 @@ impl ArbitraryFrom<(&SimulatorEnv, InteractionStats)> for Interactions { Box::new(|rng: &mut R| random_write(rng, env)), ), ( - remaining_write / 10, + remaining_create, Box::new(|rng: &mut R| create_table(rng, env)), ), - (1, Box::new(|rng: &mut R| random_fault(rng, env))), + (1.0, Box::new(|rng: &mut R| random_fault(rng, env))), ( - 1, + remaining_create / 2.0, Box::new(|rng: &mut R| property_double_create_failure(rng, env)), ), ], diff --git a/simulator/main.rs b/simulator/main.rs index bda55d909..8dc6d85bc 100644 --- a/simulator/main.rs +++ b/simulator/main.rs @@ -1,7 +1,7 @@ use clap::Parser; use generation::plan::{Interaction, InteractionPlan, ResultSet}; use generation::{pick_index, ArbitraryFrom}; -use limbo_core::{Connection, Database, Result, RowResult, IO}; +use limbo_core::{Database, Result}; use model::table::Value; use rand::prelude::*; use rand_chacha::ChaCha8Rng; @@ -11,7 +11,6 @@ use runner::io::SimulatorIO; use std::backtrace::Backtrace; use std::io::Write; use std::path::Path; -use std::rc::Rc; use std::sync::Arc; use tempfile::TempDir; @@ -137,14 +136,18 @@ fn run_simulation( ) -> Result<()> { let mut rng = ChaCha8Rng::seed_from_u64(seed); - let (read_percent, write_percent, delete_percent) = { - let mut remaining = 100; - let read_percent = rng.gen_range(0..=remaining); + let (create_percent, read_percent, write_percent, delete_percent) = { + let mut remaining = 100.0; + let read_percent = rng.gen_range(0.0..=remaining); remaining -= read_percent; - let write_percent = rng.gen_range(0..=remaining); + let write_percent = rng.gen_range(0.0..=remaining); remaining -= write_percent; let delete_percent = remaining; - (read_percent, write_percent, delete_percent) + + let create_percent = write_percent / 10.0; + let write_percent = write_percent - create_percent; + + (create_percent, read_percent, write_percent, delete_percent) }; if cli_opts.maximum_size < 1 { @@ -156,6 +159,7 @@ fn run_simulation( max_connections: 1, // TODO: for now let's use one connection as we didn't implement // correct transactions procesing max_tables: rng.gen_range(0..128), + create_percent, read_percent, write_percent, delete_percent, diff --git a/simulator/runner/env.rs b/simulator/runner/env.rs index 0624b94b4..53d99b2f0 100644 --- a/simulator/runner/env.rs +++ b/simulator/runner/env.rs @@ -30,9 +30,10 @@ pub(crate) struct SimulatorOpts { pub(crate) max_tables: usize, // this next options are the distribution of workload where read_percent + write_percent + // delete_percent == 100% - pub(crate) read_percent: usize, - pub(crate) write_percent: usize, - pub(crate) delete_percent: usize, + pub(crate) create_percent: f64, + pub(crate) read_percent: f64, + pub(crate) write_percent: f64, + pub(crate) delete_percent: f64, pub(crate) max_interactions: usize, pub(crate) page_size: usize, }