ra_salsa/plumbing.rs
1#![allow(missing_docs)]
2
3use crate::debug::TableEntry;
4use crate::durability::Durability;
5use crate::Cycle;
6use crate::Database;
7use crate::Query;
8use crate::QueryTable;
9use crate::QueryTableMut;
10use std::borrow::Borrow;
11use std::fmt::Debug;
12use std::hash::Hash;
13use triomphe::Arc;
14
15pub use crate::derived::MemoizedStorage;
16pub use crate::derived_lru::DependencyStorage as LruDependencyStorage;
17pub use crate::derived_lru::MemoizedStorage as LruMemoizedStorage;
18pub use crate::input::{InputStorage, UnitInputStorage};
19pub use crate::interned::InternedStorage;
20pub use crate::interned::LookupInternedStorage;
21pub use crate::{revision::Revision, DatabaseKeyIndex, QueryDb, Runtime};
22
23/// Defines various associated types. An impl of this
24/// should be generated for your query-context type automatically by
25/// the `database_storage` macro, so you shouldn't need to mess
26/// with this trait directly.
27pub trait DatabaseStorageTypes: Database {
28 /// Defines the "storage type", where all the query data is kept.
29 /// This type is defined by the `database_storage` macro.
30 type DatabaseStorage: Default;
31}
32
33/// Internal operations that the runtime uses to operate on the database.
34pub trait DatabaseOps {
35 /// Upcast this type to a `dyn Database`.
36 fn ops_database(&self) -> &dyn Database;
37
38 /// Gives access to the underlying salsa runtime.
39 fn ops_salsa_runtime(&self) -> &Runtime;
40
41 /// A "synthetic write" causes the system to act *as though* some
42 /// input of durability `durability` has changed. This is mostly
43 /// useful for profiling scenarios.
44 ///
45 /// **WARNING:** Just like an ordinary write, this method triggers
46 /// cancellation. If you invoke it while a snapshot exists, it
47 /// will block until that snapshot is dropped -- if that snapshot
48 /// is owned by the current thread, this could trigger deadlock.
49 fn synthetic_write(&mut self, durability: Durability);
50
51 /// Formats a database key index in a human readable fashion.
52 fn fmt_index(
53 &self,
54 index: DatabaseKeyIndex,
55 fmt: &mut std::fmt::Formatter<'_>,
56 ) -> std::fmt::Result;
57
58 /// True if the computed value for `input` may have changed since `revision`.
59 fn maybe_changed_after(&self, input: DatabaseKeyIndex, revision: Revision) -> bool;
60
61 /// Find the `CycleRecoveryStrategy` for a given input.
62 fn cycle_recovery_strategy(&self, input: DatabaseKeyIndex) -> CycleRecoveryStrategy;
63
64 /// Executes the callback for each kind of query.
65 fn for_each_query(&self, op: &mut dyn FnMut(&dyn QueryStorageMassOps));
66}
67
68/// Internal operations performed on the query storage as a whole
69/// (note that these ops do not need to know the identity of the
70/// query, unlike `QueryStorageOps`).
71pub trait QueryStorageMassOps {
72 fn purge(&self);
73}
74
75pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
76
77pub trait QueryFunction: Query {
78 /// See `CycleRecoveryStrategy`
79 const CYCLE_STRATEGY: CycleRecoveryStrategy;
80
81 fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
82
83 fn cycle_fallback(
84 db: &<Self as QueryDb<'_>>::DynDb,
85 cycle: &Cycle,
86 key: &Self::Key,
87 ) -> Self::Value {
88 let _ = (db, cycle, key);
89 panic!("query `{:?}` doesn't support cycle fallback", Self::default())
90 }
91}
92
93/// Cycle recovery strategy: Is this query capable of recovering from
94/// a cycle that results from executing the function? If so, how?
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum CycleRecoveryStrategy {
97 /// Cannot recover from cycles: panic.
98 ///
99 /// This is the default. It is also what happens if a cycle
100 /// occurs and the queries involved have different recovery
101 /// strategies.
102 ///
103 /// In the case of a failure due to a cycle, the panic
104 /// value will be XXX (FIXME).
105 Panic,
106
107 /// Recovers from cycles by storing a sentinel value.
108 ///
109 /// This value is computed by the `QueryFunction::cycle_fallback`
110 /// function.
111 Fallback,
112}
113
114/// Create a query table, which has access to the storage for the query
115/// and offers methods like `get`.
116pub fn get_query_table<'me, Q>(db: &'me <Q as QueryDb<'me>>::DynDb) -> QueryTable<'me, Q>
117where
118 Q: Query + 'me,
119 Q::Storage: QueryStorageOps<Q>,
120{
121 let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
122 let query_storage: &Q::Storage = Q::query_storage(group_storage);
123 QueryTable::new(db, query_storage)
124}
125
126/// Create a mutable query table, which has access to the storage
127/// for the query and offers methods like `set`.
128pub fn get_query_table_mut<'me, Q>(db: &'me mut <Q as QueryDb<'me>>::DynDb) -> QueryTableMut<'me, Q>
129where
130 Q: Query,
131{
132 let (group_storage, runtime) = HasQueryGroup::group_storage_mut(db);
133 let query_storage = Q::query_storage_mut(group_storage);
134 QueryTableMut::new(runtime, &**query_storage)
135}
136
137pub trait QueryGroup: Sized {
138 type GroupStorage;
139
140 /// Dyn version of the associated database trait.
141 type DynDb: ?Sized + Database + HasQueryGroup<Self>;
142}
143
144/// Trait implemented by a database for each group that it supports.
145/// `S` and `K` are the types for *group storage* and *group key*, respectively.
146pub trait HasQueryGroup<G>: Database
147where
148 G: QueryGroup,
149{
150 /// Access the group storage struct from the database.
151 fn group_storage(&self) -> &G::GroupStorage;
152
153 /// Access the group storage struct from the database.
154 /// Also returns a ref to the `Runtime`, since otherwise
155 /// the database is borrowed and one cannot get access to it.
156 fn group_storage_mut(&mut self) -> (&G::GroupStorage, &mut Runtime);
157}
158
159// ANCHOR:QueryStorageOps
160pub trait QueryStorageOps<Q>
161where
162 Self: QueryStorageMassOps,
163 Q: Query,
164{
165 // ANCHOR_END:QueryStorageOps
166
167 /// See CycleRecoveryStrategy
168 const CYCLE_STRATEGY: CycleRecoveryStrategy;
169
170 fn new(group_index: u16) -> Self;
171
172 /// Format a database key index in a suitable way.
173 fn fmt_index(
174 &self,
175 db: &<Q as QueryDb<'_>>::DynDb,
176 index: u32,
177 fmt: &mut std::fmt::Formatter<'_>,
178 ) -> std::fmt::Result;
179
180 // ANCHOR:maybe_changed_after
181 /// True if the value of `input`, which must be from this query, may have
182 /// changed after the given revision ended.
183 ///
184 /// This function should only be invoked with a revision less than the current
185 /// revision.
186 fn maybe_changed_after(
187 &self,
188 db: &<Q as QueryDb<'_>>::DynDb,
189 index: u32,
190 revision: Revision,
191 ) -> bool;
192 // ANCHOR_END:maybe_changed_after
193
194 fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
195 Self::CYCLE_STRATEGY
196 }
197
198 // ANCHOR:fetch
199 /// Execute the query, returning the result (often, the result
200 /// will be memoized). This is the "main method" for
201 /// queries.
202 ///
203 /// Returns `Err` in the event of a cycle, meaning that computing
204 /// the value for this `key` is recursively attempting to fetch
205 /// itself.
206 fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value;
207 // ANCHOR_END:fetch
208
209 /// Returns the durability associated with a given key.
210 fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability;
211
212 /// Get the (current) set of the entries in the query storage
213 fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
214 where
215 C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
216}
217
218/// An optional trait that is implemented for "user mutable" storage:
219/// that is, storage whose value is not derived from other storage but
220/// is set independently.
221pub trait InputQueryStorageOps<Q>
222where
223 Q: Query,
224{
225 fn set(&self, runtime: &mut Runtime, key: &Q::Key, new_value: Q::Value, durability: Durability);
226}
227
228/// An optional trait that is implemented for "user mutable" storage:
229/// that is, storage whose value is not derived from other storage but
230/// is set independently.
231pub trait LruQueryStorageOps {
232 fn set_lru_capacity(&self, new_capacity: u16);
233}
234
235pub trait DerivedQueryStorageOps<Q>
236where
237 Q: Query,
238{
239 fn invalidate<S>(&self, runtime: &mut Runtime, key: &S)
240 where
241 S: Eq + Hash,
242 Q::Key: Borrow<S>;
243}
244
245pub type CycleParticipants = Arc<Vec<DatabaseKeyIndex>>;