Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 1 addition & 27 deletions src/accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ use accumulated::Accumulated;
use accumulated::AnyAccumulated;

use crate::{
cycle::CycleRecoveryStrategy,
ingredient::{fmt_index, Ingredient, Jar, MaybeChangedAfter},
plumbing::IngredientIndices,
zalsa::{IngredientIndex, Zalsa},
zalsa_local::QueryOrigin,
Database, DatabaseKeyIndex, Id, Revision,
Database, Id, Revision,
};

mod accumulated;
Expand Down Expand Up @@ -109,30 +107,6 @@ impl<A: Accumulator> Ingredient for IngredientImpl<A> {
panic!("nothing should ever depend on an accumulator directly")
}

fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
CycleRecoveryStrategy::Panic
}

fn origin(&self, _db: &dyn Database, _key_index: crate::Id) -> Option<QueryOrigin> {
None
}

fn mark_validated_output(
&self,
_db: &dyn Database,
_executor: DatabaseKeyIndex,
_output_key: crate::Id,
) {
}

fn remove_stale_output(
&self,
_db: &dyn Database,
_executor: DatabaseKeyIndex,
_stale_output_key: crate::Id,
) {
}

fn fmt_index(&self, index: Option<crate::Id>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_index(A::DEBUG_NAME, index, fmt)
}
Expand Down
31 changes: 10 additions & 21 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,32 +235,13 @@ where
self.maybe_changed_after(db, input, revision)
}

fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
C::CYCLE_STRATEGY
}

fn origin(&self, db: &dyn Database, key: Id) -> Option<QueryOrigin> {
self.origin(db.zalsa(), key)
}

fn mark_validated_output(
&self,
db: &dyn Database,
zalsa: &Zalsa,
executor: DatabaseKeyIndex,
output_key: crate::Id,
) {
self.validate_specified_value(db, executor, output_key);
}

fn remove_stale_output(
&self,
_db: &dyn Database,
_executor: DatabaseKeyIndex,
_stale_output_key: crate::Id,
) {
// This function is invoked when a query Q specifies the value for `stale_output_key` in rev 1,
// but not in rev 2. We don't do anything in this case, we just leave the (now stale) memo.
// Since its `verified_at` field has not changed, it will be considered dirty if it is invoked.
self.validate_specified_value(zalsa, executor, output_key);
}

fn requires_reset_for_new_revision(&self) -> bool {
Expand All @@ -286,6 +267,14 @@ where
C::DEBUG_NAME
}

fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
C::CYCLE_STRATEGY
}

fn origin(&self, db: &dyn Database, key: Id) -> Option<QueryOrigin> {
self.origin(db.zalsa(), key)
}

fn accumulated<'db>(
&'db self,
db: &'db dyn Database,
Expand Down
4 changes: 2 additions & 2 deletions src/function/diff_outputs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{memo::Memo, Configuration, IngredientImpl};
use crate::{
hash::FxHashSet, key::OutputDependencyIndex, zalsa::Zalsa, zalsa_local::QueryRevisions,
AsDynDatabase as _, Database, DatabaseKeyIndex, Event, EventKind,
Database, DatabaseKeyIndex, Event, EventKind,
};

impl<C> IngredientImpl<C>
Expand Down Expand Up @@ -56,6 +56,6 @@ where
})
});

