merge volatile and memoized queries

This commit is contained in:
Niko Matsakis 2018-10-09 12:14:09 -04:00
parent 2d6e454638
commit 5ad0049b9f
3 changed files with 46 additions and 107 deletions

View file

@ -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>
};
(

View file

@ -31,6 +31,11 @@ pub type MemoizedStorage<DB, Q> = WeakMemoizedStorage<DB, Q, AlwaysMemoizeValue>
/// storage requirements.
pub type DependencyStorage<DB, Q> = WeakMemoizedStorage<DB, Q, NeverMemoizeValue>;
/// "Dependency" queries just track their dependencies and not the
/// actual value (which they produce on demand). This lessens the
/// storage requirements.
pub type VolatileStorage<DB, Q> = WeakMemoizedStorage<DB, Q, VolatileValue>;
pub struct WeakMemoizedStorage<DB, Q, MP>
where
Q: QueryFunction<DB>,
@ -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<DB, Q> MemoizationPolicy<DB, Q> for VolatileValue
where
Q: QueryFunction<DB>,
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<Q::Value>,
/// The inputs that went into our query, if we are tracking them.
inputs: QueryDescriptorSet<DB>,
/// 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<DB, Q, MP> QueryStorageOps<DB, Q> for WeakMemoizedStorage<DB, Q, MP>

View file

@ -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<DB, Q>
where
Q: QueryFunction<DB>,
DB: Database,
{
/// We don't store the results of volatile queries,
/// but we track in-progress set to detect cycles.
in_progress: Mutex<FxHashSet<Q::Key>>,
}
impl<DB, Q> Default for VolatileStorage<DB, Q>
where
Q: QueryFunction<DB>,
DB: Database,
{
fn default() -> Self {
VolatileStorage {
in_progress: Mutex::new(FxHashSet::default()),
}
}
}
impl<DB, Q> QueryStorageOps<DB, Q> for VolatileStorage<DB, Q>
where
Q: QueryFunction<DB>,
DB: Database,
{
fn try_fetch<'q>(
&self,
db: &'q DB,
key: &Q::Key,
descriptor: &DB::QueryDescriptor,
) -> Result<Q::Value, CycleDetected> {
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
}
}