mirror of
https://github.com/salsa-rs/salsa.git
synced 2024-12-24 12:58:37 +00:00
Replace volatile query type with report_untracked_read fn
This commit is contained in:
parent
3534d18c64
commit
6d60798eb8
12 changed files with 18 additions and 72 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "salsa"
|
name = "salsa"
|
||||||
version = "0.12.3"
|
version = "0.13.0"
|
||||||
authors = ["Salsa developers"]
|
authors = ["Salsa developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
@ -16,7 +16,7 @@ lock_api = "0.2.0"
|
||||||
indexmap = "1.0.1"
|
indexmap = "1.0.1"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
smallvec = "0.6.5"
|
smallvec = "0.6.5"
|
||||||
salsa-macros = { version = "0.12.1", path = "components/salsa-macros" }
|
salsa-macros = { version = "0.13.0", path = "components/salsa-macros" }
|
||||||
linked-hash-map = "0.5.2"
|
linked-hash-map = "0.5.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "salsa-macros"
|
name = "salsa-macros"
|
||||||
version = "0.12.1"
|
version = "0.13.0"
|
||||||
authors = ["Salsa developers"]
|
authors = ["Salsa developers"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
|
|
|
@ -58,7 +58,6 @@ mod query_group;
|
||||||
/// are described in detail in the section below.
|
/// are described in detail in the section below.
|
||||||
/// - `#[salsa::input]`
|
/// - `#[salsa::input]`
|
||||||
/// - `#[salsa::memoized]`
|
/// - `#[salsa::memoized]`
|
||||||
/// - `#[salsa::volatile]`
|
|
||||||
/// - `#[salsa::dependencies]`
|
/// - `#[salsa::dependencies]`
|
||||||
/// - Query execution:
|
/// - Query execution:
|
||||||
/// - `#[salsa::invoke(path::to::my_fn)]` -- for a non-input, this
|
/// - `#[salsa::invoke(path::to::my_fn)]` -- for a non-input, this
|
||||||
|
@ -96,8 +95,6 @@ mod query_group;
|
||||||
/// which can significantly reduce the amount of recomputation
|
/// which can significantly reduce the amount of recomputation
|
||||||
/// required in new revisions. This does require that the value
|
/// required in new revisions. This does require that the value
|
||||||
/// implements `Eq`.
|
/// implements `Eq`.
|
||||||
/// - `#[salsa::volatile]` -- indicates that the inputs are not fully
|
|
||||||
/// captured by salsa. The result will be recomputed once per revision.
|
|
||||||
/// - `#[salsa::dependencies]` -- does not cache the value, so it will
|
/// - `#[salsa::dependencies]` -- does not cache the value, so it will
|
||||||
/// be recomputed every time it is needed. We do track the inputs, however,
|
/// be recomputed every time it is needed. We do track the inputs, however,
|
||||||
/// so if they have not changed, then things that rely on this query
|
/// so if they have not changed, then things that rely on this query
|
||||||
|
|
|
@ -54,10 +54,6 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
||||||
storage = QueryStorage::Memoized;
|
storage = QueryStorage::Memoized;
|
||||||
num_storages += 1;
|
num_storages += 1;
|
||||||
}
|
}
|
||||||
"volatile" => {
|
|
||||||
storage = QueryStorage::Volatile;
|
|
||||||
num_storages += 1;
|
|
||||||
}
|
|
||||||
"dependencies" => {
|
"dependencies" => {
|
||||||
storage = QueryStorage::Dependencies;
|
storage = QueryStorage::Dependencies;
|
||||||
num_storages += 1;
|
num_storages += 1;
|
||||||
|
@ -359,7 +355,6 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
||||||
|
|
||||||
let storage = match &query.storage {
|
let storage = match &query.storage {
|
||||||
QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<#db, Self>),
|
QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<#db, Self>),
|
||||||
QueryStorage::Volatile => quote!(salsa::plumbing::VolatileStorage<#db, Self>),
|
|
||||||
QueryStorage::Dependencies => quote!(salsa::plumbing::DependencyStorage<#db, Self>),
|
QueryStorage::Dependencies => quote!(salsa::plumbing::DependencyStorage<#db, Self>),
|
||||||
QueryStorage::Input => quote!(salsa::plumbing::InputStorage<#db, Self>),
|
QueryStorage::Input => quote!(salsa::plumbing::InputStorage<#db, Self>),
|
||||||
QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<#db, Self>),
|
QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<#db, Self>),
|
||||||
|
@ -579,7 +574,6 @@ impl Query {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
enum QueryStorage {
|
enum QueryStorage {
|
||||||
Memoized,
|
Memoized,
|
||||||
Volatile,
|
|
||||||
Dependencies,
|
Dependencies,
|
||||||
Input,
|
Input,
|
||||||
Interned,
|
Interned,
|
||||||
|
@ -594,7 +588,7 @@ impl QueryStorage {
|
||||||
| QueryStorage::Interned
|
| QueryStorage::Interned
|
||||||
| QueryStorage::InternedLookup { .. }
|
| QueryStorage::InternedLookup { .. }
|
||||||
| QueryStorage::Transparent => false,
|
| QueryStorage::Transparent => false,
|
||||||
QueryStorage::Memoized | QueryStorage::Volatile | QueryStorage::Dependencies => true,
|
QueryStorage::Memoized | QueryStorage::Dependencies => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,6 @@ pub type MemoizedStorage<DB, Q> = DerivedStorage<DB, Q, AlwaysMemoizeValue>;
|
||||||
/// storage requirements.
|
/// storage requirements.
|
||||||
pub type DependencyStorage<DB, Q> = DerivedStorage<DB, Q, NeverMemoizeValue>;
|
pub type DependencyStorage<DB, Q> = DerivedStorage<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> = DerivedStorage<DB, Q, VolatileValue>;
|
|
||||||
|
|
||||||
/// Handles storage where the value is 'derived' by executing a
|
/// Handles storage where the value is 'derived' by executing a
|
||||||
/// function (in contrast to "inputs").
|
/// function (in contrast to "inputs").
|
||||||
pub struct DerivedStorage<DB, Q, MP>
|
pub struct DerivedStorage<DB, Q, MP>
|
||||||
|
@ -73,8 +68,6 @@ where
|
||||||
fn should_memoize_value(key: &Q::Key) -> bool;
|
fn should_memoize_value(key: &Q::Key) -> bool;
|
||||||
|
|
||||||
fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool;
|
fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool;
|
||||||
|
|
||||||
fn should_track_inputs(key: &Q::Key) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum AlwaysMemoizeValue {}
|
pub enum AlwaysMemoizeValue {}
|
||||||
|
@ -91,10 +84,6 @@ where
|
||||||
fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool {
|
fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool {
|
||||||
old_value == new_value
|
old_value == new_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum NeverMemoizeValue {}
|
pub enum NeverMemoizeValue {}
|
||||||
|
@ -110,34 +99,6 @@ where
|
||||||
fn memoized_value_eq(_old_value: &Q::Value, _new_value: &Q::Value) -> bool {
|
fn memoized_value_eq(_old_value: &Q::Value, _new_value: &Q::Value) -> bool {
|
||||||
panic!("cannot reach since we never memoize")
|
panic!("cannot reach since we never memoize")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn memoized_value_eq(_old_value: &Q::Value, _new_value: &Q::Value) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_track_inputs(_key: &Q::Key) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the "current state" of query's memoized results.
|
/// Defines the "current state" of query's memoized results.
|
||||||
|
@ -443,11 +404,6 @@ where
|
||||||
// stale, or value is absent. Let's execute!
|
// stale, or value is absent. Let's execute!
|
||||||
let mut result = runtime.execute_query_implementation(db, database_key, || {
|
let mut result = runtime.execute_query_implementation(db, database_key, || {
|
||||||
info!("{:?}({:?}): executing query", Q::default(), key);
|
info!("{:?}({:?}): executing query", Q::default(), key);
|
||||||
|
|
||||||
if !self.should_track_inputs(key) {
|
|
||||||
runtime.report_untracked_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
Q::execute(db, key.clone())
|
Q::execute(db, key.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -649,10 +605,6 @@ where
|
||||||
fn should_memoize_value(&self, key: &Q::Key) -> bool {
|
fn should_memoize_value(&self, key: &Q::Key) -> bool {
|
||||||
MP::should_memoize_value(key)
|
MP::should_memoize_value(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_track_inputs(&self, key: &Q::Key) -> bool {
|
|
||||||
MP::should_track_inputs(key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PanicGuard<'db, DB, Q>
|
struct PanicGuard<'db, DB, Q>
|
||||||
|
|
|
@ -11,7 +11,6 @@ use std::hash::Hash;
|
||||||
|
|
||||||
pub use crate::derived::DependencyStorage;
|
pub use crate::derived::DependencyStorage;
|
||||||
pub use crate::derived::MemoizedStorage;
|
pub use crate::derived::MemoizedStorage;
|
||||||
pub use crate::derived::VolatileStorage;
|
|
||||||
pub use crate::input::InputStorage;
|
pub use crate::input::InputStorage;
|
||||||
pub use crate::interned::InternedStorage;
|
pub use crate::interned::InternedStorage;
|
||||||
pub use crate::interned::LookupInternedStorage;
|
pub use crate::interned::LookupInternedStorage;
|
||||||
|
|
|
@ -344,7 +344,11 @@ where
|
||||||
self.local_state.report_query_read(database_key, changed_at);
|
self.local_state.report_query_read(database_key, changed_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn report_untracked_read(&self) {
|
/// Reports that the query depends on some state unknown to salsa.
|
||||||
|
///
|
||||||
|
/// If query reports untracked read, it will be reexuted in the next
|
||||||
|
/// revision.
|
||||||
|
pub fn report_untracked_read(&self) {
|
||||||
self.local_state
|
self.local_state
|
||||||
.report_untracked_read(self.current_revision());
|
.report_untracked_read(self.current_revision());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,7 @@ trait Database: salsa::Database {
|
||||||
// `a` and `b` depend on each other and form a cycle
|
// `a` and `b` depend on each other and form a cycle
|
||||||
fn memoized_a(&self) -> ();
|
fn memoized_a(&self) -> ();
|
||||||
fn memoized_b(&self) -> ();
|
fn memoized_b(&self) -> ();
|
||||||
#[salsa::volatile]
|
|
||||||
fn volatile_a(&self) -> ();
|
fn volatile_a(&self) -> ();
|
||||||
#[salsa::volatile]
|
|
||||||
fn volatile_b(&self) -> ();
|
fn volatile_b(&self) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +28,12 @@ fn memoized_b(db: &impl Database) -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volatile_a(db: &impl Database) -> () {
|
fn volatile_a(db: &impl Database) -> () {
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
db.volatile_b()
|
db.volatile_b()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volatile_b(db: &impl Database) -> () {
|
fn volatile_b(db: &impl Database) -> () {
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
db.volatile_a()
|
db.volatile_a()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,11 @@ use std::sync::Arc;
|
||||||
|
|
||||||
/// Query group for tests for how interned keys interact with GC.
|
/// Query group for tests for how interned keys interact with GC.
|
||||||
#[salsa::query_group(Volatile)]
|
#[salsa::query_group(Volatile)]
|
||||||
pub(crate) trait VolatileDatabase {
|
pub(crate) trait VolatileDatabase: Database {
|
||||||
#[salsa::input]
|
#[salsa::input]
|
||||||
fn atomic_cell(&self) -> Arc<AtomicUsize>;
|
fn atomic_cell(&self) -> Arc<AtomicUsize>;
|
||||||
|
|
||||||
/// Underlying volatile query.
|
/// Underlying volatile query.
|
||||||
#[salsa::volatile]
|
|
||||||
fn volatile(&self) -> usize;
|
fn volatile(&self) -> usize;
|
||||||
|
|
||||||
/// This just executes the intern query and returns the result.
|
/// This just executes the intern query and returns the result.
|
||||||
|
@ -21,6 +20,7 @@ pub(crate) trait VolatileDatabase {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn volatile(db: &impl VolatileDatabase) -> usize {
|
fn volatile(db: &impl VolatileDatabase) -> usize {
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
db.atomic_cell().load(Ordering::SeqCst)
|
db.atomic_cell().load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ pub(crate) trait MemoizedVolatileContext: TestContext {
|
||||||
// memoization.
|
// memoization.
|
||||||
fn memoized2(&self) -> usize;
|
fn memoized2(&self) -> usize;
|
||||||
fn memoized1(&self) -> usize;
|
fn memoized1(&self) -> usize;
|
||||||
#[salsa::volatile]
|
|
||||||
fn volatile(&self) -> usize;
|
fn volatile(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +23,7 @@ fn memoized1(db: &impl MemoizedVolatileContext) -> usize {
|
||||||
|
|
||||||
fn volatile(db: &impl MemoizedVolatileContext) -> usize {
|
fn volatile(db: &impl MemoizedVolatileContext) -> usize {
|
||||||
db.log().add("Volatile invoked");
|
db.log().add("Volatile invoked");
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
db.clock().increment()
|
db.clock().increment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,8 @@ impl Drop for HotPotato {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[salsa::query_group(QueryGroupStorage)]
|
#[salsa::query_group(QueryGroupStorage)]
|
||||||
trait QueryGroup {
|
trait QueryGroup: salsa::Database {
|
||||||
fn get(&self, x: u32) -> Arc<HotPotato>;
|
fn get(&self, x: u32) -> Arc<HotPotato>;
|
||||||
#[salsa::volatile]
|
|
||||||
fn get_volatile(&self, x: u32) -> usize;
|
fn get_volatile(&self, x: u32) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +34,9 @@ fn get(_db: &impl QueryGroup, x: u32) -> Arc<HotPotato> {
|
||||||
Arc::new(HotPotato::new(x))
|
Arc::new(HotPotato::new(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volatile(_db: &impl QueryGroup, _x: u32) -> usize {
|
fn get_volatile(db: &impl QueryGroup, _x: u32) -> usize {
|
||||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
COUNTER.fetch_add(1, Ordering::SeqCst)
|
COUNTER.fetch_add(1, Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ pub(crate) trait Counter: salsa::Database {
|
||||||
#[salsa::query_group(GroupStruct)]
|
#[salsa::query_group(GroupStruct)]
|
||||||
pub(crate) trait Database: Counter {
|
pub(crate) trait Database: Counter {
|
||||||
fn memoized(&self) -> usize;
|
fn memoized(&self) -> usize;
|
||||||
#[salsa::volatile]
|
|
||||||
fn volatile(&self) -> usize;
|
fn volatile(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,5 +17,6 @@ fn memoized(db: &impl Database) -> usize {
|
||||||
/// Because this query is volatile, each time it is invoked,
|
/// Because this query is volatile, each time it is invoked,
|
||||||
/// we will increment the counter.
|
/// we will increment the counter.
|
||||||
fn volatile(db: &impl Database) -> usize {
|
fn volatile(db: &impl Database) -> usize {
|
||||||
|
db.salsa_runtime().report_untracked_read();
|
||||||
db.increment()
|
db.increment()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue