From 496e07647be90845898aa8a495ed2677c28ffb78 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Tue, 31 Dec 2024 09:51:27 +0100 Subject: [PATCH 1/2] Fix accumulated values for backdated queries --- src/accumulator.rs | 9 +++- src/accumulator/accumulated_map.rs | 19 +++++-- src/active_query.rs | 6 ++- src/function.rs | 9 +++- src/function/accumulated.rs | 2 +- src/function/fetch.rs | 2 +- src/function/maybe_changed_after.rs | 53 +++++++++++++++----- src/function/memo.rs | 7 ++- src/function/specify.rs | 2 + src/ingredient.rs | 22 ++++++++- src/input.rs | 11 +++-- src/input/input_field.rs | 12 +++-- src/interned.rs | 11 +++-- src/key.rs | 9 ++-- src/tracked_struct.rs | 11 +++-- src/tracked_struct/tracked_field.rs | 10 ++-- src/zalsa_local.rs | 3 +- tests/accumulated_backdate.rs | 77 +++++++++++++++++++++++++++++ 18 files changed, 227 insertions(+), 48 deletions(-) create mode 100644 tests/accumulated_backdate.rs diff --git a/src/accumulator.rs b/src/accumulator.rs index 1968600da..3518c9106 100644 --- a/src/accumulator.rs +++ b/src/accumulator.rs @@ -11,7 +11,7 @@ use accumulated::AnyAccumulated; use crate::{ cycle::CycleRecoveryStrategy, - ingredient::{fmt_index, Ingredient, Jar}, + ingredient::{fmt_index, Ingredient, Jar, MaybeChangedAfter}, plumbing::JarAux, zalsa::IngredientIndex, zalsa_local::QueryOrigin, @@ -100,7 +100,12 @@ impl Ingredient for IngredientImpl { self.index } - fn maybe_changed_after(&self, _db: &dyn Database, _input: Id, _revision: Revision) -> bool { + fn maybe_changed_after( + &self, + _db: &dyn Database, + _input: Id, + _revision: Revision, + ) -> MaybeChangedAfter { panic!("nothing should ever depend on an accumulator directly") } diff --git a/src/accumulator/accumulated_map.rs b/src/accumulator/accumulated_map.rs index 288c482fb..83983d71e 100644 --- a/src/accumulator/accumulated_map.rs +++ b/src/accumulator/accumulated_map.rs @@ -66,19 +66,28 @@ pub enum InputAccumulatedValues { } impl InputAccumulatedValues { - pub(crate) const fn is_any(self) -> bool { + pub const fn is_any(self) -> bool { matches!(self, Self::Any) } - pub(crate) const fn is_empty(self) -> bool { + pub const fn is_empty(self) -> bool { matches!(self, Self::Empty) } } +impl ops::BitOr for InputAccumulatedValues { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + match (self, rhs) { + (Self::Any, _) | (_, Self::Any) => Self::Any, + (Self::Empty, Self::Empty) => Self::Empty, + } + } +} + impl ops::BitOrAssign for InputAccumulatedValues { fn bitor_assign(&mut self, rhs: Self) { - if rhs.is_any() { - *self = Self::Any; - } + *self = *self | rhs; } } diff --git a/src/active_query.rs b/src/active_query.rs index 1ef9d29e2..657ed176a 100644 --- a/src/active_query.rs +++ b/src/active_query.rs @@ -1,5 +1,7 @@ use std::ops::Not; +use crossbeam::atomic::AtomicCell; + use super::zalsa_local::{QueryEdges, QueryOrigin, QueryRevisions}; use crate::key::OutputDependencyIndex; use crate::tracked_struct::{DisambiguatorMap, IdentityHash, IdentityMap}; @@ -129,10 +131,10 @@ impl ActiveQuery { origin, durability: self.durability, tracked_struct_ids: self.tracked_struct_ids, - accumulated_inputs: match &accumulated { + accumulated_inputs: AtomicCell::new(match &accumulated { Some(_) => InputAccumulatedValues::Any, None => self.accumulated_inputs, - }, + }), accumulated, } } diff --git a/src/function.rs b/src/function.rs index f96cca989..639b1819b 100644 --- a/src/function.rs +++ b/src/function.rs @@ -3,7 +3,7 @@ use std::{any::Any, fmt, sync::Arc}; use crate::{ accumulator::accumulated_map::{AccumulatedMap, InputAccumulatedValues}, cycle::CycleRecoveryStrategy, - ingredient::fmt_index, + ingredient::{fmt_index, MaybeChangedAfter}, key::DatabaseKeyIndex, plumbing::JarAux, salsa_struct::SalsaStructInDb, @@ -189,7 +189,12 @@ where self.index } - fn maybe_changed_after(&self, db: &dyn Database, input: Id, revision: Revision) -> bool { + fn maybe_changed_after( + &self, + db: &dyn Database, + input: Id, + revision: Revision, + ) -> MaybeChangedAfter { let db = db.as_view::(); self.maybe_changed_after(db, input, revision) } diff --git a/src/function/accumulated.rs b/src/function/accumulated.rs index 67664c022..1830ab62c 100644 --- a/src/function/accumulated.rs +++ b/src/function/accumulated.rs @@ -101,7 +101,7 @@ where let memo = self.refresh_memo(db, key); ( memo.revisions.accumulated.as_deref(), - memo.revisions.accumulated_inputs, + memo.revisions.accumulated_inputs.load(), ) } } diff --git a/src/function/fetch.rs b/src/function/fetch.rs index 1b806f556..58e8cdd91 100644 --- a/src/function/fetch.rs +++ b/src/function/fetch.rs @@ -24,7 +24,7 @@ where self.database_key_index(id).into(), durability, changed_at, - memo.revisions.accumulated_inputs, + memo.revisions.accumulated_inputs.load(), ); value diff --git a/src/function/maybe_changed_after.rs b/src/function/maybe_changed_after.rs index 53c94520e..7bdaa699f 100644 --- a/src/function/maybe_changed_after.rs +++ b/src/function/maybe_changed_after.rs @@ -1,4 +1,5 @@ use crate::{ + ingredient::MaybeChangedAfter, key::DatabaseKeyIndex, zalsa::{Zalsa, ZalsaDatabase}, zalsa_local::{ActiveQueryGuard, QueryEdge, QueryOrigin}, @@ -16,7 +17,7 @@ where db: &'db C::DbView, id: Id, revision: Revision, - ) -> bool { + ) -> MaybeChangedAfter { let (zalsa, zalsa_local) = db.zalsas(); zalsa_local.unwind_if_revision_cancelled(db.as_dyn_database()); @@ -29,7 +30,11 @@ where let memo_guard = self.get_memo_from_table_for(zalsa, id); if let Some(memo) = &memo_guard { if self.shallow_verify_memo(db, zalsa, database_key_index, memo) { - return memo.revisions.changed_at > revision; + return if memo.revisions.changed_at > revision { + MaybeChangedAfter::Yes + } else { + MaybeChangedAfter::No(memo.revisions.accumulated_inputs.load()) + }; } drop(memo_guard); // release the arc-swap guard before cold path if let Some(mcs) = self.maybe_changed_after_cold(db, id, revision) { @@ -39,7 +44,7 @@ where } } else { // No memo? Assume has changed. - return true; + return MaybeChangedAfter::Yes; } } } @@ -49,7 +54,7 @@ where db: &'db C::DbView, key_index: Id, revision: Revision, - ) -> Option { + ) -> Option { let (zalsa, zalsa_local) = db.zalsas(); let database_key_index = self.database_key_index(key_index); @@ -63,7 +68,7 @@ where // Load the current memo, if any. let Some(old_memo) = self.get_memo_from_table_for(zalsa, key_index) else { - return Some(true); + return Some(MaybeChangedAfter::Yes); }; tracing::debug!( @@ -74,7 +79,11 @@ where // Check if the inputs are still valid and we can just compare `changed_at`. if self.deep_verify_memo(db, &old_memo, &active_query) { - return Some(old_memo.revisions.changed_at > revision); + return Some(if old_memo.revisions.changed_at > revision { + MaybeChangedAfter::Yes + } else { + MaybeChangedAfter::No(old_memo.revisions.accumulated_inputs.load()) + }); } // If inputs have changed, but we have an old value, we can re-execute. @@ -84,11 +93,16 @@ where if old_memo.value.is_some() { let memo = self.execute(db, active_query, Some(old_memo)); let changed_at = memo.revisions.changed_at; - return Some(changed_at > revision); + + return Some(if changed_at > revision { + MaybeChangedAfter::Yes + } else { + MaybeChangedAfter::No(memo.revisions.accumulated_inputs.load()) + }); } // Otherwise, nothing for it: have to consider the value to have changed. - Some(true) + Some(MaybeChangedAfter::Yes) } /// True if the memo's value and `changed_at` time is still valid in this revision. @@ -117,7 +131,12 @@ where if memo.check_durability(zalsa) { // No input of the suitable durability has changed since last verified. let db = db.as_dyn_database(); - memo.mark_as_verified(db, revision_now, database_key_index); + memo.mark_as_verified( + db, + revision_now, + database_key_index, + memo.revisions.accumulated_inputs.load(), + ); memo.mark_outputs_as_verified(db, database_key_index); return true; } @@ -151,7 +170,7 @@ where return true; } - match &old_memo.revisions.origin { + let inputs = match &old_memo.revisions.origin { QueryOrigin::Assigned(_) => { // If the value was assigneed by another query, // and that query were up-to-date, @@ -182,13 +201,19 @@ where // valid, then some later input I1 might never have executed at all, so verifying // it is still up to date is meaningless. let last_verified_at = old_memo.verified_at.load(); + let mut inputs = old_memo.revisions.accumulated_inputs.load(); for &edge in edges.input_outputs.iter() { match edge { QueryEdge::Input(dependency_index) => { - if dependency_index + match dependency_index .maybe_changed_after(db.as_dyn_database(), last_verified_at) { - return false; + MaybeChangedAfter::Yes => { + return false; + } + MaybeChangedAfter::No(input_accumulated) => { + inputs |= input_accumulated; + } } } QueryEdge::Output(dependency_index) => { @@ -213,13 +238,15 @@ where } } } + inputs } - } + }; old_memo.mark_as_verified( db.as_dyn_database(), zalsa.current_revision(), database_key_index, + inputs, ); true } diff --git a/src/function/memo.rs b/src/function/memo.rs index 734ce0a54..246541f3e 100644 --- a/src/function/memo.rs +++ b/src/function/memo.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use crossbeam::atomic::AtomicCell; +use crate::accumulator::accumulated_map::InputAccumulatedValues; use crate::zalsa_local::QueryOrigin; use crate::{ key::DatabaseKeyIndex, zalsa::Zalsa, zalsa_local::QueryRevisions, Event, EventKind, Id, @@ -82,7 +83,7 @@ impl IngredientImpl { ref origin, ref tracked_struct_ids, ref accumulated, - accumulated_inputs, + ref accumulated_inputs, } = &memo.revisions; // Re-assemble the memo but with the value set to `None` Arc::new(Memo::new( @@ -94,7 +95,7 @@ impl IngredientImpl { origin: origin.clone(), tracked_struct_ids: tracked_struct_ids.clone(), accumulated: accumulated.clone(), - accumulated_inputs, + accumulated_inputs: AtomicCell::new(accumulated_inputs.load()), }, )) } @@ -150,6 +151,7 @@ impl Memo { db: &dyn crate::Database, revision_now: Revision, database_key_index: DatabaseKeyIndex, + accumulated: InputAccumulatedValues, ) { db.salsa_event(&|| { Event::new(EventKind::DidValidateMemoizedValue { @@ -158,6 +160,7 @@ impl Memo { }); self.verified_at.store(revision_now); + self.revisions.accumulated_inputs.store(accumulated); } pub(super) fn mark_outputs_as_verified( diff --git a/src/function/specify.rs b/src/function/specify.rs index e85600f7f..22b744a1b 100644 --- a/src/function/specify.rs +++ b/src/function/specify.rs @@ -1,6 +1,7 @@ use crossbeam::atomic::AtomicCell; use crate::{ + accumulator::accumulated_map::InputAccumulatedValues, tracked_struct::TrackedStructInDb, zalsa::ZalsaDatabase, zalsa_local::{QueryOrigin, QueryRevisions}, @@ -128,6 +129,7 @@ where db.as_dyn_database(), zalsa.current_revision(), database_key_index, + InputAccumulatedValues::Empty, ); } } diff --git a/src/ingredient.rs b/src/ingredient.rs index 76c4e5c55..84f6d3e33 100644 --- a/src/ingredient.rs +++ b/src/ingredient.rs @@ -61,7 +61,7 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync { db: &'db dyn Database, input: Id, revision: Revision, - ) -> bool; + ) -> MaybeChangedAfter; /// What were the inputs (if any) that were used to create the value at `key_index`. fn origin(&self, db: &dyn Database, key_index: Id) -> Option; @@ -175,3 +175,23 @@ pub(crate) fn fmt_index( write!(fmt, "{debug_name}()") } } + +#[derive(Copy, Clone, Debug)] +pub enum MaybeChangedAfter { + /// The query result hasn't changed. + /// + /// The inner value tracks whether the memo or any of its dependencies have an accumulated value. + No(InputAccumulatedValues), + + /// The query's result has changed since the last revision or the query isn't cached yet. + Yes, +} + +impl From for MaybeChangedAfter { + fn from(value: bool) -> Self { + match value { + true => MaybeChangedAfter::Yes, + false => MaybeChangedAfter::No(InputAccumulatedValues::Empty), + } + } +} diff --git a/src/input.rs b/src/input.rs index 6b75e00cb..09608f580 100644 --- a/src/input.rs +++ b/src/input.rs @@ -14,7 +14,7 @@ use crate::{ accumulator::accumulated_map::InputAccumulatedValues, cycle::CycleRecoveryStrategy, id::{AsId, FromId}, - ingredient::{fmt_index, Ingredient}, + ingredient::{fmt_index, Ingredient, MaybeChangedAfter}, input::singleton::{Singleton, SingletonChoice}, key::{DatabaseKeyIndex, InputDependencyIndex}, plumbing::{Jar, JarAux, Stamp}, @@ -199,10 +199,15 @@ impl Ingredient for IngredientImpl { self.ingredient_index } - fn maybe_changed_after(&self, _db: &dyn Database, _input: Id, _revision: Revision) -> bool { + fn maybe_changed_after( + &self, + _db: &dyn Database, + _input: Id, + _revision: Revision, + ) -> MaybeChangedAfter { // Input ingredients are just a counter, they store no data, they are immortal. // Their *fields* are stored in function ingredients elsewhere. - false + MaybeChangedAfter::No(InputAccumulatedValues::Empty) } fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { diff --git a/src/input/input_field.rs b/src/input/input_field.rs index 6dba77bcc..cbb511904 100644 --- a/src/input/input_field.rs +++ b/src/input/input_field.rs @@ -1,5 +1,5 @@ use crate::cycle::CycleRecoveryStrategy; -use crate::ingredient::{fmt_index, Ingredient}; +use crate::ingredient::{fmt_index, Ingredient, MaybeChangedAfter}; use crate::input::Configuration; use crate::zalsa::IngredientIndex; use crate::zalsa_local::QueryOrigin; @@ -49,10 +49,16 @@ where CycleRecoveryStrategy::Panic } - fn maybe_changed_after(&self, db: &dyn Database, input: Id, revision: Revision) -> bool { + fn maybe_changed_after( + &self, + db: &dyn Database, + input: Id, + revision: Revision, + ) -> MaybeChangedAfter { let zalsa = db.zalsa(); let value = >::data(zalsa, input); - value.stamps[self.field_index].changed_at > revision + + MaybeChangedAfter::from(value.stamps[self.field_index].changed_at > revision) } fn origin(&self, _db: &dyn Database, _key_index: Id) -> Option { diff --git a/src/interned.rs b/src/interned.rs index 5e938aa89..905ccccd8 100644 --- a/src/interned.rs +++ b/src/interned.rs @@ -2,7 +2,7 @@ use dashmap::SharedValue; use crate::accumulator::accumulated_map::InputAccumulatedValues; use crate::durability::Durability; -use crate::ingredient::fmt_index; +use crate::ingredient::{fmt_index, MaybeChangedAfter}; use crate::key::InputDependencyIndex; use crate::plumbing::{Jar, JarAux}; use crate::table::memo::MemoTable; @@ -254,8 +254,13 @@ where self.ingredient_index } - fn maybe_changed_after(&self, _db: &dyn Database, _input: Id, revision: Revision) -> bool { - revision < self.reset_at + fn maybe_changed_after( + &self, + _db: &dyn Database, + _input: Id, + revision: Revision, + ) -> MaybeChangedAfter { + MaybeChangedAfter::from(revision < self.reset_at) } fn cycle_recovery_strategy(&self) -> crate::cycle::CycleRecoveryStrategy { diff --git a/src/key.rs b/src/key.rs index d5d7acf9e..8fd159520 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,6 +1,9 @@ use core::fmt; -use crate::{cycle::CycleRecoveryStrategy, zalsa::IngredientIndex, Database, Id}; +use crate::{ + accumulator::accumulated_map::InputAccumulatedValues, cycle::CycleRecoveryStrategy, + ingredient::MaybeChangedAfter, zalsa::IngredientIndex, Database, Id, +}; /// An integer that uniquely identifies a particular query instance within the /// database. Used to track output dependencies between queries. Fully ordered and @@ -86,14 +89,14 @@ impl InputDependencyIndex { &self, db: &dyn Database, last_verified_at: crate::Revision, - ) -> bool { + ) -> MaybeChangedAfter { match self.key_index { Some(key_index) => db .zalsa() .lookup_ingredient(self.ingredient_index) .maybe_changed_after(db, key_index, last_verified_at), // Data in tables themselves remain valid until the table as a whole is reset. - None => false, + None => MaybeChangedAfter::No(InputAccumulatedValues::Empty), } } diff --git a/src/tracked_struct.rs b/src/tracked_struct.rs index 218546386..5728ad4d4 100644 --- a/src/tracked_struct.rs +++ b/src/tracked_struct.rs @@ -6,7 +6,7 @@ use tracked_field::FieldIngredientImpl; use crate::{ accumulator::accumulated_map::InputAccumulatedValues, cycle::CycleRecoveryStrategy, - ingredient::{fmt_index, Ingredient, Jar, JarAux}, + ingredient::{fmt_index, Ingredient, Jar, JarAux, MaybeChangedAfter}, key::{DatabaseKeyIndex, InputDependencyIndex}, plumbing::ZalsaLocal, runtime::StampedValue, @@ -660,8 +660,13 @@ where self.ingredient_index } - fn maybe_changed_after(&self, _db: &dyn Database, _input: Id, _revision: Revision) -> bool { - false + fn maybe_changed_after( + &self, + _db: &dyn Database, + _input: Id, + _revision: Revision, + ) -> MaybeChangedAfter { + MaybeChangedAfter::No(InputAccumulatedValues::Empty) } fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { diff --git a/src/tracked_struct/tracked_field.rs b/src/tracked_struct/tracked_field.rs index 8659e76bc..762a5dd4f 100644 --- a/src/tracked_struct/tracked_field.rs +++ b/src/tracked_struct/tracked_field.rs @@ -1,6 +1,10 @@ use std::marker::PhantomData; -use crate::{ingredient::Ingredient, zalsa::IngredientIndex, Database, Id}; +use crate::{ + ingredient::{Ingredient, MaybeChangedAfter}, + zalsa::IngredientIndex, + Database, Id, +}; use super::{Configuration, Value}; @@ -53,11 +57,11 @@ where db: &'db dyn Database, input: Id, revision: crate::Revision, - ) -> bool { + ) -> MaybeChangedAfter { let zalsa = db.zalsa(); let data = >::data(zalsa.table(), input); let field_changed_at = data.revisions[self.field_index]; - field_changed_at > revision + MaybeChangedAfter::from(field_changed_at > revision) } fn origin( diff --git a/src/zalsa_local.rs b/src/zalsa_local.rs index a110dce5c..39af70dd8 100644 --- a/src/zalsa_local.rs +++ b/src/zalsa_local.rs @@ -1,3 +1,4 @@ +use crossbeam::atomic::AtomicCell; use rustc_hash::FxHashMap; use tracing::debug; @@ -340,7 +341,7 @@ pub(crate) struct QueryRevisions { pub(super) accumulated: Option>, /// [`InputAccumulatedValues::Empty`] if any input read during the query's execution /// has any direct or indirect accumulated values. - pub(super) accumulated_inputs: InputAccumulatedValues, + pub(super) accumulated_inputs: AtomicCell, } impl QueryRevisions { diff --git a/tests/accumulated_backdate.rs b/tests/accumulated_backdate.rs new file mode 100644 index 000000000..b9d895487 --- /dev/null +++ b/tests/accumulated_backdate.rs @@ -0,0 +1,77 @@ +//! Tests that accumulated values are correctly accounted for +//! when backdating a value. + +mod common; +use common::LogDatabase; + +use expect_test::expect; +use salsa::{Accumulator, Setter}; +use test_log::test; + +#[salsa::input] +struct File { + content: String, +} + +#[salsa::accumulator] +struct Log(#[allow(dead_code)] String); + +#[salsa::tracked] +fn compile(db: &dyn LogDatabase, input: File) -> u32 { + parse(db, input) +} + +#[salsa::tracked] +fn parse(db: &dyn LogDatabase, input: File) -> u32 { + let value: Result = input.content(db).parse(); + + match value { + Ok(value) => value, + Err(error) => { + Log(error.to_string()).accumulate(db); + 0 + } + } +} + +#[test] +fn backdate() { + let mut db = common::LoggerDatabase::default(); + + let input = File::new(&db, "0".to_string()); + + let logs = compile::accumulated::(&db, input); + expect![[r#"[]"#]].assert_eq(&format!("{:#?}", logs)); + + input.set_content(&mut db).to("a".to_string()); + let logs = compile::accumulated::(&db, input); + + expect![[r#" + [ + Log( + "invalid digit found in string", + ), + ]"#]] + .assert_eq(&format!("{:#?}", logs)); +} + +#[test] +fn backdate_no_diagnostics() { + let mut db = common::LoggerDatabase::default(); + + let input = File::new(&db, "a".to_string()); + + let logs = compile::accumulated::(&db, input); + expect![[r#" + [ + Log( + "invalid digit found in string", + ), + ]"#]] + .assert_eq(&format!("{:#?}", logs)); + + input.set_content(&mut db).to("0".to_string()); + let logs = compile::accumulated::(&db, input); + + expect![[r#"[]"#]].assert_eq(&format!("{:#?}", logs)); +} From 467983da8c9d143f6131259192171e9fd049206a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 24 Jan 2025 16:08:30 +0100 Subject: [PATCH 2/2] Track only deps with accumulated_inpurts again --- src/active_query.rs | 5 +---- src/function/fetch.rs | 10 ++++++++-- src/function/maybe_changed_after.rs | 8 ++++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/active_query.rs b/src/active_query.rs index 657ed176a..a5e2c3a26 100644 --- a/src/active_query.rs +++ b/src/active_query.rs @@ -131,10 +131,7 @@ impl ActiveQuery { origin, durability: self.durability, tracked_struct_ids: self.tracked_struct_ids, - accumulated_inputs: AtomicCell::new(match &accumulated { - Some(_) => InputAccumulatedValues::Any, - None => self.accumulated_inputs, - }), + accumulated_inputs: AtomicCell::new(self.accumulated_inputs), accumulated, } } diff --git a/src/function/fetch.rs b/src/function/fetch.rs index 58e8cdd91..8ffb4639c 100644 --- a/src/function/fetch.rs +++ b/src/function/fetch.rs @@ -1,5 +1,8 @@ use super::{memo::Memo, Configuration, IngredientImpl}; -use crate::{runtime::StampedValue, zalsa::ZalsaDatabase, AsDynDatabase as _, Id}; +use crate::{ + accumulator::accumulated_map::InputAccumulatedValues, runtime::StampedValue, + zalsa::ZalsaDatabase, AsDynDatabase as _, Id, +}; impl IngredientImpl where @@ -24,7 +27,10 @@ where self.database_key_index(id).into(), durability, changed_at, - memo.revisions.accumulated_inputs.load(), + match &memo.revisions.accumulated { + Some(_) => InputAccumulatedValues::Any, + None => memo.revisions.accumulated_inputs.load(), + }, ); value diff --git a/src/function/maybe_changed_after.rs b/src/function/maybe_changed_after.rs index 7bdaa699f..58beefe3a 100644 --- a/src/function/maybe_changed_after.rs +++ b/src/function/maybe_changed_after.rs @@ -1,4 +1,5 @@ use crate::{ + accumulator::accumulated_map::InputAccumulatedValues, ingredient::MaybeChangedAfter, key::DatabaseKeyIndex, zalsa::{Zalsa, ZalsaDatabase}, @@ -97,7 +98,10 @@ where return Some(if changed_at > revision { MaybeChangedAfter::Yes } else { - MaybeChangedAfter::No(memo.revisions.accumulated_inputs.load()) + MaybeChangedAfter::No(match &memo.revisions.accumulated { + Some(_) => InputAccumulatedValues::Any, + None => memo.revisions.accumulated_inputs.load(), + }) }); } @@ -201,7 +205,7 @@ where // valid, then some later input I1 might never have executed at all, so verifying // it is still up to date is meaningless. let last_verified_at = old_memo.verified_at.load(); - let mut inputs = old_memo.revisions.accumulated_inputs.load(); + let mut inputs = InputAccumulatedValues::Empty; for &edge in edges.input_outputs.iter() { match edge { QueryEdge::Input(dependency_index) => {