]> git.proxmox.com Git - rustc.git/blame - vendor/salsa/src/lib.rs
New upstream version 1.48.0+dfsg1
[rustc.git] / vendor / salsa / src / lib.rs
CommitLineData
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 10mod blocking_future;
f035d41b
XL
11mod derived;
12mod doctest;
13mod durability;
14mod input;
15mod intern_id;
16mod interned;
17mod lru;
18mod revision;
19mod runtime;
3dfed10e 20mod storage;
f035d41b
XL
21
22pub mod debug;
23/// Items in this module are public for implementation reasons,
24/// and are exempt from the SemVer guarantees.
25#[doc(hidden)]
26pub mod plumbing;
27
28use crate::plumbing::DerivedQueryStorageOps;
29use crate::plumbing::InputQueryStorageOps;
30use crate::plumbing::LruQueryStorageOps;
31use crate::plumbing::QueryStorageMassOps;
32use crate::plumbing::QueryStorageOps;
3dfed10e 33pub use crate::revision::Revision;
f035d41b
XL
34use std::fmt::{self, Debug};
35use std::hash::Hash;
36use std::sync::Arc;
37
38pub use crate::durability::Durability;
39pub use crate::intern_id::InternId;
40pub use crate::interned::InternKey;
41pub use crate::runtime::Runtime;
42pub use crate::runtime::RuntimeId;
3dfed10e 43pub 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 48pub 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 93pub 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 102impl 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 112pub 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 149impl 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)]
173enum DiscardIf {
174 Never,
175 Outdated,
176 Always,
177}
178
179impl Default for DiscardIf {
180 fn default() -> DiscardIf {
181 DiscardIf::Never
182 }
183}
184
185#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
186enum DiscardWhat {
187 Nothing,
188 Values,
189 Everything,
190}
191
192impl 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)]
203pub struct SweepStrategy {
204 discard_if: DiscardIf,
205 discard_what: DiscardWhat,
3dfed10e 206 shrink_to_fit: bool,
f035d41b
XL
207}
208
209impl 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.
264pub 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 334pub struct Snapshot<DB: ?Sized>
f035d41b
XL
335where
336 DB: ParallelDatabase,
337{
338 db: DB,
339}
340
341impl<DB> Snapshot<DB>
342where
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
353impl<DB> std::ops::Deref for Snapshot<DB>
354where
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)]
369pub struct DatabaseKeyIndex {
370 group_index: u16,
371 query_index: u16,
372 key_index: u32,
373}
374
375impl 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`
405struct DatabaseKeyIndexDebug<'me, D: ?Sized>
406where
407 D: plumbing::DatabaseOps,
408{
409 index: DatabaseKeyIndex,
410 db: &'me D,
411}
412
413impl<D: ?Sized> std::fmt::Debug for DatabaseKeyIndexDebug<'_, D>
414where
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 424pub 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 458pub struct QueryTable<'me, Q>
f035d41b 459where
3dfed10e 460 Q: Query + 'me,
f035d41b 461{
3dfed10e 462 db: &'me Q::DynDb,
f035d41b
XL
463 storage: &'me Q::Storage,
464}
465
3dfed10e 466impl<'me, Q> QueryTable<'me, Q>
f035d41b 467where
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 513pub struct QueryTableMut<'me, Q>
f035d41b 514where
3dfed10e 515 Q: Query + 'me,
f035d41b 516{
3dfed10e 517 db: &'me mut Q::DynDb,
f035d41b
XL
518 storage: Arc<Q::Storage>,
519}
520
3dfed10e 521impl<'me, Q> QueryTableMut<'me, Q>
f035d41b 522where
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)]
590pub 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
597impl<K> fmt::Display for CycleError<K>
598where
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]
613extern crate salsa_macros;
3dfed10e 614use plumbing::HasQueryGroup;
f035d41b
XL
615#[doc(hidden)]
616pub use salsa_macros::*;