diff outputs when replacing a memoized value

We don't do anything with this info right now besides log it,
but the logs show we are reporting it at the right times
in the `specify_tracked_fn_in_rev_1_but_not_2` test
(also fix an oversight in the test where it was creating a new input
each time).
This commit is contained in:
Niko Matsakis 2022-08-11 00:53:59 -04:00
parent c0ac7447c9
commit 8accccdbce
7 changed files with 231 additions and 19 deletions

View file

@ -7,8 +7,8 @@ pub trait Database: HasJarsDyn + AsSalsaDatabase {
///
/// By default, the event is logged at level debug using
/// the standard `log` facade.
fn salsa_event(&self, event_fn: Event) {
log::debug!("salsa_event: {:?}", event_fn.debug(self));
fn salsa_event(&self, event: Event) {
log::debug!("salsa_event: {:?}", event.debug(self));
}
fn salsa_runtime(&self) -> &Runtime;

View file

@ -1,4 +1,6 @@
use crate::{debug::DebugWithDb, runtime::RuntimeId, Database, DatabaseKeyIndex};
use crate::{
debug::DebugWithDb, key::DependencyIndex, runtime::RuntimeId, Database, DatabaseKeyIndex,
};
use std::fmt;
/// The `Event` struct identifies various notable things that can
@ -74,6 +76,15 @@ pub enum EventKind {
/// Indicates that `unwind_if_cancelled` was called and salsa will check if
/// the current revision has been cancelled.
WillCheckCancellation,
/// Discovered that a query used to output a given output but no longer does.
WillDiscardStaleOutput {
/// Key for the query that is executing and which no longer outputs the given value.
execute_key: DatabaseKeyIndex,
/// Key for the query that is no longer output
output_key: DependencyIndex,
},
}
impl fmt::Debug for EventKind {
@ -96,6 +107,14 @@ impl fmt::Debug for EventKind {
.field("database_key", database_key)
.finish(),
EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(),
EventKind::WillDiscardStaleOutput {
execute_key,
output_key,
} => fmt
.debug_struct("WillDiscardStaleOutput")
.field("execute_key", &execute_key)
.field("output_key", &output_key)
.finish(),
}
}
}
@ -123,6 +142,14 @@ where
.field("database_key", &database_key.debug(db))
.finish(),
EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(),
EventKind::WillDiscardStaleOutput {
execute_key,
output_key,
} => fmt
.debug_struct("WillDiscardStaleOutput")
.field("execute_key", &execute_key.debug(db))
.field("output_key", &output_key.debug(db))
.finish(),
}
}
}

View file

@ -17,6 +17,7 @@ use super::{ingredient::Ingredient, routes::IngredientIndex, AsId};
mod accumulated;
mod backdate;
mod diff_outputs;
mod execute;
mod fetch;
mod inputs;

View file

@ -0,0 +1,63 @@
use crate::{
key::DependencyIndex, runtime::local_state::QueryRevisions, Database, DatabaseKeyIndex, Event,
EventKind,
};
use super::{memo::Memo, Configuration, DynDb, FunctionIngredient};
impl<C> FunctionIngredient<C>
where
C: Configuration,
{
/// Compute the old and new outputs and invoke the `clear_stale_output` callback
/// for each output that was generated before but is not generated now.
pub(super) fn diff_outputs(
&self,
db: &DynDb<'_, C>,
key: DatabaseKeyIndex,
old_memo: &Memo<C::Value>,
revisions: &QueryRevisions,
) {
let mut old_outputs = old_memo
.revisions
.edges
.outputs()
.iter()
.copied()
.peekable();
let mut new_outputs = revisions.edges.outputs().iter().copied().peekable();
// two list are in sorted order, we can merge them in linear time.
while let (Some(&old_output), Some(&new_output)) = (old_outputs.peek(), new_outputs.peek())
{
if old_output < new_output {
// Output that was generated but is no longer.
Self::report_stale_output(db, key, old_output);
old_outputs.next();
} else if new_output < old_output {
// This is a new output that was not generated before.
// No action needed.
new_outputs.next();
} else {
// Output generated both times.
old_outputs.next();
new_outputs.next();
}
}
for old_output in old_outputs {
Self::report_stale_output(db, key, old_output);
}
}
fn report_stale_output(db: &DynDb<'_, C>, key: DatabaseKeyIndex, output: DependencyIndex) {
let runtime_id = db.salsa_runtime().id();
db.salsa_event(Event {
runtime_id,
kind: EventKind::WillDiscardStaleOutput {
execute_key: key,
output_key: output,
},
});
}
}

View file

