Skip to content

Commit 9414602

Browse files
committed
graphql: Make the QueryCache aware of networks
1 parent 419beea commit 9414602

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

graphql/src/execution/execution.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ lazy_static! {
7171

7272
static ref CACHE_ALL: bool = CACHED_SUBGRAPH_IDS.contains(&"*".to_string());
7373

74-
// How many blocks should be kept in the query cache. When the limit is reached, older blocks
75-
// are evicted. This should be kept small since a lookup to the cache is O(n) on this value, and
76-
// the cache memory usage also increases with larger number. Set to 0 to disable the cache.
77-
// Defaults to 1.
74+
// How many blocks per network should be kept in the query cache. When the limit is reached,
75+
// older blocks are evicted. This should be kept small since a lookup to the cache is O(n) on
76+
// this value, and the cache memory usage also increases with larger number. Set to 0 to disable
77+
// the cache. Defaults to 1.
7878
static ref QUERY_CACHE_BLOCKS: usize = {
7979
std::env::var("GRAPH_QUERY_CACHE_BLOCKS")
8080
.unwrap_or("1".to_string())
@@ -92,8 +92,9 @@ lazy_static! {
9292
.expect("Invalid value for GRAPH_QUERY_CACHE_MAX_MEM environment variable")
9393
};
9494

95-
// This `VecDeque` works as a ring buffer with a capacity of `QUERY_CACHE_BLOCKS`.
96-
static ref QUERY_CACHE: RwLock<VecDeque<CacheByBlock>> = RwLock::new(VecDeque::new());
95+
// Query cache by network.
96+
// The `VecDeque` works as a ring buffer with a capacity of `QUERY_CACHE_BLOCKS`.
97+
static ref QUERY_CACHE: RwLock<Vec<(String, VecDeque<CacheByBlock>)>> = RwLock::new(vec![]);
9798
static ref QUERY_HERD_CACHE: QueryCache<Arc<QueryResult>> = QueryCache::new();
9899
}
99100

@@ -328,7 +329,7 @@ pub fn execute_root_selection_set<R: Resolver>(
328329
let mut key: Option<QueryHash> = None;
329330

330331
if R::CACHEABLE && (*CACHE_ALL || CACHED_SUBGRAPH_IDS.contains(&ctx.query.schema.id)) {
331-
if let Some(block_ptr) = block_ptr {
332+
if let (Some(block_ptr), Some(network)) = (block_ptr, &ctx.query.network) {
332333
// JSONB and metadata queries use `BLOCK_NUMBER_MAX`. Ignore this case for two reasons:
333334
// - Metadata queries are not cacheable.
334335
// - Caching `BLOCK_NUMBER_MAX` would make this cache think all other blocks are old.
@@ -338,15 +339,15 @@ pub fn execute_root_selection_set<R: Resolver>(
338339

339340
// Check if the response is cached.
340341
let cache = QUERY_CACHE.read().unwrap();
341-
342-
// Iterate from the most recent block looking for a block that matches.
343-
if let Some(cache_by_block) = cache.iter().find(|c| c.block == block_ptr) {
344-
if let Some(response) = cache_by_block.cache.get(&cache_key) {
345-
ctx.cache_status.store(CacheStatus::Hit);
346-
return response.cheap_clone();
342+
if let Some(cache) = cache.iter().find(|(n, _)| n == network).map(|(_, c)| c) {
343+
// Iterate from the most recent block looking for a block that matches.
344+
if let Some(cache_by_block) = cache.iter().find(|c| c.block == block_ptr) {
345+
if let Some(response) = cache_by_block.cache.get(&cache_key) {
346+
ctx.cache_status.store(CacheStatus::Hit);
347+
return response.cheap_clone();
348+
}
347349
}
348350
}
349-
350351
key = Some(cache_key);
351352
}
352353
}
@@ -376,11 +377,22 @@ pub fn execute_root_selection_set<R: Resolver>(
376377
// head can cause the legitimate cache to be thrown out.
377378
// It would be redundant to insert herd cache hits.
378379
let no_cache = herd_hit || result.has_errors();
379-
if let (false, Some(key), Some(block_ptr)) = (no_cache, key, block_ptr) {
380+
if let (false, Some(key), Some(block_ptr), Some(network)) =
381+
(no_cache, key, block_ptr, &ctx.query.network)
382+
{
380383
// Calculate the weight outside the lock.
381384
let weight = result.data.as_ref().unwrap().weight();
382385
let mut cache = QUERY_CACHE.write().unwrap();
383386

387+
// Get or insert the cache for this network.
388+
let cache = match cache.iter_mut().find(|(n, _)| n == network).map(|(_, c)| c) {
389+
Some(c) => c,
390+
None => {
391+
cache.push((network.clone(), VecDeque::new()));
392+
&mut cache.last_mut().unwrap().1
393+
}
394+
};
395+
384396
// If there is already a cache by the block of this query, just add it there.
385397
if let Some(cache_by_block) = cache.iter_mut().find(|c| c.block == block_ptr) {
386398
let cache_insert = cache_by_block.insert(key, result.cheap_clone(), weight);

graphql/src/execution/query.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub struct Query {
3838
/// The ShapeHash of the original query
3939
pub shape_hash: u64,
4040

41+
pub network: Option<String>,
42+
4143
pub(crate) fragments: HashMap<String, q::FragmentDefinition>,
4244
kind: Kind,
4345

@@ -111,6 +113,7 @@ impl Query {
111113
selection_set,
112114
shape_hash: query.shape_hash,
113115
kind,
116+
network: query.network,
114117
query_text,
115118
variables_text,
116119
complexity: 0,
@@ -165,6 +168,7 @@ impl Query {
165168
selection_set: self.selection_set.clone(),
166169
shape_hash: self.shape_hash,
167170
kind: self.kind,
171+
network: self.network.clone(),
168172
query_text: self.query_text.clone(),
169173
variables_text: self.variables_text.clone(),
170174
complexity: self.complexity,

0 commit comments

Comments
 (0)