mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-23 13:10:19 +00:00
document (and start warning on missing docs)
This commit is contained in:
parent
49cc8abe43
commit
a8ca57c06d
4 changed files with 142 additions and 12 deletions
|
@ -7,7 +7,11 @@ use crate::Query;
|
||||||
use crate::QueryTable;
|
use crate::QueryTable;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
/// Additional methods on queries that can be used to "peek into"
|
||||||
|
/// their current state. These methods are meant for debugging and
|
||||||
|
/// observing the effects of garbage collection etc.
|
||||||
pub trait DebugQueryTable {
|
pub trait DebugQueryTable {
|
||||||
|
/// Key of this query.
|
||||||
type Key;
|
type Key;
|
||||||
|
|
||||||
/// True if salsa thinks that the value for `key` is a
|
/// True if salsa thinks that the value for `key` is a
|
||||||
|
|
138
src/lib.rs
138
src/lib.rs
|
@ -1,6 +1,13 @@
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
//! The salsa crate is a crate for incremental recomputation. It
|
||||||
|
//! permits you to define a "database" of queries with both inputs and
|
||||||
|
//! values derived from those inputs; as you set the inputs, you can
|
||||||
|
//! re-execute the derived queries and it will try to re-use results
|
||||||
|
//! from previous invocations as appropriate.
|
||||||
|
|
||||||
mod derived;
|
mod derived;
|
||||||
mod input;
|
mod input;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
|
@ -52,8 +59,11 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps {
|
||||||
self.salsa_runtime().sweep_all(self, strategy);
|
self.salsa_runtime().sweep_all(self, strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get access to extra methods pertaining to a given query,
|
/// Get access to extra methods pertaining to a given query. For
|
||||||
/// notably `set` (for inputs).
|
/// example, you can use this to run the GC (`sweep`) across a
|
||||||
|
/// single input. You can also use it to invoke a query, though
|
||||||
|
/// it's more common to use the trait method on the database
|
||||||
|
/// itself.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn query<Q>(&self, query: Q) -> QueryTable<'_, Self, Q>
|
fn query<Q>(&self, query: Q) -> QueryTable<'_, Self, Q>
|
||||||
where
|
where
|
||||||
|
@ -63,8 +73,33 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps {
|
||||||
<Self as plumbing::GetQueryTable<Q>>::get_query_table(self)
|
<Self as plumbing::GetQueryTable<Q>>::get_query_table(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get access to extra methods pertaining to a given query,
|
/// Like `query`, but gives access to methods for setting the
|
||||||
/// notably `set` (for inputs).
|
/// value of an input.
|
||||||
|
///
|
||||||
|
/// # Threads, cancellation, and blocking
|
||||||
|
///
|
||||||
|
/// Mutating the value of a query cannot be done while there are
|
||||||
|
/// still other queries executing. If you are using your database
|
||||||
|
/// within a single thread, this is not a problem: you only have
|
||||||
|
/// `&self` access to the database, but this method requires `&mut
|
||||||
|
/// self`.
|
||||||
|
///
|
||||||
|
/// However, if you have used `snapshot` to create other threads,
|
||||||
|
/// then attempts to `set` will **block the current thread** until
|
||||||
|
/// those snapshots are dropped (usually when those threads
|
||||||
|
/// complete). This also implies that if you create a snapshot but
|
||||||
|
/// do not send it to another thread, then invoking `set` will
|
||||||
|
/// deadlock.
|
||||||
|
///
|
||||||
|
/// Before blocking, the thread that is attempting to `set` will
|
||||||
|
/// also set a cancellation flag. In the threads operating on
|
||||||
|
/// snapshots, you can use the [`is_current_revision_canceled`]
|
||||||
|
/// method to check for this flag and bring those operations to a
|
||||||
|
/// close, thus allowing the `set` to succeed. Ignoring this flag
|
||||||
|
/// may lead to "starvation", meaning that the thread attempting
|
||||||
|
/// to `set` has to wait a long, long time. =)
|
||||||
|
///
|
||||||
|
/// [`is_current_revision_canceled`]: struct.Runtime.html#method.is_current_revision_canceled
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn query_mut<Q>(&mut self, query: Q) -> QueryTableMut<'_, Self, Q>
|
fn query_mut<Q>(&mut self, query: Q) -> QueryTableMut<'_, Self, Q>
|
||||||
where
|
where
|
||||||
|
@ -82,8 +117,15 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `Event` struct identifies various notable things that can
|
||||||
|
/// occur during salsa execution. Instances of this struct are given
|
||||||
|
/// to `salsa_event`.
|
||||||
pub struct Event<DB: Database> {
|
pub struct Event<DB: Database> {
|
||||||
|
/// The id of the snapshot that triggered the event. Usually
|
||||||
|
/// 1-to-1 with a thread, as well.
|
||||||
pub runtime_id: RuntimeId,
|
pub runtime_id: RuntimeId,
|
||||||
|
|
||||||
|
/// What sort of event was it.
|
||||||
pub kind: EventKind<DB>,
|
pub kind: EventKind<DB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,13 +138,17 @@ impl<DB: Database> fmt::Debug for Event<DB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An enum identifying the various kinds of events that can occur.
|
||||||
pub enum EventKind<DB: Database> {
|
pub enum EventKind<DB: Database> {
|
||||||
/// Occurs when we found that all inputs to a memoized value are
|
/// Occurs when we found that all inputs to a memoized value are
|
||||||
/// up-to-date and hence the value can be re-used without
|
/// up-to-date and hence the value can be re-used without
|
||||||
/// executing the closure.
|
/// executing the closure.
|
||||||
///
|
///
|
||||||
/// Executes before the "re-used" value is returned.
|
/// Executes before the "re-used" value is returned.
|
||||||
DidValidateMemoizedValue { descriptor: DB::QueryDescriptor },
|
DidValidateMemoizedValue {
|
||||||
|
/// The descriptor for the affected value. Implements `Debug`.
|
||||||
|
descriptor: DB::QueryDescriptor,
|
||||||
|
},
|
||||||
|
|
||||||
/// Indicates that another thread (with id `other_runtime_id`) is processing the
|
/// Indicates that another thread (with id `other_runtime_id`) is processing the
|
||||||
/// given query (`descriptor`), so we will block until they
|
/// given query (`descriptor`), so we will block until they
|
||||||
|
@ -114,18 +160,27 @@ pub enum EventKind<DB: Database> {
|
||||||
/// (NB: you can find the `id` of the current thread via the
|
/// (NB: you can find the `id` of the current thread via the
|
||||||
/// `salsa_runtime`)
|
/// `salsa_runtime`)
|
||||||
WillBlockOn {
|
WillBlockOn {
|
||||||
|
/// The id of the runtime we will block on.
|
||||||
other_runtime_id: RuntimeId,
|
other_runtime_id: RuntimeId,
|
||||||
|
|
||||||
|
/// The descriptor for the affected value. Implements `Debug`.
|
||||||
descriptor: DB::QueryDescriptor,
|
descriptor: DB::QueryDescriptor,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Indicates that the input value will change after this
|
/// Indicates that the input value will change after this
|
||||||
/// callback, e.g. due to a call to `set`.
|
/// callback, e.g. due to a call to `set`.
|
||||||
WillChangeInputValue { descriptor: DB::QueryDescriptor },
|
WillChangeInputValue {
|
||||||
|
/// The descriptor for the affected value. Implements `Debug`.
|
||||||
|
descriptor: DB::QueryDescriptor,
|
||||||
|
},
|
||||||
|
|
||||||
/// Indicates that the function for this query will be executed.
|
/// Indicates that the function for this query will be executed.
|
||||||
/// This is either because it has never executed before or because
|
/// This is either because it has never executed before or because
|
||||||
/// its inputs may be out of date.
|
/// its inputs may be out of date.
|
||||||
WillExecute { descriptor: DB::QueryDescriptor },
|
WillExecute {
|
||||||
|
/// The descriptor for the affected value. Implements `Debug`.
|
||||||
|
descriptor: DB::QueryDescriptor,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB: Database> fmt::Debug for EventKind<DB> {
|
impl<DB: Database> fmt::Debug for EventKind<DB> {
|
||||||
|
@ -241,9 +296,9 @@ pub trait ParallelDatabase: Database + Send {
|
||||||
fn snapshot(&self) -> Snapshot<Self>;
|
fn snapshot(&self) -> Snapshot<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple wrapper struct that takes ownership of a database `DB`
|
/// Simple wrapper struct that takes ownership of a database `DB` and
|
||||||
/// and only gives `&self` access to it. See [the `snapshot` method][fm] for
|
/// only gives `&self` access to it. See [the `snapshot` method][fm]
|
||||||
/// more details.
|
/// for more details.
|
||||||
///
|
///
|
||||||
/// [fm]: trait.ParallelDatabase#method.snapshot
|
/// [fm]: trait.ParallelDatabase#method.snapshot
|
||||||
pub struct Snapshot<DB>
|
pub struct Snapshot<DB>
|
||||||
|
@ -257,6 +312,9 @@ impl<DB> Snapshot<DB>
|
||||||
where
|
where
|
||||||
DB: ParallelDatabase,
|
DB: ParallelDatabase,
|
||||||
{
|
{
|
||||||
|
/// Creates a `Snapshot` that wraps the given database handle
|
||||||
|
/// `db`. From this point forward, only shared references to `db`
|
||||||
|
/// will be possible.
|
||||||
pub fn new(db: DB) -> Self {
|
pub fn new(db: DB) -> Self {
|
||||||
Snapshot { db }
|
Snapshot { db }
|
||||||
}
|
}
|
||||||
|
@ -273,12 +331,24 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait implements by all of the "special types" associated with
|
||||||
|
/// each of your queries.
|
||||||
pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
||||||
|
/// Type that you you give as a parameter -- for queries with zero
|
||||||
|
/// or more than one input, this will be a tuple.
|
||||||
type Key: Clone + Debug + Hash + Eq;
|
type Key: Clone + Debug + Hash + Eq;
|
||||||
|
|
||||||
|
/// What value does the query return?
|
||||||
type Value: Clone + Debug;
|
type Value: Clone + Debug;
|
||||||
|
|
||||||
|
/// Internal struct storing the values for the query.
|
||||||
type Storage: plumbing::QueryStorageOps<DB, Self> + Send + Sync;
|
type Storage: plumbing::QueryStorageOps<DB, Self> + Send + Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return value from [the `query` method] on `Database`.
|
||||||
|
/// Gives access to various less common operations on queries.
|
||||||
|
///
|
||||||
|
/// [the `query_mut` method]: trait.Database#method.query
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct QueryTable<'me, DB, Q>
|
pub struct QueryTable<'me, DB, Q>
|
||||||
where
|
where
|
||||||
|
@ -295,6 +365,10 @@ where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
Q: Query<DB>,
|
Q: Query<DB>,
|
||||||
{
|
{
|
||||||
|
/// Execute the query on a given input. Usually it's easier to
|
||||||
|
/// invoke the trait method directly. Note that for variadic
|
||||||
|
/// queries (those with no inputs, or those with more than one
|
||||||
|
/// input) the key will be a tuple.
|
||||||
pub fn get(&self, key: Q::Key) -> Q::Value {
|
pub fn get(&self, key: Q::Key) -> Q::Value {
|
||||||
let descriptor = self.descriptor(&key);
|
let descriptor = self.descriptor(&key);
|
||||||
self.storage
|
self.storage
|
||||||
|
@ -304,6 +378,8 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove all values for this query that have not been used in
|
||||||
|
/// the most recent revision.
|
||||||
pub fn sweep(&self, strategy: SweepStrategy)
|
pub fn sweep(&self, strategy: SweepStrategy)
|
||||||
where
|
where
|
||||||
Q::Storage: plumbing::QueryStorageMassOps<DB>,
|
Q::Storage: plumbing::QueryStorageMassOps<DB>,
|
||||||
|
@ -316,6 +392,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return value from [the `query_mut` method] on `Database`.
|
||||||
|
/// Gives access to the `set` method, notably, that is used to
|
||||||
|
/// set the value of an input query.
|
||||||
|
///
|
||||||
|
/// [the `query_mut` method]: trait.Database#method.query_mut
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct QueryTableMut<'me, DB, Q>
|
pub struct QueryTableMut<'me, DB, Q>
|
||||||
where
|
where
|
||||||
|
@ -338,6 +419,11 @@ where
|
||||||
|
|
||||||
/// Assign a value to an "input query". Must be used outside of
|
/// Assign a value to an "input query". Must be used outside of
|
||||||
/// an active query computation.
|
/// an active query computation.
|
||||||
|
///
|
||||||
|
/// If you are using `snapshot`, see the notes on blocking
|
||||||
|
/// and cancellation on [the `query_mut` method].
|
||||||
|
///
|
||||||
|
/// [the `query_mut` method]: trait.Database#method.query_mut
|
||||||
pub fn set(&self, key: Q::Key, value: Q::Value)
|
pub fn set(&self, key: Q::Key, value: Q::Value)
|
||||||
where
|
where
|
||||||
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||||
|
@ -349,6 +435,11 @@ where
|
||||||
/// Assign a value to an "input query", with the additional
|
/// Assign a value to an "input query", with the additional
|
||||||
/// promise that this value will **never change**. Must be used
|
/// promise that this value will **never change**. Must be used
|
||||||
/// outside of an active query computation.
|
/// outside of an active query computation.
|
||||||
|
///
|
||||||
|
/// If you are using `snapshot`, see the notes on blocking
|
||||||
|
/// and cancellation on [the `query_mut` method].
|
||||||
|
///
|
||||||
|
/// [the `query_mut` method]: trait.Database#method.query_mut
|
||||||
pub fn set_constant(&self, key: Q::Key, value: Q::Value)
|
pub fn set_constant(&self, key: Q::Key, value: Q::Value)
|
||||||
where
|
where
|
||||||
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||||
|
@ -667,8 +758,31 @@ macro_rules! query_group {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This macro generates the "query storage" that goes into your query
|
/// This macro generates the "query storage" that goes into your database.
|
||||||
/// context.
|
/// It requires you to list all of the query groups that you need as well
|
||||||
|
/// as the queries within those groups. The format looks like so:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// salsa::database_storage! {
|
||||||
|
/// struct MyDatabaseStorage for MyDatabase {
|
||||||
|
/// impl MyQueryGroup {
|
||||||
|
/// fn my_query1() for MyQuery1;
|
||||||
|
/// fn my_query2() for MyQuery2;
|
||||||
|
/// }
|
||||||
|
/// // ... other query groups go here ...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Here, `MyDatabase` should be the name of your database type. The
|
||||||
|
/// macro will then generate a struct named `MyDatabaseStorage` that
|
||||||
|
/// is used by the [`salsa::Runtime`]. `MyQueryGroup` should be the
|
||||||
|
/// name of your query group.
|
||||||
|
///
|
||||||
|
/// See [the `hello_world` example][hw] for more details.
|
||||||
|
///
|
||||||
|
/// [`salsa::Runtime`]: struct.Runtime.html
|
||||||
|
/// [hw]: https://github.com/salsa-rs/salsa/tree/master/examples/hello_world
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! database_storage {
|
macro_rules! database_storage {
|
||||||
(
|
(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
use crate::Query;
|
use crate::Query;
|
||||||
use crate::QueryTable;
|
use crate::QueryTable;
|
||||||
|
|
|
@ -65,6 +65,8 @@ impl<DB> Runtime<DB>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
{
|
{
|
||||||
|
/// Create a new runtime; equivalent to `Self::default`. This is
|
||||||
|
/// used when creating a new database.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
@ -480,11 +482,19 @@ impl<DB: Database> ActiveQuery<DB> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A unique identifier for a particular runtime. Each time you create
|
||||||
|
/// a snapshot, a fresh `RuntimeId` is generated. Once a snapshot is
|
||||||
|
/// complete, its `RuntimeId` may potentially be re-used.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct RuntimeId {
|
pub struct RuntimeId {
|
||||||
counter: usize,
|
counter: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A unique identifier for the current version of the database; each
|
||||||
|
/// time an input is changed, the revision number is incremented.
|
||||||
|
/// `Revision` is used internally to track which values may need to be
|
||||||
|
/// recomputed, but not something you should have to interact with
|
||||||
|
/// directly as a user of salsa.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct Revision {
|
pub struct Revision {
|
||||||
generation: u64,
|
generation: u64,
|
||||||
|
|
Loading…
Reference in a new issue