@@ -9,9 +9,10 @@ use stable_hash::prelude::*;
9
9
use stable_hash:: utils:: stable_hash;
10
10
use std:: collections:: { BTreeMap , HashMap , HashSet , VecDeque } ;
11
11
use std:: iter;
12
- use std:: sync:: atomic:: { AtomicBool , Ordering } ;
13
12
use std:: sync:: RwLock ;
14
13
use std:: time:: Instant ;
14
+ use std:: fmt;
15
+ use crossbeam:: atomic:: AtomicCell ;
15
16
16
17
use graph:: prelude:: * ;
17
18
@@ -170,6 +171,39 @@ fn cache_key(
170
171
stable_hash :: < SetHasher , _ > ( & query)
171
172
}
172
173
174
+ /// Used for checking if a response hit the cache.
175
+ #[ derive( Copy , Clone ) ]
176
+ pub ( crate ) enum CacheStatus {
177
+ /// Hit is a hit in the generational cache.
178
+ Hit ,
179
+
180
+ /// Shared is a hit in the herd cache.
181
+ Shared ,
182
+
183
+ /// Insert is a miss that inserted in the generational cache.
184
+ Insert ,
185
+
186
+ /// A miss is none of the above.
187
+ Miss ,
188
+ }
189
+
190
+ impl Default for CacheStatus {
191
+ fn default ( ) -> Self {
192
+ CacheStatus :: Miss
193
+ }
194
+ }
195
+
196
+ impl fmt:: Display for CacheStatus {
197
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
198
+ match self {
199
+ CacheStatus :: Hit => f. write_str ( "hit" ) ,
200
+ CacheStatus :: Shared => f. write_str ( "shared" ) ,
201
+ CacheStatus :: Insert => f. write_str ( "insert" ) ,
202
+ CacheStatus :: Miss => f. write_str ( "miss" )
203
+ }
204
+ }
205
+ }
206
+
173
207
/// Contextual information passed around during query execution.
174
208
pub struct ExecutionContext < R >
175
209
where
@@ -190,15 +224,8 @@ where
190
224
/// Max value for `first`.
191
225
pub max_first : u32 ,
192
226
193
- /// Will be `true` if the response was pulled from cache. The mechanism by
194
- /// which this is set is actually to start at `true` and then be set to
195
- /// `false` if the query is executed.
196
- ///
197
- /// Used for logging.
198
- pub cached : AtomicBool ,
199
-
200
- /// Set to `true` if the response was inserted in the cache. Used for logging.
201
- pub cache_insert : AtomicBool ,
227
+ /// Records whether this was a cache hit, used for logging.
228
+ pub ( crate ) cache_status : AtomicCell < CacheStatus > ,
202
229
}
203
230
204
231
// Helpers to look for types and fields on both the introspection and regular schemas.
@@ -235,8 +262,7 @@ where
235
262
query : self . query . as_introspection_query ( ) ,
236
263
deadline : self . deadline ,
237
264
max_first : std:: u32:: MAX ,
238
- cached : AtomicBool :: new ( true ) ,
239
- cache_insert : AtomicBool :: new ( false ) ,
265
+ cache_status : AtomicCell :: new ( CacheStatus :: Miss ) ,
240
266
}
241
267
}
242
268
}
@@ -246,8 +272,6 @@ pub fn execute_root_selection_set_uncached(
246
272
selection_set : & q:: SelectionSet ,
247
273
root_type : & s:: ObjectType ,
248
274
) -> QueryResponse {
249
- ctx. cached . store ( false , std:: sync:: atomic:: Ordering :: SeqCst ) ;
250
-
251
275
// Split the top-level fields into introspection fields and
252
276
// regular data fields
253
277
let mut data_set = q:: SelectionSet {
@@ -321,7 +345,8 @@ pub fn execute_root_selection_set<R: Resolver>(
321
345
// Iterate from the most recent block looking for a block that matches.
322
346
if let Some ( cache_by_block) = cache. iter ( ) . find ( |c| c. block == block_ptr) {
323
347
if let Some ( response) = cache_by_block. cache . get ( & cache_key) {
324
- return response. clone ( ) ;
348
+ ctx. cache_status . store ( CacheStatus :: Hit ) ;
349
+ return response. cheap_clone ( ) ;
325
350
}
326
351
}
327
352
@@ -330,33 +355,39 @@ pub fn execute_root_selection_set<R: Resolver>(
330
355
}
331
356
}
332
357
333
- let result = if let Some ( key) = key {
334
- QUERY_HERD_CACHE . cached_query ( key, || {
335
- Arc :: new ( QueryResult :: from ( execute_root_selection_set_uncached (
336
- ctx,
337
- selection_set,
338
- root_type,
339
- ) ) )
340
- } )
341
- } else {
358
+ let mut herd_hit = true ;
359
+ let mut run_query = || {
360
+ herd_hit = false ;
342
361
Arc :: new ( QueryResult :: from ( execute_root_selection_set_uncached (
343
362
ctx,
344
363
selection_set,
345
364
root_type,
346
365
) ) )
347
366
} ;
367
+ let result = if let Some ( key) = key {
368
+ QUERY_HERD_CACHE . cached_query ( key, run_query)
369
+ } else {
370
+ run_query ( )
371
+ } ;
372
+ if herd_hit {
373
+ ctx. cache_status . store ( CacheStatus :: Shared ) ;
374
+ }
348
375
349
376
// Check if this query should be cached.
350
377
// Share errors from the herd cache, but don't store them in generational cache.
351
378
// In particular, there is a problem where asking for a block pointer beyond the chain
352
379
// head can cause the legitimate cache to be thrown out.
353
- if let ( false , Some ( key) , Some ( block_ptr) ) = ( result. has_errors ( ) , key, block_ptr) {
380
+ // It would be redundant to insert herd cache hits.
381
+ let no_cache = herd_hit || result. has_errors ( ) ;
382
+ if let ( false , Some ( key) , Some ( block_ptr) ) = ( no_cache, key, block_ptr) {
354
383
let mut cache = QUERY_CACHE . write ( ) . unwrap ( ) ;
355
384
356
385
// If there is already a cache by the block of this query, just add it there.
357
386
if let Some ( cache_by_block) = cache. iter_mut ( ) . find ( |c| c. block == block_ptr) {
358
387
let cache_insert = cache_by_block. insert ( key, result. cheap_clone ( ) ) ;
359
- ctx. cache_insert . store ( cache_insert, Ordering :: SeqCst ) ;
388
+ if cache_insert {
389
+ ctx. cache_status . store ( CacheStatus :: Insert ) ;
390
+ }
360
391
} else if * QUERY_CACHE_BLOCKS > 0 {
361
392
// We're creating a new `CacheByBlock` if:
362
393
// - There are none yet, this is the first query being cached, or
@@ -378,7 +409,9 @@ pub fn execute_root_selection_set<R: Resolver>(
378
409
let max_weight = * QUERY_CACHE_MAX_MEM / * QUERY_CACHE_BLOCKS ;
379
410
let mut cache_by_block = CacheByBlock :: new ( block_ptr, max_weight) ;
380
411
let cache_insert = cache_by_block. insert ( key, result. cheap_clone ( ) ) ;
381
- ctx. cache_insert . store ( cache_insert, Ordering :: SeqCst ) ;
412
+ if cache_insert {
413
+ ctx. cache_status . store ( CacheStatus :: Insert ) ;
414
+ }
382
415
cache. push_front ( cache_by_block) ;
383
416
}
384
417
}
0 commit comments