mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
fix formatting
This commit is contained in:
parent
be18c6e8f0
commit
53ecedaceb
8 changed files with 79 additions and 31 deletions
|
@ -1,2 +1,74 @@
|
|||
# Simulator
|
||||
# Limbo Simulator
|
||||
|
||||
Limbo simulator uses randomized deterministic simulations to test the Limbo database behaviors.
|
||||
|
||||
Each simulations begins with a random configurations;
|
||||
|
||||
- the database workload distribution(percentages of reads, writes, deletes...),
|
||||
- database parameters(page size),
|
||||
- number of reader or writers, etc.
|
||||
|
||||
Based on these parameters, we randomly generate **interaction plans**. Interaction plans consist of statements/queries, and assertions that will be executed in order. The building blocks of interaction plans are;
|
||||
|
||||
- Randomly generated SQL queries satisfying the workload distribution,
|
||||
- Properties, which contain multiple matching queries with assertions indicating the expected result.
|
||||
|
||||
An example of a property is the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Read your own writes",
|
||||
"queries": [
|
||||
"INSERT INTO t1 (id) VALUES (1)",
|
||||
"SELECT * FROM t1 WHERE id = 1",
|
||||
],
|
||||
"assertions": [
|
||||
"result.rows.length == 1",
|
||||
"result.rows[0].id == 1"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The simulator executes the interaction plans in a loop, and checks the assertions. It can add random queries unrelated to the properties without
|
||||
breaking the property invariants to reach more diverse states and respect the configured workload distribution.
|
||||
|
||||
The simulator code is broken into 4 main parts:
|
||||
|
||||
- **Simulator(main.rs)**: The main entry point of the simulator. It generates random configurations and interaction plans, and executes them.
|
||||
- **Model(model.rs, model/table.rs, model/query.rs)**: A simpler model of the database, it contains atomic actions for insertion and selection, we use this model while deciding the next actions.
|
||||
- **Generation(generation.rs, generation/table.rs, generation/query.rs, generation/plan.rs)**: Random generation functions for the database model and interaction plans.
|
||||
- **Properties(properties.rs)**: Contains the properties that we want to test.
|
||||
|
||||
## Running the simulator
|
||||
|
||||
To run the simulator, you can use the following command:
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
```
|
||||
|
||||
This prompt (in the future) will invoke a clap command line interface to configure the simulator. For now, the simulator runs with the default configurations changing the `main.rs` file. If you want to see the logs, you can change the `RUST_LOG` environment variable.
|
||||
|
||||
```bash
|
||||
RUST_LOG=info cargo run --bin limbo_sim
|
||||
```
|
||||
|
||||
## Adding new properties
|
||||
|
||||
Todo
|
||||
|
||||
## Adding new generation functions
|
||||
|
||||
Todo
|
||||
|
||||
## Adding new models
|
||||
|
||||
Todo
|
||||
|
||||
## Coverage with Limbo
|
||||
|
||||
Todo
|
||||
|
||||
## Automatic Compatibility Testing with SQLite
|
||||
|
||||
Todo
|
|
@ -1,8 +1,8 @@
|
|||
use anarchist_readable_name_generator_lib::readable_name_custom;
|
||||
use rand::Rng;
|
||||
|
||||
pub mod table;
|
||||
pub mod query;
|
||||
pub mod table;
|
||||
|
||||
pub trait Arbitrary {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self;
|
||||
|
@ -12,7 +12,6 @@ pub trait ArbitraryFrom<T> {
|
|||
fn arbitrary_from<R: Rng>(rng: &mut R, t: &T) -> Self;
|
||||
}
|
||||
|
||||
|
||||
fn gen_random_text<T: Rng>(rng: &mut T) -> String {
|
||||
let big_text = rng.gen_ratio(1, 1000);
|
||||
if big_text {
|
||||
|
@ -28,5 +27,3 @@ fn gen_random_text<T: Rng>(rng: &mut T) -> String {
|
|||
name.replace("-", "_")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
use crate::generation::table::{GTValue, LTValue};
|
||||
use crate::generation::{Arbitrary, ArbitraryFrom};
|
||||
use crate::generation::table::{LTValue, GTValue};
|
||||
|
||||
use crate::model::query::{Create, Delete, Insert, Predicate, Query, Select};
|
||||
use crate::model::table::{Table, Value};
|
||||
use rand::Rng;
|
||||
|
||||
|
||||
impl Arbitrary for Create {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
Create {
|
||||
|
@ -15,7 +13,6 @@ impl Arbitrary for Create {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl ArbitraryFrom<Vec<Table>> for Select {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<Table>) -> Self {
|
||||
let table = rng.gen_range(0..tables.len());
|
||||
|
@ -36,7 +33,6 @@ impl ArbitraryFrom<Vec<&Table>> for Select {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl ArbitraryFrom<Table> for Insert {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
let values = table
|
||||
|
@ -51,7 +47,6 @@ impl ArbitraryFrom<Table> for Insert {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl ArbitraryFrom<Table> for Delete {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
Delete {
|
||||
|
@ -75,7 +70,6 @@ impl ArbitraryFrom<Table> for Query {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct CompoundPredicate(Predicate);
|
||||
struct SimplePredicate(Predicate);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
use rand::Rng;
|
||||
|
||||
use crate::generation::{Arbitrary, ArbitraryFrom, readable_name_custom, gen_random_text};
|
||||
use crate::generation::{gen_random_text, readable_name_custom, Arbitrary, ArbitraryFrom};
|
||||
use crate::model::table::{Column, ColumnType, Name, Table, Value};
|
||||
|
||||
impl Arbitrary for Name {
|
||||
|
@ -11,7 +10,6 @@ impl Arbitrary for Name {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Arbitrary for Table {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
let name = Name::arbitrary(rng).0;
|
||||
|
@ -39,7 +37,6 @@ impl Arbitrary for Column {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Arbitrary for ColumnType {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
match rng.gen_range(0..4) {
|
||||
|
@ -193,4 +190,3 @@ impl ArbitraryFrom<Value> for GTValue {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use generation::{Arbitrary, ArbitraryFrom};
|
||||
use limbo_core::{Connection, Database, File, OpenFlags, PlatformIO, Result, RowResult, IO};
|
||||
use model::table::{Column, Name, Table, Value};
|
||||
use model::query::{Insert, Predicate, Query, Select};
|
||||
use model::table::{Column, Name, Table, Value};
|
||||
use properties::{property_insert_select, property_select_all};
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
@ -11,8 +11,8 @@ use std::sync::Arc;
|
|||
use tempfile::TempDir;
|
||||
|
||||
mod generation;
|
||||
mod properties;
|
||||
mod model;
|
||||
mod properties;
|
||||
|
||||
struct SimulatorEnv {
|
||||
opts: SimulatorOpts,
|
||||
|
@ -49,8 +49,6 @@ struct SimulatorOpts {
|
|||
page_size: usize,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
fn main() {
|
||||
let _ = env_logger::try_init();
|
||||
|
@ -137,7 +135,6 @@ fn main() {
|
|||
env.io.print_stats();
|
||||
}
|
||||
|
||||
|
||||
fn process_connection(env: &mut SimulatorEnv, conn: &mut Rc<Connection>) -> Result<()> {
|
||||
if env.tables.is_empty() {
|
||||
maybe_add_table(env, conn)?;
|
||||
|
@ -250,8 +247,6 @@ fn maybe_add_table(env: &mut SimulatorEnv, conn: &mut Rc<Connection>) -> Result<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn get_all_rows(
|
||||
env: &mut SimulatorEnv,
|
||||
conn: &mut Rc<Connection>,
|
||||
|
@ -477,4 +472,3 @@ impl Drop for SimulatorFile {
|
|||
self.inner.unlock_file().expect("Failed to unlock file");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
|
||||
pub mod table;
|
||||
pub mod query;
|
||||
pub mod table;
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::fmt::Display;
|
|||
|
||||
use crate::model::table::{Table, Value};
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum Predicate {
|
||||
And(Vec<Predicate>), // p1 AND p2 AND p3... AND pn
|
||||
|
@ -108,4 +107,3 @@ impl Display for Query {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
use std::{fmt::Display, ops::Deref};
|
||||
|
||||
pub(crate) struct Name(pub(crate) String);
|
||||
|
@ -88,4 +87,3 @@ impl Display for Value {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue