@@ -15,6 +15,7 @@ use crate::{DatabaseKeyIndex, QueryDb};
1515use indexmap:: map:: Entry ;
1616use parking_lot:: RwLock ;
1717use std:: convert:: TryFrom ;
18+ use std:: iter;
1819use tracing:: debug;
1920
2021/// Input queries store the result plus a list of the other queries
@@ -25,15 +26,12 @@ where
2526 Q : Query ,
2627{
2728 group_index : u16 ,
28- slots : RwLock < FxIndexMap < Q :: Key , Slot < Q > > > ,
29+ slots : RwLock < FxIndexMap < Q :: Key , Slot < Q :: Value > > > ,
2930}
3031
31- struct Slot < Q >
32- where
33- Q : Query ,
34- {
32+ struct Slot < V > {
3533 database_key_index : DatabaseKeyIndex ,
36- stamped_value : RwLock < StampedValue < Q :: Value > > ,
34+ stamped_value : RwLock < StampedValue < V > > ,
3735}
3836
3937impl < Q > std:: panic:: RefUnwindSafe for InputStorage < Q >
7876 debug_assert ! ( revision < db. salsa_runtime( ) . current_revision( ) ) ;
7977 let slots = & self . slots . read ( ) ;
8078 let slot = slots. get_index ( input. key_index as usize ) . unwrap ( ) . 1 ;
81- slot. maybe_changed_after ( db, revision)
79+
80+ debug ! ( "maybe_changed_after(slot={:?}, revision={:?})" , Q :: default ( ) , revision, ) ;
81+
82+ let changed_at = slot. stamped_value . read ( ) . changed_at ;
83+
84+ debug ! ( "maybe_changed_after: changed_at = {:?}" , changed_at) ;
85+
86+ changed_at > revision
8287 }
8388
8489 fn fetch ( & self , db : & <Q as QueryDb < ' _ > >:: DynDb , key : & Q :: Key ) -> Q :: Value {
@@ -121,21 +126,6 @@ where
121126 }
122127}
123128
124- impl < Q > Slot < Q >
125- where
126- Q : Query ,
127- {
128- fn maybe_changed_after ( & self , _db : & <Q as QueryDb < ' _ > >:: DynDb , revision : Revision ) -> bool {
129- debug ! ( "maybe_changed_after(slot={:?}, revision={:?})" , self , revision, ) ;
130-
131- let changed_at = self . stamped_value . read ( ) . changed_at ;
132-
133- debug ! ( "maybe_changed_after: changed_at = {:?}" , changed_at) ;
134-
135- changed_at > revision
136- }
137- }
138-
139129impl < Q > QueryStorageMassOps for InputStorage < Q >
140130where
141131 Q : Query ,
@@ -202,6 +192,167 @@ where
202192 }
203193}
204194
195+ /// Same as `InputStorage`, but optimized for queries that take no inputs.
196+ pub struct UnitInputStorage < Q >
197+ where
198+ Q : Query < Key = ( ) > ,
199+ {
200+ group_index : u16 ,
201+ slot : UnitSlot < Q :: Value > ,
202+ }
203+
204+ struct UnitSlot < V > {
205+ database_key_index : DatabaseKeyIndex ,
206+ stamped_value : RwLock < Option < StampedValue < V > > > ,
207+ }
208+
209+ impl < Q > std:: panic:: RefUnwindSafe for UnitInputStorage < Q >
210+ where
211+ Q : Query < Key = ( ) > ,
212+ Q :: Key : std:: panic:: RefUnwindSafe ,
213+ Q :: Value : std:: panic:: RefUnwindSafe ,
214+ {
215+ }
216+
217+ impl < Q > QueryStorageOps < Q > for UnitInputStorage < Q >
218+ where
219+ Q : Query < Key = ( ) > ,
220+ {
221+ const CYCLE_STRATEGY : crate :: plumbing:: CycleRecoveryStrategy = CycleRecoveryStrategy :: Panic ;
222+
223+ fn new ( group_index : u16 ) -> Self {
224+ let database_key_index =
225+ DatabaseKeyIndex { group_index, query_index : Q :: QUERY_INDEX , key_index : 0 } ;
226+ UnitInputStorage {
227+ group_index,
228+ slot : UnitSlot { database_key_index, stamped_value : RwLock :: new ( None ) } ,
229+ }
230+ }
231+
232+ fn fmt_index (
233+ & self ,
234+ _db : & <Q as QueryDb < ' _ > >:: DynDb ,
235+ index : DatabaseKeyIndex ,
236+ fmt : & mut std:: fmt:: Formatter < ' _ > ,
237+ ) -> std:: fmt:: Result {
238+ assert_eq ! ( index. group_index, self . group_index) ;
239+ assert_eq ! ( index. query_index, Q :: QUERY_INDEX ) ;
240+ write ! ( fmt, "{}" , Q :: QUERY_NAME )
241+ }
242+
243+ fn maybe_changed_after (
244+ & self ,
245+ db : & <Q as QueryDb < ' _ > >:: DynDb ,
246+ input : DatabaseKeyIndex ,
247+ revision : Revision ,
248+ ) -> bool {
249+ assert_eq ! ( input. group_index, self . group_index) ;
250+ assert_eq ! ( input. query_index, Q :: QUERY_INDEX ) ;
251+ debug_assert ! ( revision < db. salsa_runtime( ) . current_revision( ) ) ;
252+
253+ debug ! ( "maybe_changed_after(slot={:?}, revision={:?})" , Q :: default ( ) , revision, ) ;
254+
255+ let changed_at = self . slot . stamped_value . read ( ) . as_ref ( ) . unwrap ( ) . changed_at ;
256+
257+ debug ! ( "maybe_changed_after: changed_at = {:?}" , changed_at) ;
258+
259+ changed_at > revision
260+ }
261+
262+ fn fetch ( & self , db : & <Q as QueryDb < ' _ > >:: DynDb , & ( ) : & Q :: Key ) -> Q :: Value {
263+ db. unwind_if_cancelled ( ) ;
264+
265+ let StampedValue { value, durability, changed_at } = self
266+ . slot
267+ . stamped_value
268+ . read ( )
269+ . clone ( )
270+ . unwrap_or_else ( || panic ! ( "no value set for {:?}" , Q :: default ( ) ) ) ;
271+
272+ db. salsa_runtime ( ) . report_query_read_and_unwind_if_cycle_resulted (
273+ self . slot . database_key_index ,
274+ durability,
275+ changed_at,
276+ ) ;
277+
278+ value
279+ }
280+
281+ fn durability ( & self , _db : & <Q as QueryDb < ' _ > >:: DynDb , & ( ) : & Q :: Key ) -> Durability {
282+ match & * self . slot . stamped_value . read ( ) {
283+ Some ( stamped_value) => stamped_value. durability ,
284+ None => panic ! ( "no value set for {:?}" , Q :: default ( ) , ) ,
285+ }
286+ }
287+
288+ fn entries < C > ( & self , _db : & <Q as QueryDb < ' _ > >:: DynDb ) -> C
289+ where
290+ C : std:: iter:: FromIterator < TableEntry < Q :: Key , Q :: Value > > ,
291+ {
292+ iter:: once ( TableEntry :: new (
293+ ( ) ,
294+ self . slot . stamped_value . read ( ) . as_ref ( ) . map ( |it| it. value . clone ( ) ) ,
295+ ) )
296+ . collect ( )
297+ }
298+ }
299+
300+ impl < Q > QueryStorageMassOps for UnitInputStorage < Q >
301+ where
302+ Q : Query < Key = ( ) > ,
303+ {
304+ fn purge ( & self ) {
305+ * self . slot . stamped_value . write ( ) = Default :: default ( ) ;
306+ }
307+ }
308+
309+ impl < Q > InputQueryStorageOps < Q > for UnitInputStorage < Q >
310+ where
311+ Q : Query < Key = ( ) > ,
312+ {
313+ fn set ( & self , runtime : & mut Runtime , ( ) : & Q :: Key , value : Q :: Value , durability : Durability ) {
314+ tracing:: debug!( "{:?} = {:?} ({:?})" , Q :: default ( ) , value, durability) ;
315+
316+ // The value is changing, so we need a new revision (*). We also
317+ // need to update the 'last changed' revision by invoking
318+ // `guard.mark_durability_as_changed`.
319+ //
320+ // CAREFUL: This will block until the global revision lock can
321+ // be acquired. If there are still queries executing, they may
322+ // need to read from this input. Therefore, we wait to acquire
323+ // the lock on `map` until we also hold the global query write
324+ // lock.
325+ //
326+ // (*) Technically, since you can't presently access an input
327+ // for a non-existent key, and you can't enumerate the set of
328+ // keys, we only need a new revision if the key used to
329+ // exist. But we may add such methods in the future and this
330+ // case doesn't generally seem worth optimizing for.
331+ runtime. with_incremented_revision ( |next_revision| {
332+ let mut stamped_value_slot = self . slot . stamped_value . write ( ) ;
333+
334+ // Do this *after* we acquire the lock, so that we are not
335+ // racing with somebody else to modify this same cell.
336+ // (Otherwise, someone else might write a *newer* revision
337+ // into the same cell while we block on the lock.)
338+ let stamped_value = StampedValue { value, durability, changed_at : next_revision } ;
339+
340+ match & mut * stamped_value_slot {
341+ Some ( slot_stamped_value) => {
342+ let old_durability = slot_stamped_value. durability ;
343+ * slot_stamped_value = stamped_value;
344+ Some ( old_durability)
345+ }
346+
347+ stamped_value_slot @ None => {
348+ * stamped_value_slot = Some ( stamped_value) ;
349+ None
350+ }
351+ }
352+ } ) ;
353+ }
354+ }
355+
205356/// Check that `Slot<Q, MP>: Send + Sync` as long as
206357/// `DB::DatabaseData: Send + Sync`, which in turn implies that
207358/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
@@ -213,7 +364,8 @@ where
213364 Q :: Value : Send + Sync ,
214365{
215366 fn is_send_sync < T : Send + Sync > ( ) { }
216- is_send_sync :: < Slot < Q > > ( ) ;
367+ is_send_sync :: < Slot < Q :: Value > > ( ) ;
368+ is_send_sync :: < UnitSlot < Q :: Value > > ( ) ;
217369}
218370
219371/// Check that `Slot<Q, MP>: 'static` as long as
@@ -227,14 +379,6 @@ where
227379 Q :: Value : ' static ,
228380{
229381 fn is_static < T : ' static > ( ) { }
230- is_static :: < Slot < Q > > ( ) ;
231- }
232-
233- impl < Q > std:: fmt:: Debug for Slot < Q >
234- where
235- Q : Query ,
236- {
237- fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
238- write ! ( fmt, "{:?}" , Q :: default ( ) )
239- }
382+ is_static :: < Slot < Q :: Value > > ( ) ;
383+ is_static :: < UnitSlot < Q :: Value > > ( ) ;
240384}
0 commit comments