@@ -15,6 +15,7 @@ use crate::{DatabaseKeyIndex, QueryDb};
15
15
use indexmap:: map:: Entry ;
16
16
use parking_lot:: RwLock ;
17
17
use std:: convert:: TryFrom ;
18
+ use std:: iter;
18
19
use tracing:: debug;
19
20
20
21
/// Input queries store the result plus a list of the other queries
@@ -25,15 +26,12 @@ where
25
26
Q : Query ,
26
27
{
27
28
group_index : u16 ,
28
- slots : RwLock < FxIndexMap < Q :: Key , Slot < Q > > > ,
29
+ slots : RwLock < FxIndexMap < Q :: Key , Slot < Q :: Value > > > ,
29
30
}
30
31
31
- struct Slot < Q >
32
- where
33
- Q : Query ,
34
- {
32
+ struct Slot < V > {
35
33
database_key_index : DatabaseKeyIndex ,
36
- stamped_value : RwLock < StampedValue < Q :: Value > > ,
34
+ stamped_value : RwLock < StampedValue < V > > ,
37
35
}
38
36
39
37
impl < Q > std:: panic:: RefUnwindSafe for InputStorage < Q >
78
76
debug_assert ! ( revision < db. salsa_runtime( ) . current_revision( ) ) ;
79
77
let slots = & self . slots . read ( ) ;
80
78
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
82
87
}
83
88
84
89
fn fetch ( & self , db : & <Q as QueryDb < ' _ > >:: DynDb , key : & Q :: Key ) -> Q :: Value {
@@ -121,21 +126,6 @@ where
121
126
}
122
127
}
123
128
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
-
139
129
impl < Q > QueryStorageMassOps for InputStorage < Q >
140
130
where
141
131
Q : Query ,
@@ -202,6 +192,167 @@ where
202
192
}
203
193
}
204
194
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
+
205
356
/// Check that `Slot<Q, MP>: Send + Sync` as long as
206
357
/// `DB::DatabaseData: Send + Sync`, which in turn implies that
207
358
/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
@@ -213,7 +364,8 @@ where
213
364
Q :: Value : Send + Sync ,
214
365
{
215
366
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 > > ( ) ;
217
369
}
218
370
219
371
/// Check that `Slot<Q, MP>: 'static` as long as
@@ -227,14 +379,6 @@ where
227
379
Q :: Value : ' static ,
228
380
{
229
381
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 > > ( ) ;
240
384
}
0 commit comments