diff --git a/tests/gc/db.rs b/tests/gc/db.rs new file mode 100644 index 00000000..5883ebfd --- /dev/null +++ b/tests/gc/db.rs @@ -0,0 +1,26 @@ +use crate::group; + +#[derive(Default)] +pub struct DatabaseImpl { + runtime: salsa::Runtime, +} + +impl salsa::Database for DatabaseImpl { + fn salsa_runtime(&self) -> &salsa::Runtime { + &self.runtime + } +} + +salsa::database_storage! { + pub struct DatabaseImplStorage for DatabaseImpl { + impl group::GcDatabase { + fn min() for group::Min; + fn max() for group::Max; + fn use_triangular() for group::UseTriangular; + fn fibonacci() for group::Fibonacci; + fn triangular() for group::Triangular; + fn compute() for group::Compute; + fn compute_all() for group::ComputeAll; + } + } +} diff --git a/tests/gc/group.rs b/tests/gc/group.rs new file mode 100644 index 00000000..9be5f9e2 --- /dev/null +++ b/tests/gc/group.rs @@ -0,0 +1,64 @@ +salsa::query_group! { + pub(crate) trait GcDatabase: salsa::Database { + fn min() -> usize { + type Min; + storage input; + } + + fn max() -> usize { + type Max; + storage input; + } + + fn use_triangular(key: usize) -> bool { + type UseTriangular; + storage input; + } + + fn fibonacci(key: usize) -> usize { + type Fibonacci; + } + + fn triangular(key: usize) -> usize { + type Triangular; + } + + fn compute(key: usize) -> usize { + type Compute; + } + + fn compute_all() -> Vec { + type ComputeAll; + } + } +} + +fn fibonacci(db: &impl GcDatabase, key: usize) -> usize { + if key == 0 { + 0 + } else if key == 1 { + 1 + } else { + db.fibonacci(key - 1) + db.fibonacci(key - 2) + } +} + +fn triangular(db: &impl GcDatabase, key: usize) -> usize { + if key == 0 { + 0 + } else { + db.triangular(key - 1) + key + } +} + +fn compute(db: &impl GcDatabase, key: usize) -> usize { + if db.use_triangular(key) { + db.triangular(key) + } else { + db.fibonacci(key) + } +} + +fn compute_all(db: &impl GcDatabase) -> Vec { + (db.min()..db.max()).map(|v| db.compute(v)).collect() +} diff --git a/tests/gc/main.rs b/tests/gc/main.rs new file mode 100644 index 00000000..04300a1e --- /dev/null +++ b/tests/gc/main.rs @@ -0,0 +1,4 @@ +mod db; +mod derived_tests; +mod group; +mod shallow_constant_tests; diff --git a/tests/gc/shallow_constant_tests.rs b/tests/gc/shallow_constant_tests.rs new file mode 100644 index 00000000..bda164c3 --- /dev/null +++ b/tests/gc/shallow_constant_tests.rs @@ -0,0 +1,86 @@ +use crate::db; +use crate::group::{Fibonacci, GcDatabase}; +use salsa::debug::DebugQueryTable; +use salsa::Database; + +// For constant values (like `fibonacci`), we only keep the values +// that were used in the latest revision, not the sub-values that +// they required to be computed. + +#[test] +fn one_rev() { + let db = db::DatabaseImpl::default(); + + db.fibonacci(5); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k.len(), 6); + + // Everything was used in this revision, so + // nothing gets collected. + db.sweep_all(); + assert_eq!(k.len(), 6); +} + +#[test] +fn two_rev_nothing() { + let db = db::DatabaseImpl::default(); + + db.fibonacci(5); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k.len(), 6); + + db.salsa_runtime().next_revision(); + + // Nothing was used in this revision, so + // everything gets collected. + db.sweep_all(); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k.len(), 0); +} + +#[test] +fn two_rev_one_use() { + let db = db::DatabaseImpl::default(); + + db.fibonacci(5); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k.len(), 6); + + db.salsa_runtime().next_revision(); + + db.fibonacci(5); + + // fibonacci is a constant, so it will not be invalidated, + // hence we keep `fibonacci(5)` but remove 0..=4. + db.sweep_all(); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k, vec![5]); +} + +#[test] +fn two_rev_two_uses() { + let db = db::DatabaseImpl::default(); + + db.fibonacci(5); + + let k: Vec<_> = db.query(Fibonacci).keys(); + assert_eq!(k.len(), 6); + + db.salsa_runtime().next_revision(); + + db.fibonacci(5); + db.fibonacci(3); + + // fibonacci is a constant, so it will not be invalidated, + // hence we keep 3 and 5 but remove the rest. + db.sweep_all(); + + let mut k: Vec<_> = db.query(Fibonacci).keys(); + k.sort(); + assert_eq!(k, vec![3, 5]); +}