mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-22 21:05:11 +00:00
Support on-demand inputs
This adds initial support for on-demand inputs by allowing new inputs to be created with only a shared reference to the database. This allows creating new inputs during a revision and therefore from inside tracked functions.
This commit is contained in:
parent
f8f6dbd349
commit
5b8464c4f9
29 changed files with 108 additions and 107 deletions
|
@ -33,8 +33,8 @@ mod parser;
|
|||
mod type_check;
|
||||
|
||||
pub fn main() {
|
||||
let mut db = db::Database::default();
|
||||
let source_program = SourceProgram::new(&mut db, String::new());
|
||||
let db = db::Database::default();
|
||||
let source_program = SourceProgram::new(&db, String::new());
|
||||
compile::compile(&db, source_program);
|
||||
let diagnostics = compile::compile::accumulated::<Diagnostics>(&db, source_program);
|
||||
eprintln!("{diagnostics:?}");
|
||||
|
|
|
@ -355,10 +355,10 @@ fn parse_string(source_text: &str) -> String {
|
|||
use salsa::debug::DebugWithDb;
|
||||
|
||||
// Create the database
|
||||
let mut db = crate::db::Database::default();
|
||||
let db = crate::db::Database::default();
|
||||
|
||||
// Create the source program
|
||||
let source_program = SourceProgram::new(&mut db, source_text.to_string());
|
||||
let source_program = SourceProgram::new(&db, source_text.to_string());
|
||||
|
||||
// Invoke the parser
|
||||
let statements = parse_statements(&db, source_program);
|
||||
|
|
|
@ -97,7 +97,7 @@ fn check_string(
|
|||
let mut db = Database::default().enable_logging();
|
||||
|
||||
// Create the source program
|
||||
let source_program = SourceProgram::new(&mut db, source_text.to_string());
|
||||
let source_program = SourceProgram::new(&db, source_text.to_string());
|
||||
|
||||
// Invoke the parser
|
||||
let program = parse_statements(&db, source_program);
|
||||
|
|
|
@ -130,10 +130,10 @@ impl InputStruct {
|
|||
|
||||
let constructor: syn::ImplItemMethod = if singleton {
|
||||
parse_quote! {
|
||||
pub fn #constructor_name(__db: &mut #db_dyn_ty, #(#field_names: #field_tys,)*) -> Self
|
||||
pub fn #constructor_name(__db: &#db_dyn_ty, #(#field_names: #field_tys,)*) -> Self
|
||||
{
|
||||
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar_mut(__db);
|
||||
let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient_mut(__jar);
|
||||
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db);
|
||||
let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar);
|
||||
let __id = __ingredients.#input_index.new_singleton_input(__runtime);
|
||||
#(
|
||||
__ingredients.#field_indices.store(__runtime, __id, #field_names, salsa::Durability::LOW);
|
||||
|
@ -143,10 +143,10 @@ impl InputStruct {
|
|||
}
|
||||
} else {
|
||||
parse_quote! {
|
||||
pub fn #constructor_name(__db: &mut #db_dyn_ty, #(#field_names: #field_tys,)*) -> Self
|
||||
pub fn #constructor_name(__db: &#db_dyn_ty, #(#field_names: #field_tys,)*) -> Self
|
||||
{
|
||||
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar_mut(__db);
|
||||
let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient_mut(__jar);
|
||||
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db);
|
||||
let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar);
|
||||
let __id = __ingredients.#input_index.new_input(__runtime);
|
||||
#(
|
||||
__ingredients.#field_indices.store(__runtime, __id, #field_names, salsa::Durability::LOW);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use std::fmt;
|
||||
use std::{
|
||||
fmt,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
cycle::CycleRecoveryStrategy,
|
||||
|
@ -16,7 +19,7 @@ where
|
|||
Id: InputId,
|
||||
{
|
||||
ingredient_index: IngredientIndex,
|
||||
counter: u32,
|
||||
counter: AtomicU32,
|
||||
debug_name: &'static str,
|
||||
_phantom: std::marker::PhantomData<Id>,
|
||||
}
|
||||
|
@ -41,24 +44,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_input(&mut self, _runtime: &mut Runtime) -> Id {
|
||||
let next_id = self.counter;
|
||||
self.counter += 1;
|
||||
pub fn new_input(&self, _runtime: &Runtime) -> Id {
|
||||
let next_id = self.counter.fetch_add(1, Ordering::Relaxed);
|
||||
Id::from_id(crate::Id::from_u32(next_id))
|
||||
}
|
||||
|
||||
pub fn new_singleton_input(&mut self, _runtime: &mut Runtime) -> Id {
|
||||
if self.counter >= 1 {
|
||||
// already exists
|
||||
Id::from_id(crate::Id::from_u32(self.counter - 1))
|
||||
} else {
|
||||
self.new_input(_runtime)
|
||||
}
|
||||
pub fn new_singleton_input(&self, _runtime: &Runtime) -> Id {
|
||||
// There's only one singleton so record that we've created it
|
||||
// and return the only id.
|
||||
self.counter.store(1, Ordering::Relaxed);
|
||||
Id::from_id(crate::Id::from_u32(0))
|
||||
}
|
||||
|
||||
pub fn get_singleton_input(&self, _runtime: &Runtime) -> Option<Id> {
|
||||
(self.counter > 0)
|
||||
.then(|| Id::from_id(crate::Id::from_id(crate::Id::from_u32(self.counter - 1))))
|
||||
(self.counter.load(Ordering::Relaxed) > 0).then(|| Id::from_id(crate::Id::from_u32(0)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::key::DependencyIndex;
|
|||
use crate::runtime::local_state::QueryOrigin;
|
||||
use crate::runtime::StampedValue;
|
||||
use crate::{AsId, DatabaseKeyIndex, Durability, Id, IngredientIndex, Revision, Runtime};
|
||||
use rustc_hash::FxHashMap;
|
||||
use dashmap::DashMap;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
|
@ -15,7 +15,7 @@ use std::hash::Hash;
|
|||
/// This makes the implementation considerably simpler.
|
||||
pub struct InputFieldIngredient<K, F> {
|
||||
index: IngredientIndex,
|
||||
map: FxHashMap<K, StampedValue<F>>,
|
||||
map: DashMap<K, StampedValue<F>>,
|
||||
debug_name: &'static str,
|
||||
}
|
||||
|
||||
|
@ -31,13 +31,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn store(
|
||||
&mut self,
|
||||
runtime: &mut Runtime,
|
||||
key: K,
|
||||
value: F,
|
||||
durability: Durability,
|
||||
) -> Option<F> {
|
||||
pub fn store(&self, runtime: &Runtime, key: K, value: F, durability: Durability) -> Option<F> {
|
||||
let revision = runtime.current_revision();
|
||||
let stamped_value = StampedValue {
|
||||
value,
|
||||
|
@ -52,12 +46,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fetch(&self, runtime: &Runtime, key: K) -> &F {
|
||||
pub fn fetch<'db>(&'db self, runtime: &'db Runtime, key: K) -> &F {
|
||||
let StampedValue {
|
||||
value,
|
||||
durability,
|
||||
changed_at,
|
||||
} = self.map.get(&key).unwrap();
|
||||
} = &*self.map.get(&key).unwrap();
|
||||
|
||||
runtime.report_tracked_read(
|
||||
self.database_key_index(key).into(),
|
||||
|
@ -65,7 +59,9 @@ where
|
|||
*changed_at,
|
||||
);
|
||||
|
||||
value
|
||||
// SAFETY:
|
||||
// * Values are only removed or altered when we have `&mut self`
|
||||
unsafe { transmute_lifetime(self, value) }
|
||||
}
|
||||
|
||||
fn database_key_index(&self, key: K) -> DatabaseKeyIndex {
|
||||
|
@ -76,6 +72,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Returns `u` but with the lifetime of `t`.
|
||||
//
|
||||
// Safe if you know that data at `u` will remain shared
|
||||
// until the reference `t` expires.
|
||||
unsafe fn transmute_lifetime<'t, 'u, T, U>(_t: &'t T, u: &'u U) -> &'t U {
|
||||
std::mem::transmute(u)
|
||||
}
|
||||
|
||||
impl<DB: ?Sized, K, F> Ingredient<DB> for InputFieldIngredient<K, F>
|
||||
where
|
||||
K: AsId,
|
||||
|
|
|
@ -65,8 +65,8 @@ impl HasLogger for Database {
|
|||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let l0 = List::new(&mut db, 1, None);
|
||||
let l1 = List::new(&mut db, 10, Some(l0));
|
||||
let l0 = List::new(&db, 1, None);
|
||||
let l1 = List::new(&db, 10, Some(l0));
|
||||
|
||||
compute(&db, l1);
|
||||
expect![[r#"
|
||||
|
|
|
@ -69,8 +69,8 @@ impl HasLogger for Database {
|
|||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let l1 = List::new(&mut db, 1, None);
|
||||
let l2 = List::new(&mut db, 2, Some(l1));
|
||||
let l1 = List::new(&db, 1, None);
|
||||
let l2 = List::new(&db, 2, Some(l1));
|
||||
|
||||
assert_eq!(compute(&db, l2), 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
|
|
|
@ -64,8 +64,8 @@ impl HasLogger for Database {
|
|||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let l1 = List::new(&mut db, 1, None);
|
||||
let l2 = List::new(&mut db, 2, Some(l1));
|
||||
let l1 = List::new(&db, 1, None);
|
||||
let l2 = List::new(&db, 2, Some(l1));
|
||||
|
||||
assert_eq!(compute(&db, l2), 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
|
|
|
@ -85,7 +85,7 @@ fn accumulate_once() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// Just call accumulate on a base input to see what happens.
|
||||
let input = MyInput::new(&mut db, 2, 3);
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
let logs = push_logs::accumulated::<Logs>(&db, input);
|
||||
expect![[r#"
|
||||
[
|
||||
|
@ -109,7 +109,7 @@ fn change_a_and_reaccumulate() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// Accumulate logs for `a = 2` and `b = 3`
|
||||
let input = MyInput::new(&mut db, 2, 3);
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
let logs = push_logs::accumulated::<Logs>(&db, input);
|
||||
expect![[r#"
|
||||
[
|
||||
|
@ -148,7 +148,7 @@ fn get_a_logs_after_changing_b() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// Invoke `push_a_logs` with `a = 2` and `b = 3` (but `b` doesn't matter)
|
||||
let input = MyInput::new(&mut db, 2, 3);
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
let logs = push_a_logs::accumulated::<Logs>(&db, input);
|
||||
expect![[r#"
|
||||
[
|
||||
|
|
|
@ -183,7 +183,7 @@ fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle {
|
|||
#[test]
|
||||
fn cycle_memoized() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db);
|
||||
let input = MyInput::new(&db);
|
||||
let cycle = extract_cycle(|| memoized_a(&db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
|
@ -197,7 +197,7 @@ fn cycle_memoized() {
|
|||
#[test]
|
||||
fn cycle_volatile() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db);
|
||||
let input = MyInput::new(&db);
|
||||
let cycle = extract_cycle(|| volatile_a(&db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
|
@ -215,7 +215,7 @@ fn expect_cycle() {
|
|||
// +-----+
|
||||
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ fn inner_cycle() {
|
|||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::B);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::B);
|
||||
let err = cycle_c(&db, abc);
|
||||
assert!(err.is_err());
|
||||
let expected = expect![[r#"
|
||||
|
@ -243,7 +243,7 @@ fn cycle_revalidate() {
|
|||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
abc.set_b(&mut db).to(CycleQuery::A); // same value as default
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
@ -255,7 +255,7 @@ fn cycle_recovery_unchanged_twice() {
|
|||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
||||
abc.set_c(&mut db).to(CycleQuery::A); // force new revision
|
||||
|
@ -267,7 +267,7 @@ fn cycle_appears() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// A --> B
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::None, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::None, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_ok());
|
||||
|
||||
// A --> B
|
||||
|
@ -284,7 +284,7 @@ fn cycle_disappears() {
|
|||
// A --> B
|
||||
// ^ |
|
||||
// +-----+
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
||||
// A --> B
|
||||
|
@ -334,7 +334,7 @@ fn cycle_mixed_1() {
|
|||
// A --> B <-- C
|
||||
// | ^
|
||||
// +-----+
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::C, CycleQuery::B);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::C, CycleQuery::B);
|
||||
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
|
@ -354,7 +354,7 @@ fn cycle_mixed_2() {
|
|||
// A --> B --> C
|
||||
// ^ |
|
||||
// +-----------+
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::C, CycleQuery::A);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::C, CycleQuery::A);
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_a(0)",
|
||||
|
@ -374,7 +374,7 @@ fn cycle_deterministic_order() {
|
|||
// A --> B
|
||||
// ^ |
|
||||
// +-----+
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
(db, abc)
|
||||
};
|
||||
let (db, abc) = f();
|
||||
|
@ -411,7 +411,7 @@ fn cycle_multiple() {
|
|||
//
|
||||
// Here, conceptually, B encounters a cycle with A and then
|
||||
// recovers.
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::AthenC, CycleQuery::A);
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::AthenC, CycleQuery::A);
|
||||
|
||||
let c = cycle_c(&db, abc);
|
||||
let b = cycle_b(&db, abc);
|
||||
|
@ -446,7 +446,7 @@ fn cycle_recovery_set_but_not_participating() {
|
|||
// A --> C -+
|
||||
// ^ |
|
||||
// +--+
|
||||
let abc = ABC::new(&mut db, CycleQuery::C, CycleQuery::None, CycleQuery::C);
|
||||
let abc = ABC::new(&db, CycleQuery::C, CycleQuery::None, CycleQuery::C);
|
||||
|
||||
// Here we expect C to panic and A not to recover:
|
||||
let r = extract_cycle(|| drop(cycle_a(&db, abc)));
|
||||
|
|
|
@ -36,13 +36,13 @@ impl Db for Database {}
|
|||
|
||||
#[test]
|
||||
fn input() {
|
||||
let mut db = Database::default();
|
||||
let db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
let not_salsa = NotSalsa {
|
||||
field: "it's salsa time".to_string(),
|
||||
};
|
||||
let complex_struct = ComplexStruct::new(&mut db, input, not_salsa);
|
||||
let complex_struct = ComplexStruct::new(&db, input, not_salsa);
|
||||
|
||||
// default debug only includes identity fields
|
||||
let actual = format!("{:?}", complex_struct.debug(&db));
|
||||
|
|
|
@ -91,7 +91,7 @@ fn basic() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// Creates 3 tracked structs
|
||||
let input = MyInput::new(&mut db, 3);
|
||||
let input = MyInput::new(&db, 3);
|
||||
assert_eq!(final_result(&db, input), 2 * 2 + 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -84,7 +84,7 @@ fn basic() {
|
|||
let mut db = Database::default();
|
||||
|
||||
// Creates 3 tracked structs
|
||||
let input = MyInput::new(&mut db, 3);
|
||||
let input = MyInput::new(&db, 3);
|
||||
assert_eq!(final_result(&db, input), 2 * 2 + 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -74,7 +74,7 @@ fn execute() {
|
|||
// intermediate results:
|
||||
// x = (22 + 1) / 2 = 11
|
||||
// y = 22 / 2 = 11
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result_depends_on_x(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -53,7 +53,7 @@ fn execute() {
|
|||
// result_depends_on_y = y - 1
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22, 33);
|
||||
let input = MyInput::new(&db, 22, 33);
|
||||
assert_eq!(result_depends_on_x(&db, input), 23);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -54,7 +54,7 @@ impl HasLogger for Database {
|
|||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -85,7 +85,7 @@ fn execute() {
|
|||
fn red_herring() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -96,7 +96,7 @@ fn red_herring() {
|
|||
// Create a distinct input and mutate it.
|
||||
// This will trigger a new revision in the database
|
||||
// but shouldn't actually invalidate our existing ones.
|
||||
let input2 = MyInput::new(&mut db, 44);
|
||||
let input2 = MyInput::new(&db, 44);
|
||||
input2.set_field(&mut db).to(66);
|
||||
|
||||
// Re-run the query on the original input. Nothing re-executes!
|
||||
|
|
|
@ -82,28 +82,26 @@ fn load_n_potatoes() -> usize {
|
|||
|
||||
#[test]
|
||||
fn lru_works() {
|
||||
let mut db = DatabaseImpl::default();
|
||||
let db = DatabaseImpl::default();
|
||||
assert_eq!(load_n_potatoes(), 0);
|
||||
|
||||
for i in 0..128u32 {
|
||||
let input = MyInput::new(&mut db, i);
|
||||
let input = MyInput::new(&db, i);
|
||||
let p = get_hot_potato(&db, input);
|
||||
assert_eq!(p.0, i)
|
||||
}
|
||||
|
||||
// Create a new input to change the revision, and trigger the GC
|
||||
MyInput::new(&mut db, 0);
|
||||
MyInput::new(&db, 0);
|
||||
assert_eq!(load_n_potatoes(), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lru_doesnt_break_volatile_queries() {
|
||||
let mut db = DatabaseImpl::default();
|
||||
let db = DatabaseImpl::default();
|
||||
|
||||
// Create all inputs first, so that there are no revision changes among calls to `get_volatile`
|
||||
let inputs: Vec<MyInput> = (0..128usize)
|
||||
.map(|i| MyInput::new(&mut db, i as u32))
|
||||
.collect();
|
||||
let inputs: Vec<MyInput> = (0..128usize).map(|i| MyInput::new(&db, i as u32)).collect();
|
||||
|
||||
// Here, we check that we execute each volatile query at most once, despite
|
||||
// LRU. That does mean that we have more values in DB than the LRU capacity,
|
||||
|
@ -118,10 +116,10 @@ fn lru_doesnt_break_volatile_queries() {
|
|||
|
||||
#[test]
|
||||
fn lru_can_be_changed_at_runtime() {
|
||||
let mut db = DatabaseImpl::default();
|
||||
let db = DatabaseImpl::default();
|
||||
assert_eq!(load_n_potatoes(), 0);
|
||||
|
||||
let inputs: Vec<(u32, MyInput)> = (0..128).map(|i| (i, MyInput::new(&mut db, i))).collect();
|
||||
let inputs: Vec<(u32, MyInput)> = (0..128).map(|i| (i, MyInput::new(&db, i))).collect();
|
||||
|
||||
for &(i, input) in inputs.iter() {
|
||||
let p = get_hot_potato(&db, input);
|
||||
|
@ -129,7 +127,7 @@ fn lru_can_be_changed_at_runtime() {
|
|||
}
|
||||
|
||||
// Create a new input to change the revision, and trigger the GC
|
||||
MyInput::new(&mut db, 0);
|
||||
MyInput::new(&db, 0);
|
||||
assert_eq!(load_n_potatoes(), 32);
|
||||
|
||||
get_hot_potato::set_lru_capacity(&db, 64);
|
||||
|
@ -140,7 +138,7 @@ fn lru_can_be_changed_at_runtime() {
|
|||
}
|
||||
|
||||
// Create a new input to change the revision, and trigger the GC
|
||||
MyInput::new(&mut db, 0);
|
||||
MyInput::new(&db, 0);
|
||||
assert_eq!(load_n_potatoes(), 64);
|
||||
|
||||
// Special case: setting capacity to zero disables LRU
|
||||
|
@ -152,7 +150,7 @@ fn lru_can_be_changed_at_runtime() {
|
|||
}
|
||||
|
||||
// Create a new input to change the revision, and trigger the GC
|
||||
MyInput::new(&mut db, 0);
|
||||
MyInput::new(&db, 0);
|
||||
assert_eq!(load_n_potatoes(), 128);
|
||||
|
||||
drop(db);
|
||||
|
@ -167,7 +165,7 @@ fn lru_keeps_dependency_info() {
|
|||
// Invoke `get_hot_potato2` 33 times. This will (in turn) invoke
|
||||
// `get_hot_potato`, which will trigger LRU after 32 executions.
|
||||
let inputs: Vec<MyInput> = (0..(capacity + 1))
|
||||
.map(|i| MyInput::new(&mut db, i as u32))
|
||||
.map(|i| MyInput::new(&db, i as u32))
|
||||
.collect();
|
||||
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
|
|
|
@ -36,7 +36,7 @@ impl HasLogger for Database {
|
|||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, "Hello".to_string());
|
||||
let input = MyInput::new(&db, "Hello".to_string());
|
||||
|
||||
// Overwrite field with an empty String
|
||||
// and store the old value in my_string
|
||||
|
|
|
@ -92,10 +92,10 @@ fn recover_b2(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let db = Database::default();
|
||||
db.knobs().signal_on_will_block.set(3);
|
||||
|
||||
let input = MyInput::new(&mut db, 1);
|
||||
let input = MyInput::new(&db, 1);
|
||||
|
||||
let thread_a = std::thread::spawn({
|
||||
let db = db.snapshot();
|
||||
|
|
|
@ -87,10 +87,10 @@ fn recover_b3(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let db = Database::default();
|
||||
db.knobs().signal_on_will_block.set(3);
|
||||
|
||||
let input = MyInput::new(&mut db, 1);
|
||||
let input = MyInput::new(&db, 1);
|
||||
|
||||
let thread_a = std::thread::spawn({
|
||||
let db = db.snapshot();
|
||||
|
|
|
@ -43,10 +43,10 @@ pub(crate) fn b(db: &dyn Db, input: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let db = Database::default();
|
||||
db.knobs().signal_on_will_block.set(3);
|
||||
|
||||
let input = MyInput::new(&mut db, -1);
|
||||
let input = MyInput::new(&db, -1);
|
||||
|
||||
let thread_a = std::thread::spawn({
|
||||
let db = db.snapshot();
|
||||
|
|
|
@ -76,10 +76,10 @@ pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let db = Database::default();
|
||||
db.knobs().signal_on_will_block.set(3);
|
||||
|
||||
let input = MyInput::new(&mut db, 1);
|
||||
let input = MyInput::new(&db, 1);
|
||||
|
||||
let thread_a = std::thread::spawn({
|
||||
let db = db.snapshot();
|
||||
|
|
|
@ -56,6 +56,6 @@ impl Db for Database {}
|
|||
#[should_panic]
|
||||
fn execute_when_specified() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ impl HasLogger for Database {
|
|||
fn test_run_0() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 0);
|
||||
let input = MyInput::new(&db, 0);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -110,7 +110,7 @@ fn test_run_0() {
|
|||
fn test_run_5() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 5);
|
||||
let input = MyInput::new(&db, 5);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -131,7 +131,7 @@ fn test_run_5() {
|
|||
fn test_run_10() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 10);
|
||||
let input = MyInput::new(&db, 10);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -155,7 +155,7 @@ fn test_run_10() {
|
|||
fn test_run_20() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 20);
|
||||
let input = MyInput::new(&db, 20);
|
||||
assert_eq!(final_result(&db, input), 200);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -183,7 +183,7 @@ fn test_run_0_then_5_then_20() {
|
|||
//
|
||||
// * `create_tracked` specifies `10` for `maybe_specified`
|
||||
// * final resuilt of `100` is derived by executing `read_maybe_specified`
|
||||
let input = MyInput::new(&mut db, 0);
|
||||
let input = MyInput::new(&db, 0);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -254,7 +254,7 @@ fn test_run_0_then_5_then_10_then_20() {
|
|||
//
|
||||
// * `create_tracked` specifies `10` for `maybe_specified`
|
||||
// * final resuilt of `100` is derived by executing `read_maybe_specified`
|
||||
let input = MyInput::new(&mut db, 0);
|
||||
let input = MyInput::new(&db, 0);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -342,7 +342,7 @@ fn test_run_0_then_5_then_10_then_20() {
|
|||
fn test_run_5_then_20() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 5);
|
||||
let input = MyInput::new(&db, 5);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -30,6 +30,6 @@ fn execute() {
|
|||
impl Db for Database {}
|
||||
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input), 44);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ impl Db for Database {}
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let db = Database::default();
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input).field(&db), 44);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ impl Db for Database {}
|
|||
#[test]
|
||||
fn execute_when_specified() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
assert_eq!(tracked.field(&db), 44);
|
||||
assert_eq!(tracked_fn_extra(&db, tracked), 2222);
|
||||
|
@ -53,7 +53,7 @@ fn execute_when_specified() {
|
|||
#[test]
|
||||
fn execute_when_not_specified() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 0);
|
||||
let input = MyInput::new(&db, 0);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
assert_eq!(tracked.field(&db), 0);
|
||||
assert_eq!(tracked_fn_extra(&db, tracked), 0);
|
||||
|
|
|
@ -55,7 +55,7 @@ impl HasLogger for Database {
|
|||
fn one_entity() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -86,7 +86,7 @@ fn one_entity() {
|
|||
fn red_herring() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -97,7 +97,7 @@ fn red_herring() {
|
|||
// Create a distinct input and mutate it.
|
||||
// This will trigger a new revision in the database
|
||||
// but shouldn't actually invalidate our existing ones.
|
||||
let input2 = MyInput::new(&mut db, 44);
|
||||
let input2 = MyInput::new(&db, 44);
|
||||
input2.set_field(&mut db).to(66);
|
||||
|
||||
// Re-run the query on the original input. Nothing re-executes!
|
||||
|
|
Loading…
Reference in a new issue