diff --git a/docs/environment-variables.md b/docs/environment-variables.md index a0a3cfd8cf5..f4a7411fe6d 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -287,3 +287,7 @@ those. - `GRAPH_ENABLE_SQL_QUERIES`: Enable the experimental [SQL query interface](implementation/sql-interface.md). (default: false) +- `GRAPH_STORE_DISABLE_CALL_CACHE`: Disables the store call cache entirely. Graph node will skip writing and reading from the + call cache. The buffered block call cache will still be enabled. This option may be useful + for indexers who are running their own RPC nodes. Disabling the store call cache may have + significant performance impact. (default: false) diff --git a/graph/src/env/mod.rs b/graph/src/env/mod.rs index 3fce087986e..905907e39b9 100644 --- a/graph/src/env/mod.rs +++ b/graph/src/env/mod.rs @@ -25,6 +25,7 @@ lazy_static! { lazy_static! { pub static ref TEST_WITH_NO_REORG: Mutex = Mutex::new(false); pub static ref TEST_SQL_QUERIES_ENABLED: Mutex = Mutex::new(false); + pub static ref TEST_STORE_CALL_CACHE_DISABLED: Mutex = Mutex::new(false); } /// Panics if: @@ -441,6 +442,25 @@ impl EnvVars { let mut lock = TEST_SQL_QUERIES_ENABLED.lock().unwrap(); *lock = enable; } + + #[cfg(debug_assertions)] + pub fn store_call_cache_disabled(&self) -> bool { + if *TEST_STORE_CALL_CACHE_DISABLED.lock().unwrap() { + true + } else { + self.store.disable_call_cache + } + } + + #[cfg(not(debug_assertions))] + pub fn store_call_cache_disabled(&self) -> bool { + self.store.disable_call_cache + } + + #[cfg(debug_assertions)] + pub fn set_store_call_cache_disabled_for_tests(&self, value: bool) { + *TEST_STORE_CALL_CACHE_DISABLED.lock().unwrap() = value; + } } impl Default for EnvVars { diff --git a/graph/src/env/store.rs b/graph/src/env/store.rs index e267b28d8ce..c6eb1a09427 100644 --- a/graph/src/env/store.rs +++ b/graph/src/env/store.rs @@ -149,6 +149,10 @@ pub struct EnvVarsStore { /// The number of rows to fetch from the foreign data wrapper in one go, /// this will be set as the option 'fetch_size' on all foreign servers pub fdw_fetch_size: usize, + /// Disables the store call cache entirely. Graph node will skip writing and reading from the + /// call cache. The buffered block call cache will still be enabled. + /// Set by `GRAPH_STORE_DISABLE_CALL_CACHE`. Defaults to false. + pub disable_call_cache: bool, } // This does not print any values avoid accidentally leaking any sensitive env vars @@ -206,6 +210,7 @@ impl TryFrom for EnvVarsStore { disable_block_cache_for_lookup: x.disable_block_cache_for_lookup, insert_extra_cols: x.insert_extra_cols, fdw_fetch_size: x.fdw_fetch_size, + disable_call_cache: x.disable_call_cache, }; if let Some(timeout) = vars.batch_timeout { if timeout < 2 * vars.batch_target_duration { @@ -295,6 +300,8 @@ pub struct InnerStore { insert_extra_cols: usize, #[envconfig(from = "GRAPH_STORE_FDW_FETCH_SIZE", default = "1000")] fdw_fetch_size: usize, + #[envconfig(from = "GRAPH_STORE_DISABLE_CALL_CACHE", default = "false")] + disable_call_cache: bool, } #[derive(Clone, Copy, Debug)] diff --git a/store/postgres/src/chain_store.rs b/store/postgres/src/chain_store.rs index e3ee70f378d..03cee52f0c7 100644 --- a/store/postgres/src/chain_store.rs +++ b/store/postgres/src/chain_store.rs @@ -2960,6 +2960,10 @@ impl EthereumCallCache for ChainStore { req: &call::Request, block: BlockPtr, ) -> Result, Error> { + if ENV_VARS.store_call_cache_disabled() { + return Ok(None); + } + let id = contract_call_id(req, &block); let conn = &mut *self.get_conn()?; let return_value = conn.transaction::<_, Error, _>(|conn| { @@ -3036,6 +3040,10 @@ impl EthereumCallCache for ChainStore { block: BlockPtr, return_value: call::Retval, ) -> Result<(), Error> { + if ENV_VARS.store_call_cache_disabled() { + return Ok(()); + } + let return_value = match return_value { call::Retval::Value(return_value) if !return_value.is_empty() => return_value, _ => { diff --git a/store/test-store/tests/postgres/chain_head.rs b/store/test-store/tests/postgres/chain_head.rs index acc42ad1ee7..1cf89f45ac4 100644 --- a/store/test-store/tests/postgres/chain_head.rs +++ b/store/test-store/tests/postgres/chain_head.rs @@ -505,6 +505,36 @@ fn eth_call_cache() { }) } +#[test] +fn test_disable_call_cache() { + let chain = vec![&*GENESIS_BLOCK, &*BLOCK_ONE, &*BLOCK_TWO]; + + run_test(chain, |store, _| { + ENV_VARS.set_store_call_cache_disabled_for_tests(true); + + let logger = LOGGER.cheap_clone(); + let address = H160([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5]); + let call: [u8; 6] = [1, 2, 3, 4, 5, 6]; + let return_value: [u8; 3] = [7, 8, 9]; + + let call = call::Request::new(address, call.to_vec(), 0); + + store + .set_call( + &logger, + call.cheap_clone(), + BLOCK_ONE.block_ptr(), + call::Retval::Value(Bytes::from(return_value)), + ) + .unwrap(); + + let ret = store.get_call(&call, BLOCK_ONE.block_ptr()).unwrap(); + + assert!(ret.is_none()); + Ok(()) + }); +} + #[test] /// Tests mainly query correctness. Requires data in order not to hit early returns when no stale contracts are found. fn test_clear_stale_call_cache() {