diff --git a/simulator/main.rs b/simulator/main.rs
index 154fa76e2..6a09e4f4a 100644
--- a/simulator/main.rs
+++ b/simulator/main.rs
@@ -1,73 +1,24 @@
-use clap::{command, Parser};
+use clap::Parser;
use generation::plan::{Interaction, InteractionPlan, ResultSet};
-use generation::{pick, pick_index, Arbitrary, ArbitraryFrom};
-use limbo_core::{Connection, Database, File, OpenFlags, PlatformIO, Result, RowResult, IO};
-use model::query::{Create, Insert, Predicate, Query, Select};
+use generation::{pick_index, Arbitrary, ArbitraryFrom};
+use limbo_core::{Connection, Database, Result, RowResult, IO};
+use model::query::{Create, Query};
use model::table::{Column, Name, Table, Value};
-use properties::{property_insert_select, property_select_all};
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;
-use std::cell::RefCell;
+use simulator::cli::SimulatorCLI;
+use simulator::env::{SimConnection, SimulatorEnv, SimulatorOpts};
+use simulator::io::SimulatorIO;
use std::io::Write;
-use std::panic::UnwindSafe;
use std::path::Path;
use std::rc::Rc;
use std::sync::Arc;
-use std::time::Duration;
use tempfile::TempDir;
mod generation;
mod model;
mod properties;
-
-struct SimulatorEnv {
- opts: SimulatorOpts,
- tables: Vec
,
- connections: Vec,
- io: Arc,
- db: Arc,
- rng: ChaCha8Rng,
-}
-
-impl UnwindSafe for SimulatorEnv {}
-
-#[derive(Clone)]
-enum SimConnection {
- Connected(Rc),
- Disconnected,
-}
-
-#[derive(Debug, Clone)]
-struct SimulatorOpts {
- ticks: usize,
- max_connections: usize,
- max_tables: usize,
- // this next options are the distribution of workload where read_percent + write_percent +
- // delete_percent == 100%
- read_percent: usize,
- write_percent: usize,
- delete_percent: usize,
- max_interactions: usize,
- page_size: usize,
-}
-
-#[derive(Parser)]
-#[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)]
- pub seed: Option,
- #[clap(short, long, help = "set custom output directory for produced files", default_value = None)]
- pub output_dir: Option,
- #[clap(
- short,
- long,
- help = "enable doublechecking, run the simulator with the plan twice and check output equality"
- )]
- pub doublecheck: bool,
- #[clap(short, long, help = "change the maximum size of the randomly generated sequence of interactions", default_value_t = 1024)]
- pub maximum_size: usize,
-}
+mod simulator;
#[allow(clippy::arc_with_non_send_sync)]
fn main() {
@@ -340,176 +291,3 @@ fn get_all_rows(
}
Ok(out)
}
-
-struct SimulatorIO {
- inner: Box,
- fault: RefCell,
- files: RefCell>>,
- rng: RefCell,
- nr_run_once_faults: RefCell,
- page_size: usize,
-}
-
-impl SimulatorIO {
- fn new(seed: u64, page_size: usize) -> Result {
- let inner = Box::new(PlatformIO::new()?);
- let fault = RefCell::new(false);
- let files = RefCell::new(Vec::new());
- let rng = RefCell::new(ChaCha8Rng::seed_from_u64(seed));
- let nr_run_once_faults = RefCell::new(0);
- Ok(Self {
- inner,
- fault,
- files,
- rng,
- nr_run_once_faults,
- page_size,
- })
- }
-
- fn inject_fault(&self, fault: bool) {
- self.fault.replace(fault);
- for file in self.files.borrow().iter() {
- file.inject_fault(fault);
- }
- }
-
- fn print_stats(&self) {
- println!("run_once faults: {}", self.nr_run_once_faults.borrow());
- for file in self.files.borrow().iter() {
- file.print_stats();
- }
- }
-}
-
-impl IO for SimulatorIO {
- fn open_file(
- &self,
- path: &str,
- flags: OpenFlags,
- _direct: bool,
- ) -> Result> {
- let inner = self.inner.open_file(path, flags, false)?;
- let file = Rc::new(SimulatorFile {
- inner,
- fault: RefCell::new(false),
- nr_pread_faults: RefCell::new(0),
- nr_pwrite_faults: RefCell::new(0),
- reads: RefCell::new(0),
- writes: RefCell::new(0),
- syncs: RefCell::new(0),
- page_size: self.page_size,
- });
- self.files.borrow_mut().push(file.clone());
- Ok(file)
- }
-
- fn run_once(&self) -> Result<()> {
- if *self.fault.borrow() {
- *self.nr_run_once_faults.borrow_mut() += 1;
- return Err(limbo_core::LimboError::InternalError(
- "Injected fault".into(),
- ));
- }
- self.inner.run_once().unwrap();
- Ok(())
- }
-
- fn generate_random_number(&self) -> i64 {
- self.rng.borrow_mut().next_u64() as i64
- }
-
- fn get_current_time(&self) -> String {
- "2024-01-01 00:00:00".to_string()
- }
-}
-
-struct SimulatorFile {
- inner: Rc,
- fault: RefCell,
- nr_pread_faults: RefCell,
- nr_pwrite_faults: RefCell,
- writes: RefCell,
- reads: RefCell,
- syncs: RefCell,
- page_size: usize,
-}
-
-impl SimulatorFile {
- fn inject_fault(&self, fault: bool) {
- self.fault.replace(fault);
- }
-
- fn print_stats(&self) {
- println!(
- "pread faults: {}, pwrite faults: {}, reads: {}, writes: {}, syncs: {}",
- *self.nr_pread_faults.borrow(),
- *self.nr_pwrite_faults.borrow(),
- *self.reads.borrow(),
- *self.writes.borrow(),
- *self.syncs.borrow(),
- );
- }
-}
-
-impl limbo_core::File for SimulatorFile {
- fn lock_file(&self, exclusive: bool) -> Result<()> {
- if *self.fault.borrow() {
- return Err(limbo_core::LimboError::InternalError(
- "Injected fault".into(),
- ));
- }
- self.inner.lock_file(exclusive)
- }
-
- fn unlock_file(&self) -> Result<()> {
- if *self.fault.borrow() {
- return Err(limbo_core::LimboError::InternalError(
- "Injected fault".into(),
- ));
- }
- self.inner.unlock_file()
- }
-
- fn pread(&self, pos: usize, c: Rc) -> Result<()> {
- if *self.fault.borrow() {
- *self.nr_pread_faults.borrow_mut() += 1;
- return Err(limbo_core::LimboError::InternalError(
- "Injected fault".into(),
- ));
- }
- *self.reads.borrow_mut() += 1;
- self.inner.pread(pos, c)
- }
-
- fn pwrite(
- &self,
- pos: usize,
- buffer: Rc>,
- c: Rc,
- ) -> Result<()> {
- if *self.fault.borrow() {
- *self.nr_pwrite_faults.borrow_mut() += 1;
- return Err(limbo_core::LimboError::InternalError(
- "Injected fault".into(),
- ));
- }
- *self.writes.borrow_mut() += 1;
- self.inner.pwrite(pos, buffer, c)
- }
-
- fn sync(&self, c: Rc) -> Result<()> {
- *self.syncs.borrow_mut() += 1;
- self.inner.sync(c)
- }
-
- fn size(&self) -> Result {
- self.inner.size()
- }
-}
-
-impl Drop for SimulatorFile {
- fn drop(&mut self) {
- self.inner.unlock_file().expect("Failed to unlock file");
- }
-}
diff --git a/simulator/simulator/cli.rs b/simulator/simulator/cli.rs
new file mode 100644
index 000000000..f977937bb
--- /dev/null
+++ b/simulator/simulator/cli.rs
@@ -0,0 +1,24 @@
+use clap::{command, Parser};
+
+#[derive(Parser)]
+#[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)]
+ pub seed: Option,
+ #[clap(short, long, help = "set custom output directory for produced files", default_value = None)]
+ pub output_dir: Option,
+ #[clap(
+ short,
+ long,
+ help = "enable doublechecking, run the simulator with the plan twice and check output equality"
+ )]
+ pub doublecheck: bool,
+ #[clap(
+ short,
+ long,
+ help = "change the maximum size of the randomly generated sequence of interactions",
+ default_value_t = 1024
+ )]
+ pub maximum_size: usize,
+}
diff --git a/simulator/simulator/env.rs b/simulator/simulator/env.rs
new file mode 100644
index 000000000..0107ac501
--- /dev/null
+++ b/simulator/simulator/env.rs
@@ -0,0 +1,38 @@
+use std::rc::Rc;
+use std::sync::Arc;
+
+use limbo_core::{Connection, Database};
+use rand_chacha::ChaCha8Rng;
+
+use crate::model::table::Table;
+
+use crate::simulator::io::SimulatorIO;
+
+pub(crate) struct SimulatorEnv {
+ pub(crate) opts: SimulatorOpts,
+ pub(crate) tables: Vec,
+ pub(crate) connections: Vec,
+ pub(crate) io: Arc,
+ pub(crate) db: Arc,
+ pub(crate) rng: ChaCha8Rng,
+}
+
+#[derive(Clone)]
+pub(crate) enum SimConnection {
+ Connected(Rc),
+ Disconnected,
+}
+
+#[derive(Debug, Clone)]
+pub(crate) struct SimulatorOpts {
+ pub(crate) ticks: usize,
+ pub(crate) max_connections: usize,
+ 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) max_interactions: usize,
+ pub(crate) page_size: usize,
+}
diff --git a/simulator/simulator/file.rs b/simulator/simulator/file.rs
new file mode 100644
index 000000000..7f3fe9072
--- /dev/null
+++ b/simulator/simulator/file.rs
@@ -0,0 +1,93 @@
+use std::{cell::RefCell, rc::Rc};
+
+use limbo_core::{File, Result};
+
+pub(crate) struct SimulatorFile {
+ pub(crate) inner: Rc,
+ pub(crate) fault: RefCell,
+ pub(crate) nr_pread_faults: RefCell,
+ pub(crate) nr_pwrite_faults: RefCell,
+ pub(crate) writes: RefCell,
+ pub(crate) reads: RefCell,
+ pub(crate) syncs: RefCell,
+ pub(crate) page_size: usize,
+}
+
+impl SimulatorFile {
+ pub(crate) fn inject_fault(&self, fault: bool) {
+ self.fault.replace(fault);
+ }
+
+ pub(crate) fn print_stats(&self) {
+ println!(
+ "pread faults: {}, pwrite faults: {}, reads: {}, writes: {}, syncs: {}",
+ *self.nr_pread_faults.borrow(),
+ *self.nr_pwrite_faults.borrow(),
+ *self.reads.borrow(),
+ *self.writes.borrow(),
+ *self.syncs.borrow(),
+ );
+ }
+}
+
+impl limbo_core::File for SimulatorFile {
+ fn lock_file(&self, exclusive: bool) -> Result<()> {
+ if *self.fault.borrow() {
+ return Err(limbo_core::LimboError::InternalError(
+ "Injected fault".into(),
+ ));
+ }
+ self.inner.lock_file(exclusive)
+ }
+
+ fn unlock_file(&self) -> Result<()> {
+ if *self.fault.borrow() {
+ return Err(limbo_core::LimboError::InternalError(
+ "Injected fault".into(),
+ ));
+ }
+ self.inner.unlock_file()
+ }
+
+ fn pread(&self, pos: usize, c: Rc) -> Result<()> {
+ if *self.fault.borrow() {
+ *self.nr_pread_faults.borrow_mut() += 1;
+ return Err(limbo_core::LimboError::InternalError(
+ "Injected fault".into(),
+ ));
+ }
+ *self.reads.borrow_mut() += 1;
+ self.inner.pread(pos, c)
+ }
+
+ fn pwrite(
+ &self,
+ pos: usize,
+ buffer: Rc>,
+ c: Rc,
+ ) -> Result<()> {
+ if *self.fault.borrow() {
+ *self.nr_pwrite_faults.borrow_mut() += 1;
+ return Err(limbo_core::LimboError::InternalError(
+ "Injected fault".into(),
+ ));
+ }
+ *self.writes.borrow_mut() += 1;
+ self.inner.pwrite(pos, buffer, c)
+ }
+
+ fn sync(&self, c: Rc) -> Result<()> {
+ *self.syncs.borrow_mut() += 1;
+ self.inner.sync(c)
+ }
+
+ fn size(&self) -> Result {
+ self.inner.size()
+ }
+}
+
+impl Drop for SimulatorFile {
+ fn drop(&mut self) {
+ self.inner.unlock_file().expect("Failed to unlock file");
+ }
+}
diff --git a/simulator/simulator/io.rs b/simulator/simulator/io.rs
new file mode 100644
index 000000000..e6b96218e
--- /dev/null
+++ b/simulator/simulator/io.rs
@@ -0,0 +1,90 @@
+use std::{cell::RefCell, rc::Rc};
+
+use limbo_core::{OpenFlags, PlatformIO, Result, IO};
+use rand::{RngCore, SeedableRng};
+use rand_chacha::ChaCha8Rng;
+
+use crate::simulator::file::SimulatorFile;
+
+pub(crate) struct SimulatorIO {
+ pub(crate) inner: Box,
+ pub(crate) fault: RefCell,
+ pub(crate) files: RefCell>>,
+ pub(crate) rng: RefCell,
+ pub(crate) nr_run_once_faults: RefCell,
+ pub(crate) page_size: usize,
+}
+
+impl SimulatorIO {
+ pub(crate) fn new(seed: u64, page_size: usize) -> Result {
+ let inner = Box::new(PlatformIO::new()?);
+ let fault = RefCell::new(false);
+ let files = RefCell::new(Vec::new());
+ let rng = RefCell::new(ChaCha8Rng::seed_from_u64(seed));
+ let nr_run_once_faults = RefCell::new(0);
+ Ok(Self {
+ inner,
+ fault,
+ files,
+ rng,
+ nr_run_once_faults,
+ page_size,
+ })
+ }
+
+ pub(crate) fn inject_fault(&self, fault: bool) {
+ self.fault.replace(fault);
+ for file in self.files.borrow().iter() {
+ file.inject_fault(fault);
+ }
+ }
+
+ pub(crate) fn print_stats(&self) {
+ println!("run_once faults: {}", self.nr_run_once_faults.borrow());
+ for file in self.files.borrow().iter() {
+ file.print_stats();
+ }
+ }
+}
+
+impl IO for SimulatorIO {
+ fn open_file(
+ &self,
+ path: &str,
+ flags: OpenFlags,
+ _direct: bool,
+ ) -> Result> {
+ let inner = self.inner.open_file(path, flags, false)?;
+ let file = Rc::new(SimulatorFile {
+ inner,
+ fault: RefCell::new(false),
+ nr_pread_faults: RefCell::new(0),
+ nr_pwrite_faults: RefCell::new(0),
+ reads: RefCell::new(0),
+ writes: RefCell::new(0),
+ syncs: RefCell::new(0),
+ page_size: self.page_size,
+ });
+ self.files.borrow_mut().push(file.clone());
+ Ok(file)
+ }
+
+ fn run_once(&self) -> Result<()> {
+ if *self.fault.borrow() {
+ *self.nr_run_once_faults.borrow_mut() += 1;
+ return Err(limbo_core::LimboError::InternalError(
+ "Injected fault".into(),
+ ));
+ }
+ self.inner.run_once().unwrap();
+ Ok(())
+ }
+
+ fn generate_random_number(&self) -> i64 {
+ self.rng.borrow_mut().next_u64() as i64
+ }
+
+ fn get_current_time(&self) -> String {
+ "2024-01-01 00:00:00".to_string()
+ }
+}
diff --git a/simulator/simulator/mod.rs b/simulator/simulator/mod.rs
new file mode 100644
index 000000000..d5f06c103
--- /dev/null
+++ b/simulator/simulator/mod.rs
@@ -0,0 +1,4 @@
+pub mod cli;
+pub mod env;
+pub mod file;
+pub mod io;