diff --git a/accounts-db/src/accounts.rs b/accounts-db/src/accounts.rs index 33a57d56461c78..bfacc83b69a9e1 100644 --- a/accounts-db/src/accounts.rs +++ b/accounts-db/src/accounts.rs @@ -174,6 +174,20 @@ impl Accounts { self.load_slow(ancestors, pubkey, LoadHint::FixedMaxRoot) } + /// same as `load_with_fixed_root` except: + /// if the account is not already in the read cache, it is NOT put in the read cache on successful load + pub fn load_with_fixed_root_do_not_populate_read_cache( + &self, + ancestors: &Ancestors, + pubkey: &Pubkey, + ) -> Option<(AccountSharedData, Slot)> { + self.load_slow( + ancestors, + pubkey, + LoadHint::FixedMaxRootDoNotPopulateReadCache, + ) + } + pub fn load_without_fixed_root( &self, ancestors: &Ancestors, diff --git a/accounts-db/src/accounts_db.rs b/accounts-db/src/accounts_db.rs index 0aabae8e93ea1b..f9d40da83e9f7c 100644 --- a/accounts-db/src/accounts_db.rs +++ b/accounts-db/src/accounts_db.rs @@ -787,6 +787,8 @@ pub enum LoadHint { // account loading, while maintaining the determinism of account loading and resultant // transaction execution thereof. FixedMaxRoot, + /// same as `FixedMaxRoot`, except do not populate the read cache on load + FixedMaxRootDoNotPopulateReadCache, // Caller can't hint the above safety assumption. Generally RPC and miscellaneous // other call-site falls into this category. The likelihood of slower path is slightly // increased as well. @@ -5119,7 +5121,7 @@ impl AccountsDb { // so retry. This works because in accounts cache flush, an account is written to // storage *before* it is removed from the cache match load_hint { - LoadHint::FixedMaxRoot => { + LoadHint::FixedMaxRootDoNotPopulateReadCache | LoadHint::FixedMaxRoot => { // it's impossible for this to fail for transaction loads from // replaying/banking more than once. // This is because: @@ -5139,7 +5141,7 @@ impl AccountsDb { } LoadedAccountAccessor::Stored(None) => { match load_hint { - LoadHint::FixedMaxRoot => { + LoadHint::FixedMaxRootDoNotPopulateReadCache | LoadHint::FixedMaxRoot => { // When running replay on the validator, or banking stage on the leader, // it should be very rare that the storage entry doesn't exist if the // entry in the accounts index is the latest version of this account. @@ -5348,7 +5350,7 @@ impl AccountsDb { return None; } - if !is_cached { + if !is_cached && load_hint != LoadHint::FixedMaxRootDoNotPopulateReadCache { /* We show this store into the read-only cache for account 'A' and future loads of 'A' from the read-only cache are safe/reflect 'A''s latest state on this fork. diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c8afb7406164ae..f9a785eb9b5a57 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1823,8 +1823,13 @@ impl Bank { // from Stakes by reading the full account state from // accounts-db. Note that it is crucial that these accounts are loaded // at the right slot and match precisely with serialized Delegations. + // Note that we are disabling the read cache while we populate the stakes cache. + // The stakes accounts will not be expected to be loaded again. + // If we populate the read cache with these loads, then we'll just soon have to evict these. let stakes = Stakes::new(&fields.stakes, |pubkey| { - let (account, _slot) = bank_rc.accounts.load_with_fixed_root(&ancestors, pubkey)?; + let (account, _slot) = bank_rc + .accounts + .load_with_fixed_root_do_not_populate_read_cache(&ancestors, pubkey)?; Some(account) }) .expect(