refactor SimulatorEnv to hold committed tables and separate connection tables for snapshot isolation

This commit is contained in:
pedrocarlo
2025-09-18 16:37:22 -03:00
parent 30538e7898
commit c4843d6a6e
5 changed files with 60 additions and 12 deletions

View File

@@ -358,6 +358,8 @@ impl Shadow for Select {
impl Shadow for Begin {
type Result = Vec<Vec<SimValue>>;
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
// FIXME: currently the snapshot is taken eagerly
// this is wrong for Deffered transactions
tables.snapshot = Some(tables.tables.clone());
vec![]
}

View File

@@ -59,8 +59,8 @@ pub(crate) fn execute_interactions(
let mut env = env.lock().unwrap();
let mut rusqlite_env = rusqlite_env.lock().unwrap();
env.tables.clear();
rusqlite_env.tables.clear();
env.clear_tables();
rusqlite_env.clear_tables();
let now = std::time::Instant::now();

View File

@@ -89,8 +89,8 @@ pub(crate) fn execute_plans(
let mut env = env.lock().unwrap();
let mut doublecheck_env = doublecheck_env.lock().unwrap();
env.tables.clear();
doublecheck_env.tables.clear();
env.clear_tables();
doublecheck_env.clear_tables();
let now = std::time::Instant::now();

View File

@@ -8,6 +8,7 @@ use std::sync::Arc;
use garde::Validate;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use sql_generation::generation::GenerationContext;
use sql_generation::model::table::Table;
use turso_core::Database;
@@ -71,8 +72,12 @@ pub(crate) struct SimulatorEnv {
pub(crate) paths: Paths,
pub(crate) type_: SimulationType,
pub(crate) phase: SimulationPhase,
pub(crate) tables: SimulatorTables,
pub memory_io: bool,
/// If connection state is None, means we are not in a transaction
pub connection_tables: Vec<Option<SimulatorTables>>,
// Table data that is committed into the database or wal
pub committed_tables: SimulatorTables,
}
impl UnwindSafe for SimulatorEnv {}
@@ -81,10 +86,6 @@ impl SimulatorEnv {
pub(crate) fn clone_without_connections(&self) -> Self {
SimulatorEnv {
opts: self.opts.clone(),
tables: self.tables.clone(),
connections: (0..self.connections.len())
.map(|_| SimConnection::Disconnected)
.collect(),
io: self.io.clone(),
db: self.db.clone(),
rng: self.rng.clone(),
@@ -93,11 +94,17 @@ impl SimulatorEnv {
phase: self.phase,
memory_io: self.memory_io,
profile: self.profile.clone(),
connections: (0..self.connections.len())
.map(|_| SimConnection::Disconnected)
.collect(),
// TODO: not sure if connection_tables should be recreated instead
connection_tables: self.connection_tables.clone(),
committed_tables: self.committed_tables.clone(),
}
}
pub(crate) fn clear(&mut self) {
self.tables.clear();
self.clear_tables();
self.connections.iter_mut().for_each(|c| c.disconnect());
self.rng = ChaCha8Rng::seed_from_u64(self.opts.seed);
@@ -284,7 +291,6 @@ impl SimulatorEnv {
SimulatorEnv {
opts,
tables: SimulatorTables::new(),
connections,
paths,
rng,
@@ -294,6 +300,8 @@ impl SimulatorEnv {
phase: SimulationPhase::Test,
memory_io: cli_opts.memory_io,
profile: profile.clone(),
committed_tables: SimulatorTables::new(),
connection_tables: vec![None; profile.max_connections],
}
}
@@ -327,6 +335,44 @@ impl SimulatorEnv {
}
};
}
/// Clears the commited tables and the connection tables
pub fn clear_tables(&mut self) {
self.committed_tables.clear();
self.connection_tables.iter_mut().for_each(|t| {
if let Some(t) = t {
t.clear();
}
});
}
pub fn connection_context(&self, connection_index: usize) -> impl GenerationContext {
struct ConnectionGenContext<'a> {
tables: &'a Vec<sql_generation::model::table::Table>,
opts: &'a sql_generation::generation::Opts,
}
impl<'a> GenerationContext for ConnectionGenContext<'a> {
fn tables(&self) -> &Vec<sql_generation::model::table::Table> {
self.tables
}
fn opts(&self) -> &sql_generation::generation::Opts {
self.opts
}
}
let tables = if let Some(tables) = self.connection_tables.get(connection_index).unwrap() {
&tables.tables
} else {
&self.committed_tables.tables
};
ConnectionGenContext {
opts: &self.profile.query.gen_opts,
tables,
}
}
}
pub trait ConnectionTrait

View File

@@ -65,7 +65,7 @@ pub(crate) fn execute_interactions(
env.clear_poison();
let mut env = env.lock().unwrap();
env.tables.clear();
env.clear_tables();
for _tick in 0..env.opts.ticks {
tracing::trace!("Executing tick {}", _tick);