]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | #![warn(rust_2018_idioms)] |
2 | #![warn(missing_docs)] | |
3 | ||
4 | //! The salsa crate is a crate for incremental recomputation. It | |
5 | //! permits you to define a "database" of queries with both inputs and | |
6 | //! values derived from those inputs; as you set the inputs, you can | |
7 | //! re-execute the derived queries and it will try to re-use results | |
8 | //! from previous invocations as appropriate. | |
9 | ||
3dfed10e | 10 | mod blocking_future; |
f035d41b XL |
11 | mod derived; |
12 | mod doctest; | |
13 | mod durability; | |
14 | mod input; | |
15 | mod intern_id; | |
16 | mod interned; | |
17 | mod lru; | |
18 | mod revision; | |
19 | mod runtime; | |
3dfed10e | 20 | mod storage; |
f035d41b XL |
21 | |
22 | pub mod debug; | |
23 | /// Items in this module are public for implementation reasons, | |
24 | /// and are exempt from the SemVer guarantees. | |
25 | #[doc(hidden)] | |
26 | pub mod plumbing; | |
27 | ||
28 | use crate::plumbing::DerivedQueryStorageOps; | |
29 | use crate::plumbing::InputQueryStorageOps; | |
30 | use crate::plumbing::LruQueryStorageOps; | |
31 | use crate::plumbing::QueryStorageMassOps; | |
32 | use crate::plumbing::QueryStorageOps; | |
3dfed10e | 33 | pub use crate::revision::Revision; |
f035d41b XL |
34 | use std::fmt::{self, Debug}; |
35 | use std::hash::Hash; | |
36 | use std::sync::Arc; | |
37 | ||
38 | pub use crate::durability::Durability; | |
39 | pub use crate::intern_id::InternId; | |
40 | pub use crate::interned::InternKey; | |
41 | pub use crate::runtime::Runtime; | |
42 | pub use crate::runtime::RuntimeId; | |
3dfed10e | 43 | pub use crate::storage::Storage; |
f035d41b XL |
44 | |
45 | /// The base trait which your "query context" must implement. Gives | |
46 | /// access to the salsa runtime, which you must embed into your query | |
47 | /// context (along with whatever other state you may require). | |
3dfed10e | 48 | pub trait Database: 'static + plumbing::DatabaseOps { |
f035d41b XL |
49 | /// Iterates through all query storage and removes any values that |
50 | /// have not been used since the last revision was created. The | |
51 | /// intended use-cycle is that you first execute all of your | |
52 | /// "main" queries; this will ensure that all query values they | |
53 | /// consume are marked as used. You then invoke this method to | |
54 | /// remove other values that were not needed for your main query | |
55 | /// results. | |
56 | fn sweep_all(&self, strategy: SweepStrategy) { | |
3dfed10e XL |
57 | // Note that we do not acquire the query lock (or any locks) |
58 | // here. Each table is capable of sweeping itself atomically | |
59 | // and there is no need to bring things to a halt. That said, | |
60 | // users may wish to guarantee atomicity. | |
f035d41b | 61 | |
3dfed10e XL |
62 | let runtime = self.salsa_runtime(); |
63 | self.for_each_query(&mut |query_storage| query_storage.sweep(runtime, strategy)); | |
f035d41b XL |
64 | } |
65 | ||
66 | /// This function is invoked at key points in the salsa | |
67 | /// runtime. It permits the database to be customized and to | |
68 | /// inject logging or other custom behavior. | |
3dfed10e | 69 | fn salsa_event(&self, event_fn: Event) { |
f035d41b XL |
70 | #![allow(unused_variables)] |
71 | } | |
72 | ||
73 | /// This function is invoked when a dependent query is being computed by the | |
74 | /// other thread, and that thread panics. | |
75 | fn on_propagated_panic(&self) -> ! { | |
76 | panic!("concurrent salsa query panicked") | |
77 | } | |
3dfed10e XL |
78 | |
79 | /// Gives access to the underlying salsa runtime. | |
80 | fn salsa_runtime(&self) -> &Runtime { | |
81 | self.ops_salsa_runtime() | |
82 | } | |
83 | ||
84 | /// Gives access to the underlying salsa runtime. | |
85 | fn salsa_runtime_mut(&mut self) -> &mut Runtime { | |
86 | self.ops_salsa_runtime_mut() | |
87 | } | |
f035d41b XL |
88 | } |
89 | ||
90 | /// The `Event` struct identifies various notable things that can | |
91 | /// occur during salsa execution. Instances of this struct are given | |
92 | /// to `salsa_event`. | |
3dfed10e | 93 | pub struct Event { |
f035d41b XL |
94 | /// The id of the snapshot that triggered the event. Usually |
95 | /// 1-to-1 with a thread, as well. | |
96 | pub runtime_id: RuntimeId, | |
97 | ||
98 | /// What sort of event was it. | |
3dfed10e | 99 | pub kind: EventKind, |
f035d41b XL |
100 | } |
101 | ||
3dfed10e | 102 | impl fmt::Debug for Event { |
f035d41b XL |
103 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
104 | fmt.debug_struct("Event") | |
105 | .field("runtime_id", &self.runtime_id) | |
106 | .field("kind", &self.kind) | |
107 | .finish() | |
108 | } | |
109 | } | |
110 | ||
111 | /// An enum identifying the various kinds of events that can occur. | |
3dfed10e | 112 | pub enum EventKind { |
f035d41b XL |
113 | /// Occurs when we found that all inputs to a memoized value are |
114 | /// up-to-date and hence the value can be re-used without | |
115 | /// executing the closure. | |
116 | /// | |
117 | /// Executes before the "re-used" value is returned. | |
118 | DidValidateMemoizedValue { | |
119 | /// The database-key for the affected value. Implements `Debug`. | |
3dfed10e | 120 | database_key: DatabaseKeyIndex, |
f035d41b XL |
121 | }, |
122 | ||
123 | /// Indicates that another thread (with id `other_runtime_id`) is processing the | |
124 | /// given query (`database_key`), so we will block until they | |
125 | /// finish. | |
126 | /// | |
127 | /// Executes after we have registered with the other thread but | |
128 | /// before they have answered us. | |
129 | /// | |
130 | /// (NB: you can find the `id` of the current thread via the | |
131 | /// `salsa_runtime`) | |
132 | WillBlockOn { | |
133 | /// The id of the runtime we will block on. | |
134 | other_runtime_id: RuntimeId, | |
135 | ||
136 | /// The database-key for the affected value. Implements `Debug`. | |
3dfed10e | 137 | database_key: DatabaseKeyIndex, |
f035d41b XL |
138 | }, |
139 | ||
140 | /// Indicates that the function for this query will be executed. | |
141 | /// This is either because it has never executed before or because | |
142 | /// its inputs may be out of date. | |
143 | WillExecute { | |
144 | /// The database-key for the affected value. Implements `Debug`. | |
3dfed10e | 145 | database_key: DatabaseKeyIndex, |
f035d41b XL |
146 | }, |
147 | } | |
148 | ||
3dfed10e | 149 | impl fmt::Debug for EventKind { |
f035d41b XL |
150 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
151 | match self { | |
152 | EventKind::DidValidateMemoizedValue { database_key } => fmt | |
153 | .debug_struct("DidValidateMemoizedValue") | |
154 | .field("database_key", database_key) | |
155 | .finish(), | |
156 | EventKind::WillBlockOn { | |
157 | other_runtime_id, | |
158 | database_key, | |
159 | } => fmt | |
160 | .debug_struct("WillBlockOn") | |
161 | .field("other_runtime_id", other_runtime_id) | |
162 | .field("database_key", database_key) | |
163 | .finish(), | |
f035d41b XL |
164 | EventKind::WillExecute { database_key } => fmt |
165 | .debug_struct("WillExecute") | |
166 | .field("database_key", database_key) | |
167 | .finish(), | |
168 | } | |
169 | } | |
170 | } | |
171 | ||
172 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | |
173 | enum DiscardIf { | |
174 | Never, | |
175 | Outdated, | |
176 | Always, | |
177 | } | |
178 | ||
179 | impl Default for DiscardIf { | |
180 | fn default() -> DiscardIf { | |
181 | DiscardIf::Never | |
182 | } | |
183 | } | |
184 | ||
185 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | |
186 | enum DiscardWhat { | |
187 | Nothing, | |
188 | Values, | |
189 | Everything, | |
190 | } | |
191 | ||
192 | impl Default for DiscardWhat { | |
193 | fn default() -> DiscardWhat { | |
194 | DiscardWhat::Nothing | |
195 | } | |
196 | } | |
197 | ||
198 | /// The sweep strategy controls what data we will keep/discard when we | |
199 | /// do a GC-sweep. The default (`SweepStrategy::default`) is a no-op, | |
200 | /// use `SweepStrategy::discard_outdated` constructor or `discard_*` | |
201 | /// and `sweep_*` builder functions to construct useful strategies. | |
202 | #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] | |
203 | pub struct SweepStrategy { | |
204 | discard_if: DiscardIf, | |
205 | discard_what: DiscardWhat, | |
3dfed10e | 206 | shrink_to_fit: bool, |
f035d41b XL |
207 | } |
208 | ||
209 | impl SweepStrategy { | |
210 | /// Convenience function that discards all data not used thus far in the | |
211 | /// current revision. | |
212 | /// | |
213 | /// Equivalent to `SweepStrategy::default().discard_everything()`. | |
214 | pub fn discard_outdated() -> SweepStrategy { | |
215 | SweepStrategy::default() | |
216 | .discard_everything() | |
217 | .sweep_outdated() | |
218 | } | |
219 | ||
220 | /// Collects query values. | |
221 | /// | |
222 | /// Query dependencies are left in the database, which allows to quickly | |
223 | /// determine if the query is up to date, and avoid recomputing | |
224 | /// dependencies. | |
225 | pub fn discard_values(self) -> SweepStrategy { | |
226 | SweepStrategy { | |
227 | discard_what: self.discard_what.max(DiscardWhat::Values), | |
228 | ..self | |
229 | } | |
230 | } | |
231 | ||
232 | /// Collects both values and information about dependencies. | |
233 | /// | |
234 | /// Dependant queries will be recomputed even if all inputs to this query | |
235 | /// stay the same. | |
236 | pub fn discard_everything(self) -> SweepStrategy { | |
237 | SweepStrategy { | |
238 | discard_what: self.discard_what.max(DiscardWhat::Everything), | |
239 | ..self | |
240 | } | |
241 | } | |
242 | ||
243 | /// Process all keys, not verefied at the current revision. | |
244 | pub fn sweep_outdated(self) -> SweepStrategy { | |
245 | SweepStrategy { | |
246 | discard_if: self.discard_if.max(DiscardIf::Outdated), | |
247 | ..self | |
248 | } | |
249 | } | |
250 | ||
251 | /// Process all keys. | |
252 | pub fn sweep_all_revisions(self) -> SweepStrategy { | |
253 | SweepStrategy { | |
254 | discard_if: self.discard_if.max(DiscardIf::Always), | |
255 | ..self | |
256 | } | |
257 | } | |
258 | } | |
259 | ||
260 | /// Indicates a database that also supports parallel query | |
261 | /// evaluation. All of Salsa's base query support is capable of | |
262 | /// parallel execution, but for it to work, your query key/value types | |
263 | /// must also be `Send`, as must any additional data in your database. | |
264 | pub trait ParallelDatabase: Database + Send { | |
265 | /// Creates a second handle to the database that holds the | |
266 | /// database fixed at a particular revision. So long as this | |
267 | /// "frozen" handle exists, any attempt to [`set`] an input will | |
268 | /// block. | |
269 | /// | |
270 | /// [`set`]: struct.QueryTable.html#method.set | |
271 | /// | |
272 | /// This is the method you are meant to use most of the time in a | |
273 | /// parallel setting where modifications may arise asynchronously | |
274 | /// (e.g., a language server). In this context, it is common to | |
275 | /// wish to "fork off" a snapshot of the database performing some | |
276 | /// series of queries in parallel and arranging the results. Using | |
277 | /// this method for that purpose ensures that those queries will | |
278 | /// see a consistent view of the database (it is also advisable | |
279 | /// for those queries to use the [`is_current_revision_canceled`] | |
280 | /// method to check for cancellation). | |
281 | /// | |
282 | /// [`is_current_revision_canceled`]: struct.Runtime.html#method.is_current_revision_canceled | |
283 | /// | |
284 | /// # Panics | |
285 | /// | |
286 | /// It is not permitted to create a snapshot from inside of a | |
287 | /// query. Attepting to do so will panic. | |
288 | /// | |
289 | /// # Deadlock warning | |
290 | /// | |
291 | /// The intended pattern for snapshots is that, once created, they | |
292 | /// are sent to another thread and used from there. As such, the | |
293 | /// `snapshot` acquires a "read lock" on the database -- | |
294 | /// therefore, so long as the `snapshot` is not dropped, any | |
295 | /// attempt to `set` a value in the database will block. If the | |
296 | /// `snapshot` is owned by the same thread that is attempting to | |
297 | /// `set`, this will cause a problem. | |
298 | /// | |
299 | /// # How to implement this | |
300 | /// | |
301 | /// Typically, this method will create a second copy of your | |
302 | /// database type (`MyDatabaseType`, in the example below), | |
303 | /// cloning over each of the fields from `self` into this new | |
304 | /// copy. For the field that stores the salsa runtime, you should | |
305 | /// use [the `Runtime::snapshot` method][rfm] to create a snapshot of the | |
306 | /// runtime. Finally, package up the result using `Snapshot::new`, | |
307 | /// which is a simple wrapper type that only gives `&self` access | |
308 | /// to the database within (thus preventing the use of methods | |
309 | /// that may mutate the inputs): | |
310 | /// | |
311 | /// [rfm]: struct.Runtime.html#method.snapshot | |
312 | /// | |
313 | /// ```rust,ignore | |
314 | /// impl ParallelDatabase for MyDatabaseType { | |
315 | /// fn snapshot(&self) -> Snapshot<Self> { | |
316 | /// Snapshot::new( | |
317 | /// MyDatabaseType { | |
318 | /// runtime: self.runtime.snapshot(self), | |
319 | /// other_field: self.other_field.clone(), | |
320 | /// } | |
321 | /// ) | |
322 | /// } | |
323 | /// } | |
324 | /// ``` | |
325 | fn snapshot(&self) -> Snapshot<Self>; | |
326 | } | |
327 | ||
328 | /// Simple wrapper struct that takes ownership of a database `DB` and | |
329 | /// only gives `&self` access to it. See [the `snapshot` method][fm] | |
330 | /// for more details. | |
331 | /// | |
332 | /// [fm]: trait.ParallelDatabase.html#method.snapshot | |
333 | #[derive(Debug)] | |
3dfed10e | 334 | pub struct Snapshot<DB: ?Sized> |
f035d41b XL |
335 | where |
336 | DB: ParallelDatabase, | |
337 | { | |
338 | db: DB, | |
339 | } | |
340 | ||
341 | impl<DB> Snapshot<DB> | |
342 | where | |
343 | DB: ParallelDatabase, | |
344 | { | |
345 | /// Creates a `Snapshot` that wraps the given database handle | |
346 | /// `db`. From this point forward, only shared references to `db` | |
347 | /// will be possible. | |
348 | pub fn new(db: DB) -> Self { | |
349 | Snapshot { db } | |
350 | } | |
351 | } | |
352 | ||
353 | impl<DB> std::ops::Deref for Snapshot<DB> | |
354 | where | |
355 | DB: ParallelDatabase, | |
356 | { | |
357 | type Target = DB; | |
358 | ||
359 | fn deref(&self) -> &DB { | |
360 | &self.db | |
361 | } | |
362 | } | |
363 | ||
3dfed10e XL |
364 | /// An integer that uniquely identifies a particular query instance within the |
365 | /// database. Used to track dependencies between queries. Fully ordered and | |
366 | /// equatable but those orderings are arbitrary, and meant to be used only for | |
367 | /// inserting into maps and the like. | |
368 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
369 | pub struct DatabaseKeyIndex { | |
370 | group_index: u16, | |
371 | query_index: u16, | |
372 | key_index: u32, | |
373 | } | |
374 | ||
375 | impl DatabaseKeyIndex { | |
376 | /// Returns the index of the query group containing this key. | |
377 | #[inline] | |
378 | pub fn group_index(self) -> u16 { | |
379 | self.group_index | |
380 | } | |
381 | ||
382 | /// Returns the index of the query within its query group. | |
383 | #[inline] | |
384 | pub fn query_index(self) -> u16 { | |
385 | self.query_index | |
386 | } | |
387 | ||
388 | /// Returns the index of this particular query key within the query. | |
389 | #[inline] | |
390 | pub fn key_index(self) -> u32 { | |
391 | self.key_index | |
392 | } | |
393 | ||
394 | /// Returns a type that gives a user-readable debug output. | |
395 | /// Use like `println!("{:?}", index.debug(db))`. | |
396 | pub fn debug<D: ?Sized>(self, db: &D) -> impl std::fmt::Debug + '_ | |
397 | where | |
398 | D: plumbing::DatabaseOps, | |
399 | { | |
400 | DatabaseKeyIndexDebug { index: self, db } | |
401 | } | |
402 | } | |
403 | ||
404 | /// Helper type for `DatabaseKeyIndex::debug` | |
405 | struct DatabaseKeyIndexDebug<'me, D: ?Sized> | |
406 | where | |
407 | D: plumbing::DatabaseOps, | |
408 | { | |
409 | index: DatabaseKeyIndex, | |
410 | db: &'me D, | |
411 | } | |
412 | ||
413 | impl<D: ?Sized> std::fmt::Debug for DatabaseKeyIndexDebug<'_, D> | |
414 | where | |
415 | D: plumbing::DatabaseOps, | |
416 | { | |
417 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
418 | self.db.fmt_index(self.index, fmt) | |
419 | } | |
420 | } | |
421 | ||
f035d41b XL |
422 | /// Trait implements by all of the "special types" associated with |
423 | /// each of your queries. | |
3dfed10e | 424 | pub trait Query: Debug + Default + Sized + 'static { |
f035d41b XL |
425 | /// Type that you you give as a parameter -- for queries with zero |
426 | /// or more than one input, this will be a tuple. | |
427 | type Key: Clone + Debug + Hash + Eq; | |
428 | ||
429 | /// What value does the query return? | |
430 | type Value: Clone + Debug; | |
431 | ||
432 | /// Internal struct storing the values for the query. | |
3dfed10e | 433 | type Storage: plumbing::QueryStorageOps<Self>; |
f035d41b XL |
434 | |
435 | /// Associate query group struct. | |
3dfed10e | 436 | type Group: plumbing::QueryGroup<DynDb = Self::DynDb, GroupStorage = Self::GroupStorage>; |
f035d41b XL |
437 | |
438 | /// Generated struct that contains storage for all queries in a group. | |
439 | type GroupStorage; | |
440 | ||
3dfed10e XL |
441 | /// Dyn version of the associated trait for this query group. |
442 | type DynDb: ?Sized + Database + HasQueryGroup<Self::Group>; | |
443 | ||
444 | /// A unique index identifying this query within the group. | |
445 | const QUERY_INDEX: u16; | |
446 | ||
447 | /// Name of the query method (e.g., `foo`) | |
448 | const QUERY_NAME: &'static str; | |
f035d41b XL |
449 | |
450 | /// Extact storage for this query from the storage for its group. | |
451 | fn query_storage(group_storage: &Self::GroupStorage) -> &Arc<Self::Storage>; | |
f035d41b XL |
452 | } |
453 | ||
454 | /// Return value from [the `query` method] on `Database`. | |
455 | /// Gives access to various less common operations on queries. | |
456 | /// | |
457 | /// [the `query` method]: trait.Database.html#method.query | |
3dfed10e | 458 | pub struct QueryTable<'me, Q> |
f035d41b | 459 | where |
3dfed10e | 460 | Q: Query + 'me, |
f035d41b | 461 | { |
3dfed10e | 462 | db: &'me Q::DynDb, |
f035d41b XL |
463 | storage: &'me Q::Storage, |
464 | } | |
465 | ||
3dfed10e | 466 | impl<'me, Q> QueryTable<'me, Q> |
f035d41b | 467 | where |
3dfed10e | 468 | Q: Query, |
f035d41b XL |
469 | { |
470 | /// Constructs a new `QueryTable`. | |
3dfed10e | 471 | pub fn new(db: &'me Q::DynDb, storage: &'me Q::Storage) -> Self { |
f035d41b XL |
472 | Self { db, storage } |
473 | } | |
474 | ||
475 | /// Execute the query on a given input. Usually it's easier to | |
476 | /// invoke the trait method directly. Note that for variadic | |
477 | /// queries (those with no inputs, or those with more than one | |
478 | /// input) the key will be a tuple. | |
479 | pub fn get(&self, key: Q::Key) -> Q::Value { | |
480 | self.try_get(key).unwrap_or_else(|err| panic!("{}", err)) | |
481 | } | |
482 | ||
3dfed10e | 483 | fn try_get(&self, key: Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> { |
f035d41b XL |
484 | self.storage.try_fetch(self.db, &key) |
485 | } | |
486 | ||
487 | /// Remove all values for this query that have not been used in | |
488 | /// the most recent revision. | |
489 | pub fn sweep(&self, strategy: SweepStrategy) | |
490 | where | |
3dfed10e | 491 | Q::Storage: plumbing::QueryStorageMassOps, |
f035d41b | 492 | { |
3dfed10e | 493 | self.storage.sweep(self.db.salsa_runtime(), strategy); |
f035d41b | 494 | } |
3dfed10e XL |
495 | /// Completely clears the storage for this query. |
496 | /// | |
497 | /// This method breaks internal invariants of salsa, so any further queries | |
498 | /// might return nonsense results. It is useful only in very specific | |
499 | /// circumstances -- for example, when one wants to observe which values | |
500 | /// dropped together with the table | |
501 | pub fn purge(&self) | |
502 | where | |
503 | Q::Storage: plumbing::QueryStorageMassOps, | |
504 | { | |
505 | self.storage.purge(); | |
506 | }} | |
f035d41b XL |
507 | |
508 | /// Return value from [the `query_mut` method] on `Database`. | |
509 | /// Gives access to the `set` method, notably, that is used to | |
510 | /// set the value of an input query. | |
511 | /// | |
512 | /// [the `query_mut` method]: trait.Database.html#method.query_mut | |
3dfed10e | 513 | pub struct QueryTableMut<'me, Q> |
f035d41b | 514 | where |
3dfed10e | 515 | Q: Query + 'me, |
f035d41b | 516 | { |
3dfed10e | 517 | db: &'me mut Q::DynDb, |
f035d41b XL |
518 | storage: Arc<Q::Storage>, |
519 | } | |
520 | ||
3dfed10e | 521 | impl<'me, Q> QueryTableMut<'me, Q> |
f035d41b | 522 | where |
3dfed10e | 523 | Q: Query, |
f035d41b XL |
524 | { |
525 | /// Constructs a new `QueryTableMut`. | |
3dfed10e | 526 | pub fn new(db: &'me mut Q::DynDb, storage: Arc<Q::Storage>) -> Self { |
f035d41b XL |
527 | Self { db, storage } |
528 | } | |
529 | ||
f035d41b XL |
530 | /// Assign a value to an "input query". Must be used outside of |
531 | /// an active query computation. | |
532 | /// | |
533 | /// If you are using `snapshot`, see the notes on blocking | |
534 | /// and cancellation on [the `query_mut` method]. | |
535 | /// | |
536 | /// [the `query_mut` method]: trait.Database.html#method.query_mut | |
537 | pub fn set(&mut self, key: Q::Key, value: Q::Value) | |
538 | where | |
3dfed10e | 539 | Q::Storage: plumbing::InputQueryStorageOps<Q>, |
f035d41b XL |
540 | { |
541 | self.set_with_durability(key, value, Durability::LOW); | |
542 | } | |
543 | ||
544 | /// Assign a value to an "input query", with the additional | |
545 | /// promise that this value will **never change**. Must be used | |
546 | /// outside of an active query computation. | |
547 | /// | |
548 | /// If you are using `snapshot`, see the notes on blocking | |
549 | /// and cancellation on [the `query_mut` method]. | |
550 | /// | |
551 | /// [the `query_mut` method]: trait.Database.html#method.query_mut | |
552 | pub fn set_with_durability(&mut self, key: Q::Key, value: Q::Value, durability: Durability) | |
553 | where | |
3dfed10e | 554 | Q::Storage: plumbing::InputQueryStorageOps<Q>, |
f035d41b | 555 | { |
3dfed10e | 556 | self.storage.set(self.db, &key, value, durability); |
f035d41b XL |
557 | } |
558 | ||
559 | /// Sets the size of LRU cache of values for this query table. | |
560 | /// | |
561 | /// That is, at most `cap` values will be preset in the table at the same | |
562 | /// time. This helps with keeping maximum memory usage under control, at the | |
563 | /// cost of potential extra recalculations of evicted values. | |
564 | /// | |
565 | /// If `cap` is zero, all values are preserved, this is the default. | |
566 | pub fn set_lru_capacity(&self, cap: usize) | |
567 | where | |
568 | Q::Storage: plumbing::LruQueryStorageOps, | |
569 | { | |
570 | self.storage.set_lru_capacity(cap); | |
571 | } | |
572 | ||
573 | /// Marks the computed value as outdated. | |
574 | /// | |
575 | /// This causes salsa to re-execute the query function on the next access to | |
576 | /// the query, even if all dependencies are up to date. | |
577 | /// | |
578 | /// This is most commonly used as part of the [on-demand input | |
579 | /// pattern](https://salsa-rs.github.io/salsa/common_patterns/on_demand_inputs.html). | |
580 | pub fn invalidate(&mut self, key: &Q::Key) | |
581 | where | |
3dfed10e | 582 | Q::Storage: plumbing::DerivedQueryStorageOps<Q>, |
f035d41b XL |
583 | { |
584 | self.storage.invalidate(self.db, key) | |
585 | } | |
586 | } | |
587 | ||
588 | /// The error returned when a query could not be resolved due to a cycle | |
589 | #[derive(Eq, PartialEq, Clone, Debug)] | |
590 | pub struct CycleError<K> { | |
591 | /// The queries that were part of the cycle | |
592 | cycle: Vec<K>, | |
593 | changed_at: Revision, | |
594 | durability: Durability, | |
595 | } | |
596 | ||
597 | impl<K> fmt::Display for CycleError<K> | |
598 | where | |
599 | K: fmt::Debug, | |
600 | { | |
601 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
602 | writeln!(f, "Internal error, cycle detected:\n")?; | |
603 | for i in &self.cycle { | |
604 | writeln!(f, "{:?}", i)?; | |
605 | } | |
606 | Ok(()) | |
607 | } | |
608 | } | |
609 | ||
610 | // Re-export the procedural macros. | |
611 | #[allow(unused_imports)] | |
612 | #[macro_use] | |
613 | extern crate salsa_macros; | |
3dfed10e | 614 | use plumbing::HasQueryGroup; |
f035d41b XL |
615 | #[doc(hidden)] |
616 | pub use salsa_macros::*; |