diff --git a/core/io/clock.rs b/core/io/clock.rs index 3a38ad955..8c12aa4e5 100644 --- a/core/io/clock.rs +++ b/core/io/clock.rs @@ -4,6 +4,17 @@ pub struct Instant { pub micros: u32, } +impl From> for Instant { + fn from(value: chrono::DateTime) -> Self { + Instant { + secs: value.timestamp(), + micros: value.timestamp_subsec_micros(), + } + } +} + + + pub trait Clock { fn now(&self) -> Instant; } diff --git a/simulator/runner/clock.rs b/simulator/runner/clock.rs new file mode 100644 index 000000000..56ef72f1f --- /dev/null +++ b/simulator/runner/clock.rs @@ -0,0 +1,34 @@ +use std::cell::RefCell; + +use chrono::{DateTime, Utc}; +use rand::Rng; +use rand_chacha::ChaCha8Rng; + +#[derive(Debug)] +pub struct SimulatorClock { + curr_time: RefCell>, + rng: RefCell, +} + +impl SimulatorClock { + const MIN_TICK: u64 = 1; + const MAX_TICK: u64 = 50; + + pub fn new(rng: ChaCha8Rng) -> Self { + Self { + curr_time: RefCell::new(Utc::now()), + rng: RefCell::new(rng), + } + } + + pub fn now(&self) -> DateTime { + let mut time = self.curr_time.borrow_mut(); + let nanos = self + .rng + .borrow_mut() + .gen_range(Self::MIN_TICK..Self::MAX_TICK); + let nanos = std::time::Duration::from_micros(nanos); + *time = *time + nanos; + *time + } +} diff --git a/simulator/runner/file.rs b/simulator/runner/file.rs index c7d615c0c..6bebbc5e1 100644 --- a/simulator/runner/file.rs +++ b/simulator/runner/file.rs @@ -4,12 +4,13 @@ use std::{ sync::Arc, }; +use chrono::{DateTime, Utc}; use rand::Rng as _; use rand_chacha::ChaCha8Rng; use tracing::{instrument, Level}; use turso_core::{File, Result}; -use crate::model::FAULT_ERROR_MSG; +use crate::{model::FAULT_ERROR_MSG, runner::clock::SimulatorClock}; pub(crate) struct SimulatorFile { pub(crate) inner: Arc, pub(crate) fault: Cell, @@ -40,12 +41,13 @@ pub(crate) struct SimulatorFile { pub sync_completion: RefCell>>, pub queued_io: RefCell>, + pub clock: Arc, } type IoOperation = Box Result>>; pub struct DelayedIo { - pub time: std::time::Instant, + pub time: turso_core::Instant, pub op: IoOperation, } @@ -95,17 +97,19 @@ impl SimulatorFile { } #[instrument(skip_all, level = Level::TRACE)] - fn generate_latency_duration(&self) -> Option { + fn generate_latency_duration(&self) -> Option { let mut rng = self.rng.borrow_mut(); // Chance to introduce some latency rng.gen_bool(self.latency_probability as f64 / 100.0) .then(|| { - std::time::Instant::now() + std::time::Duration::from_millis(rng.gen_range(5..15)) + let now: DateTime = self.clock.now().into(); + let sum = now + std::time::Duration::from_millis(rng.gen_range(5..20)); + sum.into() }) } #[instrument(skip_all, level = Level::DEBUG)] - pub fn run_queued_io(&self, now: std::time::Instant) -> Result<()> { + pub fn run_queued_io(&self, now: turso_core::Instant) -> Result<()> { let mut queued_io = self.queued_io.borrow_mut(); // TODO: as we are not in version 1.87 we cannot use `extract_if` // so we have to do something different to achieve the same thing diff --git a/simulator/runner/io.rs b/simulator/runner/io.rs index cc4b04f4e..b56000965 100644 --- a/simulator/runner/io.rs +++ b/simulator/runner/io.rs @@ -7,7 +7,10 @@ use rand::{RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use turso_core::{Clock, Instant, MemoryIO, OpenFlags, PlatformIO, Result, IO}; -use crate::{model::FAULT_ERROR_MSG, runner::file::SimulatorFile}; +use crate::{ + model::FAULT_ERROR_MSG, + runner::{clock::SimulatorClock, file::SimulatorFile}, +}; pub(crate) struct SimulatorIO { pub(crate) inner: Box, @@ -18,6 +21,7 @@ pub(crate) struct SimulatorIO { pub(crate) page_size: usize, seed: u64, latency_probability: usize, + clock: Arc, } unsafe impl Send for SimulatorIO {} @@ -30,6 +34,8 @@ impl SimulatorIO { let files = RefCell::new(Vec::new()); let rng = RefCell::new(ChaCha8Rng::seed_from_u64(seed)); let nr_run_once_faults = Cell::new(0); + let clock = SimulatorClock::new(ChaCha8Rng::seed_from_u64(seed)); + Ok(Self { inner, fault, @@ -39,6 +45,7 @@ impl SimulatorIO { page_size, seed, latency_probability, + clock: Arc::new(clock), }) } @@ -59,11 +66,7 @@ impl SimulatorIO { impl Clock for SimulatorIO { fn now(&self) -> Instant { - let now = chrono::Local::now(); - Instant { - secs: now.timestamp(), - micros: now.timestamp_subsec_micros(), - } + self.clock.now().into() } } @@ -89,6 +92,7 @@ impl IO for SimulatorIO { latency_probability: self.latency_probability, sync_completion: RefCell::new(None), queued_io: RefCell::new(Vec::new()), + clock: self.clock.clone(), }); self.files.borrow_mut().push(file.clone()); Ok(file) @@ -109,7 +113,7 @@ impl IO for SimulatorIO { FAULT_ERROR_MSG.into(), )); } - let now = std::time::Instant::now(); + let now = self.now(); for file in self.files.borrow().iter() { file.run_queued_io(now)?; } diff --git a/simulator/runner/mod.rs b/simulator/runner/mod.rs index ccb0563ab..b56335da5 100644 --- a/simulator/runner/mod.rs +++ b/simulator/runner/mod.rs @@ -1,5 +1,6 @@ pub mod bugbase; pub mod cli; +pub mod clock; pub mod differential; pub mod doublecheck; pub mod env;