output.remove_stale_output(zalsa, db.as_dyn_database(), key);
output.remove_stale_output(zalsa);
}
}
5 changes: 2 additions & 3 deletions src/function/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ where
let memo_ingredient_index = self.memo_ingredient_index(zalsa, id);
loop {
if let Some(memo) = self
.fetch_hot(zalsa, db, id, memo_ingredient_index)
.fetch_hot(zalsa, id, memo_ingredient_index)
.or_else(|| self.fetch_cold(zalsa, db, id, memo_ingredient_index))
{
return memo;
Expand All @@ -62,14 +62,13 @@ where
fn fetch_hot<'db>(
&'db self,
zalsa: &'db Zalsa,
db: &'db C::DbView,
id: Id,
memo_ingredient_index: MemoIngredientIndex,
) -> Option<&'db Memo<C::Output<'db>>> {
let memo_guard = self.get_memo_from_table_for(zalsa, id, memo_ingredient_index);
if let Some(memo) = memo_guard {
if memo.value.is_some()
&& self.shallow_verify_memo(db, zalsa, self.database_key_index(id), memo)
&& self.shallow_verify_memo(zalsa, self.database_key_index(id), memo)
{
// Unsafety invariant: memo is present in memo_map and we have verified that it is
// still valid for the current revision.
Expand Down
22 changes: 6 additions & 16 deletions src/function/maybe_changed_after.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ where
// Check if we have a verified version: this is the hot path.
let memo_guard = self.get_memo_from_table_for(zalsa, id, memo_ingredient_index);
if let Some(memo) = memo_guard {
if self.shallow_verify_memo(db, zalsa, database_key_index, memo) {
if self.shallow_verify_memo(zalsa, database_key_index, memo) {
return if memo.revisions.changed_at > revision {
MaybeChangedAfter::Yes
} else {
Expand Down Expand Up @@ -118,7 +118,6 @@ where
#[inline]
pub(super) fn shallow_verify_memo(
&self,
db: &C::DbView,
zalsa: &Zalsa,
database_key_index: DatabaseKeyIndex,
memo: &Memo<C::Output<'_>>,
Expand Down Expand Up @@ -146,13 +145,8 @@ where
);
if last_changed <= verified_at {
// No input of the suitable durability has changed since last verified.
memo.mark_as_verified(
db,
revision_now,
database_key_index,
memo.revisions.accumulated_inputs.load(),
);
memo.mark_outputs_as_verified(zalsa, db.as_dyn_database(), database_key_index);
memo.mark_as_verified(revision_now, memo.revisions.accumulated_inputs.load());
memo.mark_outputs_as_verified(zalsa, database_key_index);
return true;
}

Expand Down Expand Up @@ -181,7 +175,7 @@ where
old_memo = old_memo.tracing_debug()
);

if self.shallow_verify_memo(db, zalsa, database_key_index, old_memo) {
if self.shallow_verify_memo(zalsa, database_key_index, old_memo) {
return true;
}

Expand Down Expand Up @@ -241,16 +235,12 @@ where
// by this function cannot be read until this function is marked green,
// so even if we mark them as valid here, the function will re-execute
// and overwrite the contents.
dependency_index.mark_validated_output(
zalsa,
dyn_db,
database_key_index,
);
dependency_index.mark_validated_output(zalsa, database_key_index);
}
}
}

old_memo.mark_as_verified(db, zalsa.current_revision(), database_key_index, inputs);
old_memo.mark_as_verified(zalsa.current_revision(), inputs);
true
}
}
Expand Down
18 changes: 3 additions & 15 deletions src/function/memo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ use crate::revision::AtomicRevision;
use crate::table::memo::MemoTable;
use crate::zalsa::MemoIngredientIndex;
use crate::zalsa_local::QueryOrigin;
use crate::{
key::DatabaseKeyIndex, zalsa::Zalsa, zalsa_local::QueryRevisions, Event, EventKind, Id,
Revision,
};
use crate::{key::DatabaseKeyIndex, zalsa::Zalsa, zalsa_local::QueryRevisions, Id, Revision};

use super::{Configuration, IngredientImpl};

Expand Down Expand Up @@ -136,31 +133,22 @@ impl<V> Memo<V> {

/// Mark memo as having been verified in the `revision_now`, which should
/// be the current revision.
pub(super) fn mark_as_verified<Db: ?Sized + crate::Database>(
pub(super) fn mark_as_verified(
&self,
db: &Db,
revision_now: Revision,
database_key_index: DatabaseKeyIndex,
accumulated: InputAccumulatedValues,
) {
db.salsa_event(&|| {
Event::new(EventKind::DidValidateMemoizedValue {
database_key: database_key_index,
})
});

self.verified_at.store(revision_now);
self.revisions.accumulated_inputs.store(accumulated);
}

pub(super) fn mark_outputs_as_verified(
&self,
zalsa: &Zalsa,
db: &dyn crate::Database,
database_key_index: DatabaseKeyIndex,
) {
for output in self.revisions.origin.outputs() {
output.mark_validated_output(zalsa, db, database_key_index);
output.mark_validated_output(zalsa, database_key_index);
}
}

Expand Down
17 changes: 5 additions & 12 deletions src/function/specify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use crate::{
accumulator::accumulated_map::InputAccumulatedValues,
revision::AtomicRevision,
tracked_struct::TrackedStructInDb,
zalsa::ZalsaDatabase,
zalsa::{Zalsa, ZalsaDatabase},
zalsa_local::{QueryOrigin, QueryRevisions},
AsDynDatabase as _, Database, DatabaseKeyIndex, Id,
AsDynDatabase as _, DatabaseKeyIndex, Id,
};

use super::{memo::Memo, Configuration, IngredientImpl};
Expand Down Expand Up @@ -101,13 +101,12 @@ where
/// and `key` is a value that was specified by `executor`.
/// Marks `key` as valid in the current revision since if `executor` had re-executed,
/// it would have specified `key` again.
pub(super) fn validate_specified_value<Db: ?Sized + Database>(
pub(super) fn validate_specified_value(
&self,
db: &Db,
zalsa: &Zalsa,
executor: DatabaseKeyIndex,
key: Id,
) {
let zalsa = db.zalsa();
let memo_ingredient_index = self.memo_ingredient_index(zalsa, key);

let memo = match self.get_memo_from_table_for(zalsa, key, memo_ingredient_index) {
Expand All @@ -125,12 +124,6 @@ where
),
}

let database_key_index = self.database_key_index(key);
memo.mark_as_verified(
db,
zalsa.current_revision(),
database_key_index,
InputAccumulatedValues::Empty,
);
memo.mark_as_verified(zalsa.current_revision(), InputAccumulatedValues::Empty);
}
}
68 changes: 37 additions & 31 deletions src/ingredient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,50 +62,32 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync {
revision: Revision,
) -> 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<QueryOrigin>;

/// What values were accumulated during the creation of the value at `key_index`
/// (if any).
///
/// In practice, returns `Some` only for tracked function ingredients.
fn accumulated<'db>(
&'db self,
db: &'db dyn Database,
key_index: Id,
) -> (Option<&'db AccumulatedMap>, InputAccumulatedValues) {
_ = (db, key_index);
(None, InputAccumulatedValues::Any)
}

/// Invoked when the value `output_key` should be marked as valid in the current revision.
/// This occurs because the value for `executor`, which generated it, was marked as valid
/// in the current revision.
fn mark_validated_output<'db>(
&'db self,
db: &'db dyn Database,
fn mark_validated_output(
&self,
zalsa: &Zalsa,
executor: DatabaseKeyIndex,
output_key: crate::Id,
);
) {
let _ = (zalsa, executor, output_key);
unreachable!("only tracked struct and function ingredients can have validatable outputs")
}

/// Invoked when the value `stale_output` was output by `executor` in a previous
/// revision, but was NOT output in the current revision.
///
/// This hook is used to clear out the stale value so others cannot read it.
fn remove_stale_output(
&self,
db: &dyn Database,
executor: DatabaseKeyIndex,
stale_output_key: Id,
);
fn remove_stale_output(&self, zalsa: &Zalsa, stale_output_key: Id) {
let _ = (zalsa, stale_output_key);
unreachable!("only tracked struct ingredients can have stale outputs")
}

/// Returns the [`IngredientIndex`] of this ingredient.
fn ingredient_index(&self) -> IngredientIndex;

/// If this ingredient is a participant in a cycle, what is its cycle recovery strategy?
/// (Really only relevant to [`crate::function::FunctionIngredient`],
/// since only function ingredients push themselves onto the active query stack.)
fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy;
fn fmt_index(&self, index: Option<crate::Id>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;

/// Returns true if `reset_for_new_revision` should be called when new revisions start.
/// Invoked once when ingredient is added and not after that.
Expand All @@ -132,7 +114,31 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync {
);
}

fn fmt_index(&self, index: Option<crate::Id>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
// Function ingredient methods

/// If this ingredient is a participant in a cycle, what is its cycle recovery strategy?
/// (Really only relevant to [`crate::function::FunctionIngredient`],
/// since only function ingredients push themselves onto the active query stack.)
fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
unreachable!("only function ingredients can be part of a cycle")
}

/// 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<QueryOrigin> {
let _ = (db, key_index);
unreachable!("only function ingredients have origins")
}

/// What values were accumulated during the creation of the value at `key_index`
/// (if any).
fn accumulated<'db>(
&'db self,
db: &'db dyn Database,
key_index: Id,
) -> (Option<&'db AccumulatedMap>, InputAccumulatedValues) {
let _ = (db, key_index);
(None, InputAccumulatedValues::Empty)
}
}

impl dyn Ingredient {
Expand Down
Loading
Loading