Merge 'Fix non-determinism in simulator ' from Pedro Muniz

Use IndexSet for order preserving iteration instead of HashSet

Closes #2934
This commit is contained in:
Pekka Enberg
2025-09-05 08:29:03 +03:00
committed by GitHub
8 changed files with 30 additions and 79 deletions

17
Cargo.lock generated
View File

@@ -1800,9 +1800,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.10.0"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
@@ -1822,7 +1822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88"
dependencies = [
"ahash",
"indexmap 2.10.0",
"indexmap 2.11.0",
"is-terminal",
"itoa",
"log",
@@ -2192,7 +2192,7 @@ dependencies = [
"env_logger 0.10.2",
"garde",
"hex",
"indexmap 2.10.0",
"indexmap 2.11.0",
"itertools 0.14.0",
"json5",
"log",
@@ -2774,7 +2774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d"
dependencies = [
"base64",
"indexmap 2.10.0",
"indexmap 2.11.0",
"quick-xml 0.32.0",
"serde",
"time",
@@ -3672,6 +3672,7 @@ dependencies = [
"anyhow",
"garde",
"hex",
"indexmap 2.11.0",
"itertools 0.14.0",
"rand 0.9.2",
"rand_chacha 0.9.0",
@@ -4064,7 +4065,7 @@ version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
dependencies = [
"indexmap 2.10.0",
"indexmap 2.11.0",
"serde",
"serde_spanned",
"toml_datetime",
@@ -4086,7 +4087,7 @@ version = "0.22.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
dependencies = [
"indexmap 2.10.0",
"indexmap 2.11.0",
"serde",
"serde_spanned",
"toml_datetime",
@@ -4371,7 +4372,7 @@ dependencies = [
"cc",
"env_logger 0.11.7",
"fallible-iterator",
"indexmap 2.10.0",
"indexmap 2.11.0",
"log",
"memchr",
"miette",

View File

@@ -1,11 +1,11 @@
use std::{
collections::HashSet,
fmt::{Debug, Display},
path::Path,
sync::Arc,
vec,
};
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
use sql_generation::{
@@ -166,13 +166,13 @@ impl Interactions {
}
impl Interactions {
pub(crate) fn dependencies(&self) -> HashSet<String> {
pub(crate) fn dependencies(&self) -> IndexSet<String> {
match self {
Interactions::Property(property) => {
property
.interactions()
.iter()
.fold(HashSet::new(), |mut acc, i| match i {
.fold(IndexSet::new(), |mut acc, i| match i {
Interaction::Query(q) => {
acc.extend(q.dependencies());
acc
@@ -181,7 +181,7 @@ impl Interactions {
})
}
Interactions::Query(query) => query.dependencies(),
Interactions::Fault(_) => HashSet::new(),
Interactions::Fault(_) => IndexSet::new(),
}
}

View File

@@ -1,6 +1,7 @@
use std::{collections::HashSet, fmt::Display};
use std::fmt::Display;
use anyhow::Context;
use indexmap::IndexSet;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use sql_generation::model::{
@@ -32,19 +33,19 @@ pub enum Query {
}
impl Query {
pub fn dependencies(&self) -> HashSet<String> {
pub fn dependencies(&self) -> IndexSet<String> {
match self {
Query::Select(select) => select.dependencies(),
Query::Create(_) => HashSet::new(),
Query::Create(_) => IndexSet::new(),
Query::Insert(Insert::Select { table, .. })
| Query::Insert(Insert::Values { table, .. })
| Query::Delete(Delete { table, .. })
| Query::Update(Update { table, .. })
| Query::Drop(Drop { table, .. }) => HashSet::from_iter([table.clone()]),
| Query::Drop(Drop { table, .. }) => IndexSet::from_iter([table.clone()]),
Query::CreateIndex(CreateIndex { table_name, .. }) => {
HashSet::from_iter([table_name.clone()])
IndexSet::from_iter([table_name.clone()])
}
Query::Begin(_) | Query::Commit(_) | Query::Rollback(_) => HashSet::new(),
Query::Begin(_) | Query::Commit(_) | Query::Rollback(_) => IndexSet::new(),
}
}
pub fn uses(&self) -> Vec<String> {

View File

@@ -185,59 +185,6 @@ impl SimulatorEnv {
) -> Self {
let mut rng = ChaCha8Rng::seed_from_u64(seed);
let total = 100.0;
let mut create_percent = 0.0;
let mut create_index_percent = 0.0;
let mut drop_percent = 0.0;
let mut delete_percent = 0.0;
let mut update_percent = 0.0;
let read_percent = rng.random_range(0.0..=total);
let write_percent = total - read_percent;
if !cli_opts.disable_create {
// Create percent should be 5-15% of the write percent
create_percent = rng.random_range(0.05..=0.15) * write_percent;
}
if !cli_opts.disable_create_index {
// Create indexpercent should be 2-5% of the write percent
create_index_percent = rng.random_range(0.02..=0.05) * write_percent;
}
if !cli_opts.disable_drop {
// Drop percent should be 2-5% of the write percent
drop_percent = rng.random_range(0.02..=0.05) * write_percent;
}
if !cli_opts.disable_delete {
// Delete percent should be 10-20% of the write percent
delete_percent = rng.random_range(0.1..=0.2) * write_percent;
}
if !cli_opts.disable_update {
// Update percent should be 10-20% of the write percent
// TODO: freestyling the percentage
update_percent = rng.random_range(0.1..=0.2) * write_percent;
}
let write_percent = write_percent
- create_percent
- create_index_percent
- delete_percent
- drop_percent
- update_percent;
let summed_total: f64 = read_percent
+ write_percent
+ create_percent
+ create_index_percent
+ drop_percent
+ update_percent
+ delete_percent;
let abs_diff = (summed_total - total).abs();
if abs_diff > 0.0001 {
panic!("Summed total {summed_total} is not equal to total {total}");
}
let opts = SimulatorOpts {
seed,
ticks: rng.random_range(cli_opts.minimum_tests..=cli_opts.maximum_tests),

View File

@@ -21,6 +21,7 @@ anyhow = { workspace = true }
tracing = { workspace = true }
schemars = { workspace = true }
garde = { workspace = true, features = ["derive", "serde"] }
indexmap = { version = "2.11.0" }
[dev-dependencies]
rand_chacha = "0.9.0"

View File

@@ -10,6 +10,7 @@ use crate::model::query::select::{
use crate::model::query::update::Update;
use crate::model::query::{Create, CreateIndex, Delete, Drop, Insert, Select};
use crate::model::table::{JoinTable, JoinType, JoinedTable, SimValue, Table, TableContext};
use indexmap::IndexSet;
use itertools::Itertools;
use rand::Rng;
use turso_parser::ast::{Expr, SortOrder};
@@ -104,7 +105,7 @@ impl Arbitrary for SelectInner {
if order_by_col_count == 0 {
return None;
}
let mut col_names = std::collections::HashSet::new();
let mut col_names = IndexSet::new();
let mut order_by_cols = Vec::new();
while order_by_cols.len() < order_by_col_count {
let table = pick(&order_by_table_candidates, rng);

View File

@@ -1,5 +1,4 @@
use std::collections::HashSet;
use indexmap::IndexSet;
use rand::Rng;
use turso_core::Value;
@@ -28,7 +27,7 @@ impl Arbitrary for Table {
} else {
rng.random_range(opts.column_range)
} as usize;
let mut column_set = HashSet::with_capacity(column_size);
let mut column_set = IndexSet::with_capacity(column_size);
for col in std::iter::repeat_with(|| Column::arbitrary(rng, context)) {
column_set.insert(col);
if column_set.len() == column_size {

View File

@@ -1,6 +1,7 @@
use std::{collections::HashSet, fmt::Display};
use std::fmt::Display;
pub use ast::Distinctness;
use indexmap::IndexSet;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use turso_parser::ast::{
@@ -105,12 +106,12 @@ impl Select {
}
}
pub fn dependencies(&self) -> HashSet<String> {
pub fn dependencies(&self) -> IndexSet<String> {
if self.body.select.from.is_none() {
return HashSet::new();
return IndexSet::new();
}
let from = self.body.select.from.as_ref().unwrap();
let mut tables = HashSet::new();
let mut tables = IndexSet::new();
tables.insert(from.table.clone());
tables.extend(from.dependencies());