Skip to main content

mongreldb_sim/
lib.rs

1//! MongrelDB deterministic test simulator (spec section 9.5, FND-005).
2//!
3//! A seeded, reproducible environment for consensus and
4//! distributed-transaction tests: a virtual clock with per-node skew
5//! schedules, deterministic cooperative task scheduling, virtual network
6//! links with delay/drop/duplication/reordering and partition/heal,
7//! virtual durable disks with write/fsync/torn-write faults, and process
8//! crash/restart that preserves exactly the fsynced prefix.
9//!
10//! # Determinism contract
11//!
12//! Same seed ⇒ identical event order and identical outcomes. The
13//! contract rests on four rules the whole crate follows:
14//!
15//! - Every random decision flows through [`SimRng`], seeded once from
16//!   the scenario [`Seed`]. Subsystems receive independent streams via
17//!   [`SimRng::fork`] / [`SimRng::fork_label`], so drawing extra numbers
18//!   in one subsystem never perturbs another.
19//! - Time is virtual microseconds; the simulator never reads the wall
20//!   clock. The clock advances only when no task can run
21//!   ("advance-on-idle"), jumping straight to the next timer or message
22//!   delivery.
23//! - Scheduling is cooperative and single-threaded. When several tasks
24//!   are ready, the runtime's seeded stream picks the next one, fixing
25//!   the interleaving.
26//! - Only `BTreeMap`/`BTreeSet` are iterated on behavior-affecting
27//!   paths, so hash-randomized iteration order can never leak into a
28//!   run.
29//!
30//! # Why no async runtime
31//!
32//! The executor is deliberately std-only: no tokio, no other runtime.
33//! A production executor schedules on OS threads and reads the real
34//! clock, which makes runs irreproducible. Here a task is a boxed
35//! closure state machine ([`TaskBody`]) polled step by step by the
36//! seeded cooperative executor in [`runtime`], so every interleaving
37//! decision and every timer fires under simulator control.
38//!
39//! # Failure artifacts
40//!
41//! When a run fails (deadlock, step-limit exhaustion, or a task panic),
42//! [`Scenario::run`] / [`Scenario::run_with`] persist the seed and the
43//! full event log as JSON to `$MONGRELDB_SIM_FAILURES` (default
44//! `target/sim-failures/`) so CI can archive the exact repro.
45
46pub mod clock;
47pub mod disk;
48pub mod network;
49pub mod rng;
50pub mod runtime;
51pub mod scenario;
52
53pub use clock::{Clock, ClockError, Micros, SkewSchedule};
54pub use disk::{DiskError, VirtualDisk};
55pub use network::{
56    Delivery, DeliveryOutcome, DropReason, LinkConfig, Message, Network, NetworkStats, NodeId,
57    SendOutcome,
58};
59pub use rng::{Seed, SimRng};
60pub use runtime::{NodeContext, Runtime, TaskBody, TaskId, TaskState};
61pub use scenario::{
62    failure_dir, persist_failure_report, Event, RunOutcome, Scenario, ScenarioError,
63};