diff --git a/src/lib.rs b/src/lib.rs index 4a5b5130..5a759640 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ use std::hash::Hash; pub mod input; pub mod memoized; pub mod runtime; -pub mod volatile; /// The base trait which your "query context" must implement. Gives /// access to the salsa runtime, which you must embed into your query @@ -428,7 +427,7 @@ macro_rules! query_group { ( @storage_ty[$DB:ident, $Self:ident, volatile] ) => { - $crate::volatile::VolatileStorage<$DB, $Self> + $crate::memoized::VolatileStorage<$DB, $Self> }; ( diff --git a/src/memoized.rs b/src/memoized.rs index 9b408f14..294a133e 100644 --- a/src/memoized.rs +++ b/src/memoized.rs @@ -31,6 +31,11 @@ pub type MemoizedStorage = WeakMemoizedStorage /// storage requirements. pub type DependencyStorage = WeakMemoizedStorage; +/// "Dependency" queries just track their dependencies and not the +/// actual value (which they produce on demand). This lessens the +/// storage requirements. +pub type VolatileStorage = WeakMemoizedStorage; + pub struct WeakMemoizedStorage where Q: QueryFunction, @@ -47,6 +52,8 @@ where DB: Database, { fn should_memoize_value(key: &Q::Key) -> bool; + + fn is_volatile(key: &Q::Key) -> bool; } pub enum AlwaysMemoizeValue {} @@ -58,6 +65,10 @@ where fn should_memoize_value(_key: &Q::Key) -> bool { true } + + fn is_volatile(_key: &Q::Key) -> bool { + false + } } pub enum NeverMemoizeValue {} @@ -69,6 +80,25 @@ where fn should_memoize_value(_key: &Q::Key) -> bool { false } + + fn is_volatile(_key: &Q::Key) -> bool { + false + } +} + +pub enum VolatileValue {} +impl MemoizationPolicy for VolatileValue +where + Q: QueryFunction, + DB: Database, +{ + fn should_memoize_value(_key: &Q::Key) -> bool { + false + } + + fn is_volatile(_key: &Q::Key) -> bool { + true + } } /// Defines the "current state" of query's memoized results. @@ -97,6 +127,7 @@ where /// The result of the query, if we decide to memoize it. value: Option, + /// The inputs that went into our query, if we are tracking them. inputs: QueryDescriptorSet, /// Last time that we checked our inputs to see if they have @@ -202,12 +233,16 @@ where // Query was not previously executed, or value is potentially // stale, or value is absent. Let's execute! - let (mut stamped_value, inputs) = - db.salsa_runtime() - .execute_query_implementation(descriptor, || { - debug!("{:?}({:?}): executing query", Q::default(), key); - Q::execute(db, key.clone()) - }); + let runtime = db.salsa_runtime(); + let (mut stamped_value, inputs) = runtime.execute_query_implementation(descriptor, || { + debug!("{:?}({:?}): executing query", Q::default(), key); + + if self.is_volatile(key) { + runtime.report_untracked_read(); + } + + Q::execute(db, key.clone()) + }); // We assume that query is side-effect free -- that is, does // not mutate the "inputs" to the query system. Sanity check @@ -270,6 +305,10 @@ where fn should_memoize_value(&self, key: &Q::Key) -> bool { MP::should_memoize_value(key) } + + fn is_volatile(&self, key: &Q::Key) -> bool { + MP::is_volatile(key) + } } impl QueryStorageOps for WeakMemoizedStorage diff --git a/src/volatile.rs b/src/volatile.rs deleted file mode 100644 index 091048a6..00000000 --- a/src/volatile.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::runtime::ChangedAt; -use crate::runtime::QueryDescriptorSet; -use crate::runtime::Revision; -use crate::runtime::StampedValue; -use crate::CycleDetected; -use crate::Database; -use crate::QueryFunction; -use crate::QueryStorageOps; -use crate::QueryTable; -use log::debug; -use parking_lot::Mutex; -use rustc_hash::FxHashSet; -use std::any::Any; -use std::cell::RefCell; -use std::collections::hash_map::Entry; -use std::fmt::Debug; -use std::fmt::Display; -use std::fmt::Write; -use std::hash::Hash; - -/// Volatile Storage is just **always** considered dirty. Any time you -/// ask for the result of such a query, it is recomputed. -pub struct VolatileStorage -where - Q: QueryFunction, - DB: Database, -{ - /// We don't store the results of volatile queries, - /// but we track in-progress set to detect cycles. - in_progress: Mutex>, -} - -impl Default for VolatileStorage -where - Q: QueryFunction, - DB: Database, -{ - fn default() -> Self { - VolatileStorage { - in_progress: Mutex::new(FxHashSet::default()), - } - } -} - -impl QueryStorageOps for VolatileStorage -where - Q: QueryFunction, - DB: Database, -{ - fn try_fetch<'q>( - &self, - db: &'q DB, - key: &Q::Key, - descriptor: &DB::QueryDescriptor, - ) -> Result { - if !self.in_progress.lock().insert(key.clone()) { - return Err(CycleDetected); - } - - let runtime = db.salsa_runtime(); - - let (StampedValue { value, changed_at }, inputs) = - runtime.execute_query_implementation(descriptor, || { - debug!("{:?}({:?}): executing query", Q::default(), key); - runtime.report_untracked_read(); - Q::execute(db, key.clone()) - }); - - assert!(changed_at == ChangedAt::Revision(db.salsa_runtime().current_revision())); - assert!(match inputs { - QueryDescriptorSet::Untracked => true, - _ => false, - }); - - let was_in_progress = self.in_progress.lock().remove(key); - assert!(was_in_progress); - - db.salsa_runtime().report_query_read(descriptor, changed_at); - - Ok(value) - } - - fn maybe_changed_since( - &self, - _db: &'q DB, - revision: Revision, - key: &Q::Key, - _descriptor: &DB::QueryDescriptor, - ) -> bool { - debug!( - "{:?}({:?})::maybe_changed_since(revision={:?}) ==> true (volatile)", - Q::default(), - key, - revision, - ); - - true - } -}