2018-10-09 12:53:13 +00:00
|
|
|
use crate::runtime::ChangedAt;
|
2018-09-29 12:14:58 +00:00
|
|
|
use crate::runtime::QueryDescriptorSet;
|
|
|
|
use crate::runtime::Revision;
|
2018-10-12 16:10:25 +00:00
|
|
|
use crate::runtime::Runtime;
|
|
|
|
use crate::runtime::RuntimeId;
|
2018-10-01 09:37:35 +00:00
|
|
|
use crate::runtime::StampedValue;
|
2018-09-28 15:04:52 +00:00
|
|
|
use crate::CycleDetected;
|
2018-10-05 08:54:51 +00:00
|
|
|
use crate::Database;
|
2018-09-29 12:14:58 +00:00
|
|
|
use crate::QueryDescriptor;
|
2018-10-05 08:59:10 +00:00
|
|
|
use crate::QueryFunction;
|
2018-09-28 15:04:52 +00:00
|
|
|
use crate::QueryStorageOps;
|
2018-10-05 19:23:05 +00:00
|
|
|
use crate::UncheckedMutQueryStorageOps;
|
2018-09-30 11:28:22 +00:00
|
|
|
use log::debug;
|
2018-10-13 10:04:57 +00:00
|
|
|
use parking_lot::Condvar;
|
|
|
|
use parking_lot::Mutex;
|
2018-09-28 18:02:39 +00:00
|
|
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
2018-09-28 15:04:52 +00:00
|
|
|
use rustc_hash::FxHashMap;
|
2018-10-06 17:13:30 +00:00
|
|
|
use std::marker::PhantomData;
|
2018-10-13 09:45:57 +00:00
|
|
|
use std::ops::Deref;
|
2018-09-28 15:04:52 +00:00
|
|
|
|
2018-09-30 10:09:06 +00:00
|
|
|
/// Memoized queries store the result plus a list of the other queries
|
|
|
|
/// that they invoked. This means we can avoid recomputing them when
|
|
|
|
/// none of those inputs have changed.
|
2018-10-09 16:15:33 +00:00
|
|
|
pub type MemoizedStorage<DB, Q> = DerivedStorage<DB, Q, AlwaysMemoizeValue>;
|
2018-10-06 17:13:30 +00:00
|
|
|
|
|
|
|
/// "Dependency" queries just track their dependencies and not the
|
|
|
|
/// actual value (which they produce on demand). This lessens the
|
|
|
|
/// storage requirements.
|
2018-10-09 16:15:33 +00:00
|
|
|
pub type DependencyStorage<DB, Q> = DerivedStorage<DB, Q, NeverMemoizeValue>;
|
2018-10-06 17:13:30 +00:00
|
|
|
|
2018-10-09 16:14:09 +00:00
|
|
|
/// "Dependency" queries just track their dependencies and not the
|
|
|
|
/// actual value (which they produce on demand). This lessens the
|
|
|
|
/// storage requirements.
|
2018-10-09 16:15:33 +00:00
|
|
|
pub type VolatileStorage<DB, Q> = DerivedStorage<DB, Q, VolatileValue>;
|
2018-10-09 16:14:09 +00:00
|
|
|
|
2018-10-09 16:15:33 +00:00
|
|
|
/// Handles storage where the value is 'derived' by executing a
|
|
|
|
/// function (in contrast to "inputs").
|
|
|
|
pub struct DerivedStorage<DB, Q, MP>
|
2018-09-28 15:04:52 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-10-09 12:39:41 +00:00
|
|
|
MP: MemoizationPolicy<DB, Q>,
|
2018-09-28 15:04:52 +00:00
|
|
|
{
|
2018-10-05 08:54:51 +00:00
|
|
|
map: RwLock<FxHashMap<Q::Key, QueryState<DB, Q>>>,
|
2018-10-09 12:39:41 +00:00
|
|
|
policy: PhantomData<MP>,
|
2018-10-13 10:04:57 +00:00
|
|
|
|
|
|
|
/// This cond var is used when one thread is waiting on another to
|
|
|
|
/// produce some specific key. In that case, the thread producing
|
|
|
|
/// the key will signal the cond-var. The threads awaiting the key
|
|
|
|
/// will check in `map` to see if their key is present and (if
|
|
|
|
/// not) await the cond-var.
|
|
|
|
signal_cond_var: Condvar,
|
|
|
|
|
|
|
|
/// Mutex used for `signal_cond_var`. Note that this mutex is
|
|
|
|
/// never acquired while holding the lock on `map` (but you may
|
|
|
|
/// acquire the `map` lock while holding this mutex).
|
|
|
|
signal_mutex: Mutex<()>,
|
2018-10-06 17:13:30 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 12:39:41 +00:00
|
|
|
pub trait MemoizationPolicy<DB, Q>
|
2018-10-06 17:13:30 +00:00
|
|
|
where
|
|
|
|
Q: QueryFunction<DB>,
|
|
|
|
DB: Database,
|
|
|
|
{
|
|
|
|
fn should_memoize_value(key: &Q::Key) -> bool;
|
2018-10-09 16:14:09 +00:00
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
fn should_track_inputs(key: &Q::Key) -> bool;
|
2018-10-06 17:13:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum AlwaysMemoizeValue {}
|
2018-10-09 12:39:41 +00:00
|
|
|
impl<DB, Q> MemoizationPolicy<DB, Q> for AlwaysMemoizeValue
|
2018-10-06 17:13:30 +00:00
|
|
|
where
|
|
|
|
Q: QueryFunction<DB>,
|
|
|
|
DB: Database,
|
|
|
|
{
|
|
|
|
fn should_memoize_value(_key: &Q::Key) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2018-10-09 16:14:09 +00:00
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
|
|
true
|
2018-10-09 16:14:09 +00:00
|
|
|
}
|
2018-10-06 17:13:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum NeverMemoizeValue {}
|
2018-10-09 12:39:41 +00:00
|
|
|
impl<DB, Q> MemoizationPolicy<DB, Q> for NeverMemoizeValue
|
2018-10-06 17:13:30 +00:00
|
|
|
where
|
|
|
|
Q: QueryFunction<DB>,
|
|
|
|
DB: Database,
|
|
|
|
{
|
|
|
|
fn should_memoize_value(_key: &Q::Key) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2018-10-09 16:14:09 +00:00
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
|
|
true
|
2018-10-09 16:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2018-10-09 16:18:16 +00:00
|
|
|
// Why memoize? Well, if the "volatile" value really is
|
|
|
|
// constantly changing, we still want to capture its value
|
|
|
|
// until the next revision is triggered and ensure it doesn't
|
|
|
|
// change -- otherwise the system gets into an inconsistent
|
|
|
|
// state where the same query reports back different values.
|
|
|
|
true
|
2018-10-09 16:14:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
|
|
false
|
2018-10-09 16:14:09 +00:00
|
|
|
}
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
|
|
|
|
2018-09-28 17:53:15 +00:00
|
|
|
/// Defines the "current state" of query's memoized results.
|
2018-10-05 08:54:51 +00:00
|
|
|
enum QueryState<DB, Q>
|
2018-09-29 12:14:58 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-09-29 12:14:58 +00:00
|
|
|
{
|
2018-10-12 16:10:25 +00:00
|
|
|
/// The runtime with the given id is currently computing the
|
|
|
|
/// result of this query; if we see this value in the table, it
|
|
|
|
/// indeeds a cycle.
|
2018-10-13 10:08:29 +00:00
|
|
|
InProgress { id: RuntimeId },
|
2018-09-28 17:53:15 +00:00
|
|
|
|
|
|
|
/// We have computed the query already, and here is the result.
|
2018-10-05 08:54:51 +00:00
|
|
|
Memoized(Memo<DB, Q>),
|
2018-09-29 11:24:53 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 08:54:51 +00:00
|
|
|
struct Memo<DB, Q>
|
2018-09-29 12:14:58 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-09-29 12:14:58 +00:00
|
|
|
{
|
2018-10-06 17:13:30 +00:00
|
|
|
/// Last time the value has actually changed.
|
|
|
|
/// changed_at can be less than verified_at.
|
2018-10-09 12:53:13 +00:00
|
|
|
changed_at: ChangedAt,
|
2018-10-09 12:37:57 +00:00
|
|
|
|
2018-10-06 17:13:30 +00:00
|
|
|
/// The result of the query, if we decide to memoize it.
|
|
|
|
value: Option<Q::Value>,
|
2018-09-29 12:14:58 +00:00
|
|
|
|
2018-10-09 16:14:09 +00:00
|
|
|
/// The inputs that went into our query, if we are tracking them.
|
2018-10-05 08:54:51 +00:00
|
|
|
inputs: QueryDescriptorSet<DB>,
|
2018-09-29 12:14:58 +00:00
|
|
|
|
|
|
|
/// Last time that we checked our inputs to see if they have
|
|
|
|
/// changed. If this is equal to the current revision, then the
|
|
|
|
/// value is up to date. If not, we need to check our inputs and
|
|
|
|
/// see if any of them have changed since our last check -- if so,
|
|
|
|
/// we'll need to re-execute.
|
|
|
|
verified_at: Revision,
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 16:15:33 +00:00
|
|
|
impl<DB, Q, MP> Default for DerivedStorage<DB, Q, MP>
|
2018-09-28 15:40:20 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-10-09 12:39:41 +00:00
|
|
|
MP: MemoizationPolicy<DB, Q>,
|
2018-09-28 15:40:20 +00:00
|
|
|
{
|
|
|
|
fn default() -> Self {
|
2018-10-09 16:15:33 +00:00
|
|
|
DerivedStorage {
|
2018-09-28 18:02:39 +00:00
|
|
|
map: RwLock::new(FxHashMap::default()),
|
2018-10-09 12:39:41 +00:00
|
|
|
policy: PhantomData,
|
2018-10-13 10:04:57 +00:00
|
|
|
signal_cond_var: Default::default(),
|
|
|
|
signal_mutex: Default::default(),
|
2018-09-28 15:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-13 10:27:41 +00:00
|
|
|
enum ProbeState<V, G> {
|
|
|
|
UpToDate(StampedValue<V>),
|
|
|
|
CycleDetected,
|
|
|
|
StaleOrAbsent(G),
|
|
|
|
BlockedOnOtherThread(RuntimeId),
|
|
|
|
}
|
|
|
|
|
2018-10-09 16:15:33 +00:00
|
|
|
impl<DB, Q, MP> DerivedStorage<DB, Q, MP>
|
2018-09-28 15:04:52 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-10-09 12:39:41 +00:00
|
|
|
MP: MemoizationPolicy<DB, Q>,
|
2018-09-28 15:04:52 +00:00
|
|
|
{
|
2018-09-30 14:22:11 +00:00
|
|
|
fn read(
|
2018-09-28 15:04:52 +00:00
|
|
|
&self,
|
2018-10-05 08:54:51 +00:00
|
|
|
db: &DB,
|
2018-09-28 15:04:52 +00:00
|
|
|
key: &Q::Key,
|
2018-10-05 08:54:51 +00:00
|
|
|
descriptor: &DB::QueryDescriptor,
|
2018-09-30 10:04:09 +00:00
|
|
|
) -> Result<StampedValue<Q::Value>, CycleDetected> {
|
2018-10-11 20:48:20 +00:00
|
|
|
let runtime = db.salsa_runtime();
|
|
|
|
|
|
|
|
let _read_lock = runtime.freeze_revision();
|
|
|
|
|
|
|
|
let revision_now = runtime.current_revision();
|
2018-09-29 12:14:58 +00:00
|
|
|
|
2018-09-30 11:28:22 +00:00
|
|
|
debug!(
|
|
|
|
"{:?}({:?}): invoked at {:?}",
|
|
|
|
Q::default(),
|
|
|
|
key,
|
|
|
|
revision_now,
|
|
|
|
);
|
|
|
|
|
2018-10-13 10:27:41 +00:00
|
|
|
// In this loop, we are looking for an up-to-date value. The loop is needed
|
|
|
|
// to handle other threads: if we find that some other thread is "using" this
|
|
|
|
// key, we will block until they are done and then loop back around and try
|
|
|
|
// again.
|
|
|
|
//
|
|
|
|
// Otherwise, we first check for a usable value with the read
|
|
|
|
// lock. If that fails, we acquire the write lock and try
|
|
|
|
// again. We don't use an upgradable read lock because that
|
|
|
|
// would eliminate the ability for multiple cache hits to be
|
|
|
|
// executing in parallel.
|
|
|
|
let mut old_value = loop {
|
|
|
|
// Read-lock check.
|
|
|
|
match self.probe(self.map.read(), runtime, revision_now, key) {
|
|
|
|
ProbeState::UpToDate(v) => return Ok(v),
|
|
|
|
ProbeState::CycleDetected => return Err(CycleDetected),
|
|
|
|
ProbeState::BlockedOnOtherThread(other_id) => {
|
|
|
|
self.await_other_thread(other_id, key);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ProbeState::StaleOrAbsent(_guard) => (),
|
|
|
|
}
|
2018-10-09 12:37:57 +00:00
|
|
|
|
2018-10-13 10:27:41 +00:00
|
|
|
// Write-lock check: install `InProgress` sentinel if no usable value.
|
|
|
|
match self.probe(self.map.write(), runtime, revision_now, key) {
|
|
|
|
ProbeState::UpToDate(v) => return Ok(v),
|
|
|
|
ProbeState::CycleDetected => return Err(CycleDetected),
|
|
|
|
ProbeState::BlockedOnOtherThread(other_id) => {
|
|
|
|
self.await_other_thread(other_id, key);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ProbeState::StaleOrAbsent(mut map) => {
|
|
|
|
break map.insert(key.clone(), QueryState::InProgress { id: runtime.id() })
|
2018-10-13 10:08:29 +00:00
|
|
|
}
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
2018-09-29 12:14:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// If we have an old-value, it *may* now be stale, since there
|
|
|
|
// has been a new revision since the last time we checked. So,
|
|
|
|
// first things first, let's walk over each of our previous
|
|
|
|
// inputs and check whether they are out of date.
|
|
|
|
if let Some(QueryState::Memoized(old_memo)) = &mut old_value {
|
2018-10-09 19:11:57 +00:00
|
|
|
if let Some(value) = old_memo.verify_memoized_value(db) {
|
2018-10-09 12:53:13 +00:00
|
|
|
debug!("{:?}({:?}): inputs still valid", Q::default(), key);
|
|
|
|
// If none of out inputs have changed since the last time we refreshed
|
|
|
|
// our value, then our value must still be good. We'll just patch
|
|
|
|
// the verified-at date and re-use it.
|
|
|
|
old_memo.verified_at = revision_now;
|
|
|
|
let changed_at = old_memo.changed_at;
|
|
|
|
|
|
|
|
let mut map_write = self.map.write();
|
2018-10-12 16:10:25 +00:00
|
|
|
self.overwrite_placeholder(runtime, &mut map_write, key, old_value.unwrap());
|
2018-10-09 12:53:13 +00:00
|
|
|
return Ok(StampedValue { value, changed_at });
|
2018-09-29 12:14:58 +00:00
|
|
|
}
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
|
|
|
|
2018-10-06 17:13:30 +00:00
|
|
|
// Query was not previously executed, or value is potentially
|
|
|
|
// stale, or value is absent. Let's execute!
|
2018-10-09 16:14:09 +00:00
|
|
|
let (mut stamped_value, inputs) = runtime.execute_query_implementation(descriptor, || {
|
|
|
|
debug!("{:?}({:?}): executing query", Q::default(), key);
|
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
if !self.should_track_inputs(key) {
|
2018-10-09 16:14:09 +00:00
|
|
|
runtime.report_untracked_read();
|
|
|
|
}
|
|
|
|
|
|
|
|
Q::execute(db, key.clone())
|
|
|
|
});
|
2018-09-28 15:04:52 +00:00
|
|
|
|
2018-09-29 12:14:58 +00:00
|
|
|
// We assume that query is side-effect free -- that is, does
|
|
|
|
// not mutate the "inputs" to the query system. Sanity check
|
|
|
|
// that assumption here, at least to the best of our ability.
|
|
|
|
assert_eq!(
|
2018-10-11 20:48:20 +00:00
|
|
|
runtime.current_revision(),
|
2018-09-29 12:14:58 +00:00
|
|
|
revision_now,
|
|
|
|
"revision altered during query execution",
|
|
|
|
);
|
|
|
|
|
|
|
|
// If the new value is equal to the old one, then it didn't
|
|
|
|
// really change, even if some of its inputs have. So we can
|
2018-10-01 09:46:07 +00:00
|
|
|
// "backdate" its `changed_at` revision to be the same as the
|
2018-09-29 12:14:58 +00:00
|
|
|
// old value.
|
|
|
|
if let Some(QueryState::Memoized(old_memo)) = &old_value {
|
2018-10-06 17:13:30 +00:00
|
|
|
if old_memo.value.as_ref() == Some(&stamped_value.value) {
|
|
|
|
assert!(old_memo.changed_at <= stamped_value.changed_at);
|
|
|
|
stamped_value.changed_at = old_memo.changed_at;
|
2018-09-29 12:14:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-28 15:04:52 +00:00
|
|
|
{
|
2018-10-06 17:13:30 +00:00
|
|
|
let value = if self.should_memoize_value(key) {
|
|
|
|
Some(stamped_value.value.clone())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-09-28 18:02:39 +00:00
|
|
|
let mut map_write = self.map.write();
|
2018-10-01 10:02:00 +00:00
|
|
|
self.overwrite_placeholder(
|
2018-10-12 16:10:25 +00:00
|
|
|
runtime,
|
2018-10-01 10:02:00 +00:00
|
|
|
&mut map_write,
|
|
|
|
key,
|
2018-09-30 10:04:09 +00:00
|
|
|
QueryState::Memoized(Memo {
|
2018-10-06 17:13:30 +00:00
|
|
|
changed_at: stamped_value.changed_at,
|
|
|
|
value,
|
2018-09-29 12:14:58 +00:00
|
|
|
inputs,
|
|
|
|
verified_at: revision_now,
|
2018-09-29 11:24:53 +00:00
|
|
|
}),
|
|
|
|
);
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
|
|
|
|
2018-10-01 09:49:18 +00:00
|
|
|
Ok(stamped_value)
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
2018-10-01 10:02:00 +00:00
|
|
|
|
2018-10-13 09:45:57 +00:00
|
|
|
/// Helper for `read`:
|
|
|
|
///
|
|
|
|
/// Looks in the map to see if we have an up-to-date value or a
|
|
|
|
/// cycle. If so, returns `Ok(v)` with either the value or a cycle-error;
|
|
|
|
/// this can be propagated as the final result of read.
|
|
|
|
///
|
|
|
|
/// Otherwise, returns `Err(map)` where `map` is the lock guard
|
|
|
|
/// that was given in as argument.
|
2018-10-13 10:27:41 +00:00
|
|
|
fn probe<MapGuard>(
|
2018-10-13 09:45:57 +00:00
|
|
|
&self,
|
|
|
|
map: MapGuard,
|
|
|
|
runtime: &Runtime<DB>,
|
|
|
|
revision_now: Revision,
|
|
|
|
key: &Q::Key,
|
2018-10-13 10:27:41 +00:00
|
|
|
) -> ProbeState<Q::Value, MapGuard>
|
2018-10-13 09:45:57 +00:00
|
|
|
where
|
|
|
|
MapGuard: Deref<Target = FxHashMap<Q::Key, QueryState<DB, Q>>>,
|
|
|
|
{
|
|
|
|
match map.get(key) {
|
2018-10-13 10:08:29 +00:00
|
|
|
Some(QueryState::InProgress { id }) => {
|
2018-10-13 09:45:57 +00:00
|
|
|
if *id == runtime.id() {
|
2018-10-13 10:27:41 +00:00
|
|
|
return ProbeState::CycleDetected;
|
2018-10-13 09:45:57 +00:00
|
|
|
} else {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(QueryState::Memoized(m)) => {
|
|
|
|
debug!(
|
|
|
|
"{:?}({:?}): found memoized value verified_at={:?}",
|
|
|
|
Q::default(),
|
|
|
|
key,
|
|
|
|
m.verified_at,
|
|
|
|
);
|
|
|
|
|
|
|
|
// We've found that the query is definitely up-to-date.
|
|
|
|
// If the value is also memoized, return it.
|
|
|
|
// Otherwise fallback to recomputing the value.
|
|
|
|
if m.verified_at == revision_now {
|
|
|
|
if let Some(value) = &m.value {
|
|
|
|
debug!(
|
|
|
|
"{:?}({:?}): returning memoized value (changed_at={:?})",
|
|
|
|
Q::default(),
|
|
|
|
key,
|
|
|
|
m.changed_at,
|
|
|
|
);
|
2018-10-13 10:27:41 +00:00
|
|
|
return ProbeState::UpToDate(StampedValue {
|
2018-10-13 09:45:57 +00:00
|
|
|
value: value.clone(),
|
|
|
|
changed_at: m.changed_at,
|
2018-10-13 10:27:41 +00:00
|
|
|
});
|
2018-10-13 09:45:57 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
2018-10-13 10:27:41 +00:00
|
|
|
ProbeState::StaleOrAbsent(map)
|
2018-10-13 09:45:57 +00:00
|
|
|
}
|
|
|
|
|
2018-10-13 10:04:57 +00:00
|
|
|
/// If some other thread is tasked with producing a memoized
|
|
|
|
/// result for this value, then wait for them.
|
|
|
|
///
|
|
|
|
/// Pre-conditions:
|
|
|
|
/// - we have installed ourselves in the dependency graph and set the
|
|
|
|
/// bool that informs the producer we are waiting
|
2018-10-13 10:27:41 +00:00
|
|
|
/// - `self.map` must not be locked
|
|
|
|
fn await_other_thread(&self, other_id: RuntimeId, key: &Q::Key) {
|
2018-10-13 10:04:57 +00:00
|
|
|
let mut signal_lock_guard = self.signal_mutex.lock();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
{
|
|
|
|
let map = self.map.read();
|
|
|
|
|
2018-10-13 10:27:41 +00:00
|
|
|
match map.get(key) {
|
|
|
|
Some(QueryState::InProgress { id }) => {
|
|
|
|
// Other thread still working!
|
|
|
|
assert_eq!(*id, other_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
// The other thread finished!
|
|
|
|
return;
|
|
|
|
}
|
2018-10-13 10:04:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.signal_cond_var.wait(&mut signal_lock_guard);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-01 10:02:00 +00:00
|
|
|
fn overwrite_placeholder(
|
|
|
|
&self,
|
2018-10-12 16:10:25 +00:00
|
|
|
runtime: &Runtime<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
map_write: &mut FxHashMap<Q::Key, QueryState<DB, Q>>,
|
2018-10-01 10:02:00 +00:00
|
|
|
key: &Q::Key,
|
2018-10-05 08:54:51 +00:00
|
|
|
value: QueryState<DB, Q>,
|
2018-10-01 10:02:00 +00:00
|
|
|
) {
|
|
|
|
let old_value = map_write.insert(key.clone(), value);
|
|
|
|
assert!(
|
|
|
|
match old_value {
|
2018-10-13 10:08:29 +00:00
|
|
|
Some(QueryState::InProgress { id }) => id == runtime.id(),
|
2018-10-01 10:02:00 +00:00
|
|
|
_ => false,
|
|
|
|
},
|
|
|
|
"expected in-progress state",
|
|
|
|
);
|
|
|
|
}
|
2018-10-06 17:13:30 +00:00
|
|
|
|
|
|
|
fn should_memoize_value(&self, key: &Q::Key) -> bool {
|
2018-10-09 12:39:41 +00:00
|
|
|
MP::should_memoize_value(key)
|
2018-10-06 17:13:30 +00:00
|
|
|
}
|
2018-10-09 16:14:09 +00:00
|
|
|
|
2018-10-09 17:28:33 +00:00
|
|
|
fn should_track_inputs(&self, key: &Q::Key) -> bool {
|
|
|
|
MP::should_track_inputs(key)
|
2018-10-09 16:14:09 +00:00
|
|
|
}
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 16:15:33 +00:00
|
|
|
impl<DB, Q, MP> QueryStorageOps<DB, Q> for DerivedStorage<DB, Q, MP>
|
2018-09-30 10:04:09 +00:00
|
|
|
where
|
2018-10-05 08:59:10 +00:00
|
|
|
Q: QueryFunction<DB>,
|
2018-10-05 08:54:51 +00:00
|
|
|
DB: Database,
|
2018-10-09 12:39:41 +00:00
|
|
|
MP: MemoizationPolicy<DB, Q>,
|
2018-09-30 10:04:09 +00:00
|
|
|
{
|
2018-10-09 21:44:26 +00:00
|
|
|
fn try_fetch(
|
2018-09-30 10:04:09 +00:00
|
|
|
&self,
|
2018-10-09 21:44:26 +00:00
|
|
|
db: &DB,
|
2018-09-30 10:04:09 +00:00
|
|
|
key: &Q::Key,
|
2018-10-05 08:54:51 +00:00
|
|
|
descriptor: &DB::QueryDescriptor,
|
2018-09-30 10:04:09 +00:00
|
|
|
) -> Result<Q::Value, CycleDetected> {
|
2018-10-05 08:54:51 +00:00
|
|
|
let StampedValue { value, changed_at } = self.read(db, key, &descriptor)?;
|
2018-09-30 11:28:22 +00:00
|
|
|
|
2018-10-05 08:54:51 +00:00
|
|
|
db.salsa_runtime().report_query_read(descriptor, changed_at);
|
2018-09-30 11:28:22 +00:00
|
|
|
|
|
|
|
Ok(value)
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 21:44:26 +00:00
|
|
|
fn maybe_changed_since(
|
2018-09-30 10:04:09 +00:00
|
|
|
&self,
|
2018-10-09 21:44:26 +00:00
|
|
|
db: &DB,
|
2018-09-30 10:04:09 +00:00
|
|
|
revision: Revision,
|
|
|
|
key: &Q::Key,
|
2018-10-05 08:54:51 +00:00
|
|
|
descriptor: &DB::QueryDescriptor,
|
2018-09-30 10:04:09 +00:00
|
|
|
) -> bool {
|
2018-10-12 16:10:25 +00:00
|
|
|
let runtime = db.salsa_runtime();
|
|
|
|
let revision_now = runtime.current_revision();
|
2018-09-30 11:28:22 +00:00
|
|
|
|
|
|
|
debug!(
|
|
|
|
"{:?}({:?})::maybe_changed_since(revision={:?}, revision_now={:?})",
|
|
|
|
Q::default(),
|
|
|
|
key,
|
|
|
|
revision,
|
|
|
|
revision_now,
|
|
|
|
);
|
|
|
|
|
2018-10-06 17:13:30 +00:00
|
|
|
let value = {
|
|
|
|
let map_read = self.map.upgradable_read();
|
2018-09-30 10:04:09 +00:00
|
|
|
match map_read.get(key) {
|
2018-10-13 10:08:29 +00:00
|
|
|
None | Some(QueryState::InProgress { .. }) => return true,
|
2018-09-30 10:04:09 +00:00
|
|
|
Some(QueryState::Memoized(memo)) => {
|
2018-10-06 17:13:30 +00:00
|
|
|
// If our memo is still up to date, then check if we've
|
|
|
|
// changed since the revision.
|
|
|
|
if memo.verified_at == revision_now {
|
2018-10-09 12:53:13 +00:00
|
|
|
return memo.changed_at.changed_since(revision);
|
2018-10-06 17:13:30 +00:00
|
|
|
}
|
|
|
|
if memo.value.is_some() {
|
|
|
|
// Otherwise, if we cache values, fall back to the full read to compute the result.
|
|
|
|
drop(memo);
|
|
|
|
drop(map_read);
|
|
|
|
return match self.read(db, key, descriptor) {
|
2018-10-09 12:53:13 +00:00
|
|
|
Ok(v) => v.changed_at.changed_since(revision),
|
2018-10-06 17:13:30 +00:00
|
|
|
Err(CycleDetected) => true,
|
|
|
|
};
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-06 17:13:30 +00:00
|
|
|
};
|
|
|
|
// If, however, we don't cache values, then optimistically
|
|
|
|
// try to advance `verified_at` by walking the inputs.
|
|
|
|
let mut map_write = RwLockUpgradableReadGuard::upgrade(map_read);
|
2018-10-13 10:08:29 +00:00
|
|
|
map_write.insert(key.clone(), QueryState::InProgress { id: runtime.id() })
|
2018-10-06 17:13:30 +00:00
|
|
|
};
|
2018-09-30 10:04:09 +00:00
|
|
|
|
2018-10-06 17:13:30 +00:00
|
|
|
let mut memo = match value {
|
|
|
|
Some(QueryState::Memoized(memo)) => memo,
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
2018-10-09 13:27:59 +00:00
|
|
|
if memo.verify_inputs(db) {
|
2018-10-06 17:13:30 +00:00
|
|
|
memo.verified_at = revision_now;
|
2018-10-12 16:10:25 +00:00
|
|
|
self.overwrite_placeholder(
|
|
|
|
runtime,
|
|
|
|
&mut self.map.write(),
|
|
|
|
key,
|
|
|
|
QueryState::Memoized(memo),
|
|
|
|
);
|
2018-10-06 17:13:30 +00:00
|
|
|
return false;
|
2018-09-30 10:04:09 +00:00
|
|
|
}
|
2018-10-06 17:13:30 +00:00
|
|
|
|
|
|
|
// Just remove the existing entry. It's out of date.
|
|
|
|
self.map.write().remove(key);
|
|
|
|
|
|
|
|
true
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
2018-10-11 08:37:29 +00:00
|
|
|
|
|
|
|
fn is_constant(&self, _db: &DB, key: &Q::Key) -> bool {
|
|
|
|
let map_read = self.map.read();
|
|
|
|
match map_read.get(key) {
|
|
|
|
None => false,
|
2018-10-13 10:08:29 +00:00
|
|
|
Some(QueryState::InProgress { .. }) => panic!("query in progress"),
|
2018-10-11 08:37:29 +00:00
|
|
|
Some(QueryState::Memoized(memo)) => memo.changed_at.is_constant(),
|
|
|
|
}
|
|
|
|
}
|
2018-09-28 15:04:52 +00:00
|
|
|
}
|
2018-10-05 19:23:05 +00:00
|
|
|
|
2018-10-09 16:15:33 +00:00
|
|
|
impl<DB, Q, MP> UncheckedMutQueryStorageOps<DB, Q> for DerivedStorage<DB, Q, MP>
|
2018-10-05 19:23:05 +00:00
|
|
|
where
|
|
|
|
Q: QueryFunction<DB>,
|
|
|
|
DB: Database,
|
2018-10-09 12:39:41 +00:00
|
|
|
MP: MemoizationPolicy<DB, Q>,
|
2018-10-05 19:23:05 +00:00
|
|
|
{
|
|
|
|
fn set_unchecked(&self, db: &DB, key: &Q::Key, value: Q::Value) {
|
|
|
|
let key = key.clone();
|
|
|
|
|
|
|
|
let mut map_write = self.map.write();
|
|
|
|
|
2018-10-09 12:53:13 +00:00
|
|
|
let current_revision = db.salsa_runtime().current_revision();
|
|
|
|
let changed_at = ChangedAt::Revision(current_revision);
|
2018-10-05 19:23:05 +00:00
|
|
|
|
|
|
|
map_write.insert(
|
|
|
|
key,
|
|
|
|
QueryState::Memoized(Memo {
|
2018-10-06 17:13:30 +00:00
|
|
|
value: Some(value),
|
|
|
|
changed_at,
|
2018-10-09 15:04:25 +00:00
|
|
|
inputs: QueryDescriptorSet::default(),
|
2018-10-09 12:53:13 +00:00
|
|
|
verified_at: current_revision,
|
2018-10-05 19:23:05 +00:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2018-10-09 12:53:13 +00:00
|
|
|
|
|
|
|
impl<DB, Q> Memo<DB, Q>
|
|
|
|
where
|
|
|
|
Q: QueryFunction<DB>,
|
|
|
|
DB: Database,
|
|
|
|
{
|
2018-10-09 19:11:57 +00:00
|
|
|
fn verify_memoized_value(&self, db: &DB) -> Option<Q::Value> {
|
2018-10-09 12:53:13 +00:00
|
|
|
// If we don't have a memoized value, nothing to validate.
|
2018-10-09 19:11:57 +00:00
|
|
|
if let Some(v) = &self.value {
|
|
|
|
// If inputs are still valid.
|
|
|
|
if self.verify_inputs(db) {
|
|
|
|
return Some(v.clone());
|
|
|
|
}
|
2018-10-09 12:53:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 19:11:57 +00:00
|
|
|
None
|
2018-10-09 13:27:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn verify_inputs(&self, db: &DB) -> bool {
|
2018-10-09 12:53:13 +00:00
|
|
|
match self.changed_at {
|
2018-10-11 08:53:33 +00:00
|
|
|
ChangedAt::Constant(_) => {
|
2018-10-09 20:20:57 +00:00
|
|
|
// If we know that the value is constant, it had
|
|
|
|
// better not change, but in that case, we ought not
|
|
|
|
// to have any inputs. Using `debug_assert` because
|
|
|
|
// this is on the fast path.
|
|
|
|
debug_assert!(match &self.inputs {
|
|
|
|
QueryDescriptorSet::Tracked(inputs) => inputs.is_empty(),
|
|
|
|
QueryDescriptorSet::Untracked => false,
|
|
|
|
});
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2018-10-09 15:04:25 +00:00
|
|
|
ChangedAt::Revision(revision) => match &self.inputs {
|
|
|
|
QueryDescriptorSet::Tracked(inputs) => inputs
|
|
|
|
.iter()
|
|
|
|
.all(|old_input| !old_input.maybe_changed_since(db, revision)),
|
|
|
|
|
|
|
|
QueryDescriptorSet::Untracked => false,
|
|
|
|
},
|
2018-10-09 12:53:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|