1 use crate::debug
::TableEntry
;
2 use crate::durability
::Durability
;
4 use crate::plumbing
::DerivedQueryStorageOps
;
5 use crate::plumbing
::LruQueryStorageOps
;
6 use crate::plumbing
::QueryFunction
;
7 use crate::plumbing
::QueryStorageMassOps
;
8 use crate::plumbing
::QueryStorageOps
;
9 use crate::runtime
::{FxIndexMap, StampedValue}
;
10 use crate::{CycleError, Database, DatabaseKeyIndex, Revision, Runtime, SweepStrategy}
;
11 use parking_lot
::RwLock
;
12 use std
::convert
::TryFrom
;
13 use std
::marker
::PhantomData
;
19 /// Memoized queries store the result plus a list of the other queries
20 /// that they invoked. This means we can avoid recomputing them when
21 /// none of those inputs have changed.
22 pub type MemoizedStorage
<Q
> = DerivedStorage
<Q
, AlwaysMemoizeValue
>;
24 /// "Dependency" queries just track their dependencies and not the
25 /// actual value (which they produce on demand). This lessens the
26 /// storage requirements.
27 pub type DependencyStorage
<Q
> = DerivedStorage
<Q
, NeverMemoizeValue
>;
29 /// Handles storage where the value is 'derived' by executing a
30 /// function (in contrast to "inputs").
31 pub struct DerivedStorage
<Q
, MP
>
34 MP
: MemoizationPolicy
<Q
>,
37 lru_list
: Lru
<Slot
<Q
, MP
>>,
38 slot_map
: RwLock
<FxIndexMap
<Q
::Key
, Arc
<Slot
<Q
, MP
>>>>,
39 policy
: PhantomData
<MP
>,
42 impl<Q
, MP
> std
::panic
::RefUnwindSafe
for DerivedStorage
<Q
, MP
>
45 MP
: MemoizationPolicy
<Q
>,
46 Q
::Key
: std
::panic
::RefUnwindSafe
,
47 Q
::Value
: std
::panic
::RefUnwindSafe
,
51 pub trait MemoizationPolicy
<Q
>: Send
+ Sync
+ '
static
55 fn should_memoize_value(key
: &Q
::Key
) -> bool
;
57 fn memoized_value_eq(old_value
: &Q
::Value
, new_value
: &Q
::Value
) -> bool
;
60 pub enum AlwaysMemoizeValue {}
61 impl<Q
> MemoizationPolicy
<Q
> for AlwaysMemoizeValue
66 fn should_memoize_value(_key
: &Q
::Key
) -> bool
{
70 fn memoized_value_eq(old_value
: &Q
::Value
, new_value
: &Q
::Value
) -> bool
{
71 old_value
== new_value
75 pub enum NeverMemoizeValue {}
76 impl<Q
> MemoizationPolicy
<Q
> for NeverMemoizeValue
80 fn should_memoize_value(_key
: &Q
::Key
) -> bool
{
84 fn memoized_value_eq(_old_value
: &Q
::Value
, _new_value
: &Q
::Value
) -> bool
{
85 panic
!("cannot reach since we never memoize")
89 impl<Q
, MP
> DerivedStorage
<Q
, MP
>
92 MP
: MemoizationPolicy
<Q
>,
94 fn slot(&self, key
: &Q
::Key
) -> Arc
<Slot
<Q
, MP
>> {
95 if let Some(v
) = self.slot_map
.read().get(key
) {
99 let mut write
= self.slot_map
.write();
100 let entry
= write
.entry(key
.clone());
101 let key_index
= u32::try_from(entry
.index()).unwrap();
102 let database_key_index
= DatabaseKeyIndex
{
103 group_index
: self.group_index
,
104 query_index
: Q
::QUERY_INDEX
,
105 key_index
: key_index
,
108 .or_insert_with(|| Arc
::new(Slot
::new(key
.clone(), database_key_index
)))
113 impl<Q
, MP
> QueryStorageOps
<Q
> for DerivedStorage
<Q
, MP
>
116 MP
: MemoizationPolicy
<Q
>,
118 fn new(group_index
: u16) -> Self {
121 slot_map
: RwLock
::new(FxIndexMap
::default()),
122 lru_list
: Default
::default(),
130 index
: DatabaseKeyIndex
,
131 fmt
: &mut std
::fmt
::Formatter
<'_
>,
132 ) -> std
::fmt
::Result
{
133 assert_eq
!(index
.group_index
, self.group_index
);
134 assert_eq
!(index
.query_index
, Q
::QUERY_INDEX
);
135 let slot_map
= self.slot_map
.read();
136 let key
= slot_map
.get_index(index
.key_index
as usize).unwrap().0;
137 write
!(fmt
, "{}({:?})", Q
::QUERY_NAME
, key
)
140 fn maybe_changed_since(
143 input
: DatabaseKeyIndex
,
146 assert_eq
!(input
.group_index
, self.group_index
);
147 assert_eq
!(input
.query_index
, Q
::QUERY_INDEX
);
151 .get_index(input
.key_index
as usize)
155 slot
.maybe_changed_since(db
, revision
)
162 ) -> Result
<Q
::Value
, CycleError
<DatabaseKeyIndex
>> {
163 let slot
= self.slot(key
);
170 if let Some(evicted
) = self.lru_list
.record_use(&slot
) {
175 .report_query_read(slot
.database_key_index(), durability
, changed_at
);
180 fn durability(&self, db
: &Q
::DynDb
, key
: &Q
::Key
) -> Durability
{
181 self.slot(key
).durability(db
)
184 fn entries
<C
>(&self, _db
: &Q
::DynDb
) -> C
186 C
: std
::iter
::FromIterator
<TableEntry
<Q
::Key
, Q
::Value
>>,
188 let slot_map
= self.slot_map
.read();
191 .filter_map(|slot
| slot
.as_table_entry())
196 impl<Q
, MP
> QueryStorageMassOps
for DerivedStorage
<Q
, MP
>
199 MP
: MemoizationPolicy
<Q
>,
201 fn sweep(&self, runtime
: &Runtime
, strategy
: SweepStrategy
) {
202 let map_read
= self.slot_map
.read();
203 let revision_now
= runtime
.current_revision();
204 for slot
in map_read
.values() {
205 slot
.sweep(revision_now
, strategy
);
209 self.lru_list
.purge();
210 *self.slot_map
.write() = Default
::default();
214 impl<Q
, MP
> LruQueryStorageOps
for DerivedStorage
<Q
, MP
>
217 MP
: MemoizationPolicy
<Q
>,
219 fn set_lru_capacity(&self, new_capacity
: usize) {
220 self.lru_list
.set_lru_capacity(new_capacity
);
224 impl<Q
, MP
> DerivedQueryStorageOps
<Q
> for DerivedStorage
<Q
, MP
>
227 MP
: MemoizationPolicy
<Q
>,
229 fn invalidate(&self, db
: &mut Q
::DynDb
, key
: &Q
::Key
) {
230 db
.salsa_runtime_mut()
231 .with_incremented_revision(&mut |_new_revision
| {
232 let map_read
= self.slot_map
.read();
234 if let Some(slot
) = map_read
.get(key
) {
235 if let Some(durability
) = slot
.invalidate() {
236 return Some(durability
);