From a263dd04bac6719c8da5878c593900aa6493a94e Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 5 Aug 2024 16:24:39 +0200 Subject: [PATCH] Fix query invalidation when high durability input changes --- .../src/setup_input_struct.rs | 6 ++-- src/input.rs | 11 ++++-- src/input/setter.rs | 12 +++---- src/zalsa.rs | 10 ++++-- .../tracked_fn_high_durability_dependency.rs | 36 +++++++++++++++++++ 5 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 tests/tracked_fn_high_durability_dependency.rs diff --git a/components/salsa-macro-rules/src/setup_input_struct.rs b/components/salsa-macro-rules/src/setup_input_struct.rs index ab2fbc6..f5a0f98 100644 --- a/components/salsa-macro-rules/src/setup_input_struct.rs +++ b/components/salsa-macro-rules/src/setup_input_struct.rs @@ -86,13 +86,13 @@ macro_rules! setup_input_struct { }) } - pub fn ingredient_mut(db: &mut dyn $zalsa::Database) -> (&mut $zalsa_struct::IngredientImpl, $zalsa::Revision) { + pub fn ingredient_mut(db: &mut dyn $zalsa::Database) -> (&mut $zalsa_struct::IngredientImpl, &mut $zalsa::Runtime) { let zalsa_mut = db.zalsa_mut(); let index = zalsa_mut.add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default()); let current_revision = zalsa_mut.current_revision(); - let ingredient = zalsa_mut.lookup_ingredient_mut(index); + let (ingredient, runtime) = zalsa_mut.lookup_ingredient_mut(index); let ingredient = ingredient.assert_type_mut::<$zalsa_struct::IngredientImpl>(); - (ingredient, current_revision) + (ingredient, runtime) } } diff --git a/src/input.rs b/src/input.rs index adcc768..1da42d7 100644 --- a/src/input.rs +++ b/src/input.rs @@ -20,7 +20,7 @@ use crate::{ plumbing::{Jar, Stamp}, zalsa::IngredientIndex, zalsa_local::QueryOrigin, - Database, Durability, Id, Revision, + Database, Durability, Id, Revision, Runtime, }; pub trait Configuration: Any { @@ -120,7 +120,7 @@ impl IngredientImpl { /// * `setter`, function that modifies the fields tuple; should only modify the element for `field_index` pub fn set_field( &mut self, - current_revision: Revision, + runtime: &mut Runtime, id: C::Struct, field_index: usize, durability: Durability, @@ -129,8 +129,13 @@ impl IngredientImpl { let id: Id = id.as_id(); let mut r = self.struct_map.update(id); let stamp = &mut r.stamps[field_index]; + + if stamp.durability != Durability::LOW { + runtime.report_tracked_write(stamp.durability); + } + stamp.durability = durability; - stamp.changed_at = current_revision; + stamp.changed_at = runtime.current_revision(); setter(&mut r.fields) } diff --git a/src/input/setter.rs b/src/input/setter.rs index e19d9c9..a976aad 100644 --- a/src/input/setter.rs +++ b/src/input/setter.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use crate::input::{Configuration, IngredientImpl}; -use crate::{Durability, Revision}; +use crate::{Durability, Runtime}; /// Setter for a field of an input. pub trait Setter: Sized { @@ -12,7 +12,7 @@ pub trait Setter: Sized { #[must_use] pub struct SetterImpl<'setter, C: Configuration, S, F> { - current_revision: Revision, + runtime: &'setter mut Runtime, id: C::Struct, ingredient: &'setter mut IngredientImpl, durability: Durability, @@ -27,14 +27,14 @@ where S: FnOnce(&mut C::Fields, F) -> F, { pub fn new( - current_revision: Revision, + runtime: &'setter mut Runtime, id: C::Struct, field_index: usize, ingredient: &'setter mut IngredientImpl, setter: S, ) -> Self { SetterImpl { - current_revision, + runtime, id, field_index, ingredient, @@ -59,7 +59,7 @@ where fn to(self, value: F) -> F { let Self { - current_revision, + runtime, id, ingredient, durability, @@ -68,7 +68,7 @@ where phantom: _, } = self; - ingredient.set_field(current_revision, id, field_index, durability, |tuple| { + ingredient.set_field(runtime, id, field_index, durability, |tuple| { setter(tuple, value) }) } diff --git a/src/zalsa.rs b/src/zalsa.rs index c91a02d..cdbba8a 100644 --- a/src/zalsa.rs +++ b/src/zalsa.rs @@ -172,8 +172,14 @@ impl Zalsa { } /// **NOT SEMVER STABLE** - pub fn lookup_ingredient_mut(&mut self, index: IngredientIndex) -> &mut dyn Ingredient { - &mut **self.ingredients_vec.get_mut(index.as_usize()).unwrap() + pub fn lookup_ingredient_mut( + &mut self, + index: IngredientIndex, + ) -> (&mut dyn Ingredient, &mut Runtime) { + ( + &mut **self.ingredients_vec.get_mut(index.as_usize()).unwrap(), + &mut self.runtime, + ) } /// **NOT SEMVER STABLE** diff --git a/tests/tracked_fn_high_durability_dependency.rs b/tests/tracked_fn_high_durability_dependency.rs new file mode 100644 index 0000000..a05be17 --- /dev/null +++ b/tests/tracked_fn_high_durability_dependency.rs @@ -0,0 +1,36 @@ +#![allow(warnings)] + +use salsa::plumbing::HasStorage; +use salsa::{Database, Durability, Setter}; + +mod common; +#[salsa::input] +struct MyInput { + field: u32, +} + +#[salsa::tracked] +fn tracked_fn(db: &dyn salsa::Database, input: MyInput) -> u32 { + input.field(db) * 2 +} + +#[test] +fn execute() { + let mut db = salsa::DatabaseImpl::default(); + + let input_high = MyInput::new(&mut db, 0); + input_high + .set_field(&mut db) + .with_durability(Durability::HIGH) + .to(2200); + + assert_eq!(tracked_fn(&db, input_high), 4400); + + // Changing the value should re-execute the query + input_high + .set_field(&mut db) + .with_durability(Durability::HIGH) + .to(2201); + + assert_eq!(tracked_fn(&db, input_high), 4402); +}