diff --git a/simulator/generation/property.rs b/simulator/generation/property.rs index 7129f7989..ca75477ac 100644 --- a/simulator/generation/property.rs +++ b/simulator/generation/property.rs @@ -1533,7 +1533,10 @@ impl ArbitraryFrom<(&SimulatorEnv, &InteractionStats)> for Property { Box::new(|rng: &mut R| property_fsync_no_wait(rng, env, &remaining_)), ), ( - if env.profile.io.enable && !env.opts.disable_faulty_query { + if env.profile.io.enable + && env.profile.io.fault.enable + && !env.opts.disable_faulty_query + { 20 } else { 0 diff --git a/simulator/profiles/io.rs b/simulator/profiles/io.rs index e49d6d1c9..4bf44683a 100644 --- a/simulator/profiles/io.rs +++ b/simulator/profiles/io.rs @@ -11,6 +11,8 @@ pub struct IOProfile { pub enable: bool, #[garde(dive)] pub latency: LatencyProfile, + #[garde(dive)] + pub fault: FaultProfile, // TODO: expand here with header corruption options and faults on specific IO operations } @@ -19,6 +21,7 @@ impl Default for IOProfile { Self { enable: true, latency: Default::default(), + fault: Default::default(), } } } @@ -49,3 +52,28 @@ impl Default for LatencyProfile { } } } + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)] +#[serde(deny_unknown_fields, default)] +pub struct FaultProfile { + #[garde(skip)] + pub enable: bool, + // TODO: modify SimIo impls to have a FaultProfile inside so they can skip faults depending on the profile + #[garde(skip)] + pub read: bool, + #[garde(skip)] + pub write: bool, + #[garde(skip)] + pub sync: bool, +} + +impl Default for FaultProfile { + fn default() -> Self { + Self { + enable: true, + read: true, + write: true, + sync: true, + } + } +} diff --git a/simulator/profiles/mod.rs b/simulator/profiles/mod.rs index 20bb3b5ea..633bb3750 100644 --- a/simulator/profiles/mod.rs +++ b/simulator/profiles/mod.rs @@ -13,7 +13,10 @@ use serde::{Deserialize, Serialize}; use sql_generation::generation::{InsertOpts, LargeTableOpts, Opts, QueryOpts, TableOpts}; use strum::EnumString; -use crate::profiles::{io::IOProfile, query::QueryProfile}; +use crate::profiles::{ + io::{FaultProfile, IOProfile}, + query::QueryProfile, +}; pub mod io; pub mod query; @@ -79,10 +82,33 @@ impl Profile { profile } + pub fn faultless() -> Self { + let profile = Profile { + io: IOProfile { + fault: FaultProfile { + enable: false, + ..Default::default() + }, + ..Default::default() + }, + query: QueryProfile { + create_table_weight: 0, + create_index_weight: 0, + ..Default::default() + }, + ..Default::default() + }; + + // Validate that we as the developer are not creating an incorrect default profile + profile.validate().unwrap(); + profile + } + pub fn parse_from_type(profile_type: ProfileType) -> anyhow::Result { let profile = match profile_type { ProfileType::Default => Self::default(), ProfileType::WriteHeavy => Self::write_heavy(), + ProfileType::Faultless => Self::faultless(), ProfileType::Custom(path) => { Self::parse(path).with_context(|| "failed to parse JSON profile")? } @@ -120,6 +146,7 @@ pub enum ProfileType { #[default] Default, WriteHeavy, + Faultless, #[strum(disabled)] Custom(PathBuf), }