@ -87,6 +87,7 @@ where
// old value.
if let Some(old_memo) = &opt_old_memo {
self.backdate_if_appropriate(old_memo, &mut revisions, &value);
self.diff_outputs(db, database_key_index, &old_memo, &revisions);
}
let value = self

View file

@ -26,8 +26,8 @@ where
None => panic!("can only use `set` with an active query"),
};
let entity_index = key.database_key_index(db);
if !runtime.is_output_of_active_query(entity_index) {
let database_key_index = key.database_key_index(db);
if !runtime.is_output_of_active_query(database_key_index) {
panic!("can only use `set` on entities created during current query");
}
@ -64,6 +64,7 @@ where
if let Some(old_memo) = self.memo_map.get(key) {
self.backdate_if_appropriate(&old_memo, &mut revisions, &value);
self.diff_outputs(db, database_key_index, &old_memo, &revisions);
}
let memo = Memo {

View file

@ -2,6 +2,7 @@
//! compiles and executes successfully.
use expect_test::expect;
use salsa::DebugWithDb;
use salsa_2022_tests::{HasLogger, Logger};
use test_log::test;
@ -74,6 +75,10 @@ impl salsa::Database for Database {
fn salsa_runtime(&self) -> &salsa::Runtime {
self.storage.runtime()
}
fn salsa_event(&self, event: salsa::Event) {
self.push_log(format!("{:?}", event.debug(self)));
}
}
impl Db for Database {}
@ -92,9 +97,17 @@ fn test_run_0() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
}
@ -106,9 +119,17 @@ fn test_run_5() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
}
@ -120,10 +141,21 @@ fn test_run_10() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
}
@ -135,10 +167,21 @@ fn test_run_20() {
assert_eq!(final_result(&db, input), 200);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
}
@ -150,9 +193,17 @@ fn test_run_0_then_5_then_20() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
// FIXME: read_maybe_specified should not re-execute
@ -160,16 +211,35 @@ fn test_run_0_then_5_then_20() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 2 }) } } }",
"final_result(MyInput(Id { value: 2 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 2 }) } } }",
"create_tracked(MyInput(Id { value: 2 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 2 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 2 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
input.set_field(&mut db, 20);
assert_eq!(final_result(&db, input), 100); // FIXME: Should be 20.
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 2 }) } } }",
"create_tracked(MyInput(Id { value: 2 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillDiscardStaleOutput { execute_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 2 }) }, output_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 2 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 2 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 2 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 2 }) } } }",
]"#]]); // FIXME: should invoke maybe_specified
}
@ -181,41 +251,71 @@ fn test_run_0_then_5_then_10_then_20() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
// FIXME: `read_maybe_specified` should not re-execute
let input = MyInput::new(&mut db, 5);
input.set_field(&mut db, 5);
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"final_result(MyInput(Id { value: 2 }))",
"create_tracked(MyInput(Id { value: 2 }))",
"read_maybe_specified(MyTracked(Id { value: 2 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
]"#]]);
// FIXME: should execute `maybe_specified` but not `read_maybe_specified`
let input = MyInput::new(&mut db, 10);
input.set_field(&mut db, 10);
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"final_result(MyInput(Id { value: 3 }))",
"create_tracked(MyInput(Id { value: 3 }))",
"read_maybe_specified(MyTracked(Id { value: 3 }))",
"maybe_specified(MyTracked(Id { value: 3 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillDiscardStaleOutput { execute_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) }, output_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
]"#]]);
// FIXME: should execute `maybe_specified` but not `read_maybe_specified`
input.set_field(&mut db, 20);
assert_eq!(final_result(&db, input), 200);
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"create_tracked(MyInput(Id { value: 3 }))",
"maybe_specified(MyTracked(Id { value: 3 }))",
"read_maybe_specified(MyTracked(Id { value: 3 }))",
"final_result(MyInput(Id { value: 3 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
]"#]]);
}
@ -227,15 +327,34 @@ fn test_run_5_then_20() {
assert_eq!(final_result(&db, input), 100);
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
"final_result(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"read_maybe_specified(MyTracked(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
]"#]]);
input.set_field(&mut db, 20);
assert_eq!(final_result(&db, input), 100); // FIXME: Should be 20.
db.assert_logs(expect![[r#"
[
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) } } }",
"create_tracked(MyInput(Id { value: 1 }))",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillDiscardStaleOutput { execute_key: DependencyIndex { ingredient_index: IngredientIndex(6), key_index: Some(Id { value: 1 }) }, output_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(4), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(5), key_index: Some(Id { value: 1 }) } } }",
"Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: DependencyIndex { ingredient_index: IngredientIndex(7), key_index: Some(Id { value: 1 }) } } }",
]"#]]); // FIXME: should invoke maybe_specified
}