diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 2e3a59c6c..9524e9b46 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -154,6 +154,13 @@ pub struct AccountMapEntryInner { } impl AccountMapEntryInner { + pub fn new(slot_list: SlotList, ref_count: RefCount, meta: AccountMapEntryMeta) -> Self { + Self { + slot_list: RwLock::new(slot_list), + ref_count: AtomicU64::new(ref_count), + meta, + } + } pub fn ref_count(&self) -> RefCount { self.ref_count.load(Ordering::Relaxed) } @@ -270,11 +277,11 @@ impl WriteAccountMapEntry { storage: &Arc>, ) -> AccountMapEntry { let ref_count = if account_info.is_cached() { 0 } else { 1 }; - Arc::new(AccountMapEntryInner { - ref_count: AtomicU64::new(ref_count), - slot_list: RwLock::new(vec![(slot, account_info)]), - meta: AccountMapEntryMeta::new_dirty(storage), - }) + Arc::new(AccountMapEntryInner::new( + vec![(slot, account_info)], + ref_count, + AccountMapEntryMeta::new_dirty(storage), + )) } // Try to update an item in the slot list the given `slot` If an item for the slot diff --git a/runtime/src/in_mem_accounts_index.rs b/runtime/src/in_mem_accounts_index.rs index efc9f7a13..b28380627 100644 --- a/runtime/src/in_mem_accounts_index.rs +++ b/runtime/src/in_mem_accounts_index.rs @@ -1,5 +1,6 @@ use crate::accounts_index::{ - AccountMapEntry, AccountMapEntryInner, IndexValue, SlotList, WriteAccountMapEntry, + AccountMapEntry, AccountMapEntryInner, AccountMapEntryMeta, IndexValue, RefCount, SlotList, + WriteAccountMapEntry, }; use crate::bucket_map_holder::{Age, BucketMapHolder}; use crate::bucket_map_holder_stats::BucketMapHolderStats; @@ -104,9 +105,23 @@ impl InMemAccountsIndex { keys } - pub fn get(&self, key: &K) -> Option> { + fn load_from_disk(&self, pubkey: &Pubkey) -> Option<(SlotList, RefCount)> { + self.storage + .disk + .as_ref() + .and_then(|disk| disk.read_value(pubkey)) + } + + fn load_account_entry_from_disk(&self, pubkey: &Pubkey) -> Option> { + let entry_disk = self.load_from_disk(pubkey)?; // returns None if not on disk + + Some(self.disk_to_cache_entry(entry_disk.0, entry_disk.1)) + } + + // lookup 'pubkey' in index + pub fn get(&self, pubkey: &K) -> Option> { let m = Measure::start("get"); - let result = self.map().read().unwrap().get(key).cloned(); + let result = self.map().read().unwrap().get(pubkey).map(Arc::clone); let stats = self.stats(); let (count, time) = if result.is_some() { (&stats.gets_from_mem, &stats.get_mem_us) @@ -115,7 +130,20 @@ impl InMemAccountsIndex { }; Self::update_time_stat(time, m); Self::update_stat(count, 1); - result + + if result.is_some() { + return result; + } + + // not in cache, look on disk + let new_entry = self.load_account_entry_from_disk(pubkey)?; + let mut map = self.map().write().unwrap(); + let entry = map.entry(*pubkey); + let result = match entry { + Entry::Occupied(occupied) => Arc::clone(occupied.get()), + Entry::Vacant(vacant) => Arc::clone(vacant.insert(new_entry)), + }; + Some(result) } // If the slot list for pubkey exists in the index and is empty, remove the index entry for pubkey and return true. @@ -245,6 +273,19 @@ impl InMemAccountsIndex { addref } + // convert from raw data on disk to AccountMapEntry, set to age in future + fn disk_to_cache_entry( + &self, + slot_list: SlotList, + ref_count: RefCount, + ) -> AccountMapEntry { + Arc::new(AccountMapEntryInner::new( + slot_list, + ref_count, + AccountMapEntryMeta::new_dirty(&self.storage), + )) + } + // returns true if upsert was successful. new_value is modified in this case. new_value contains a RwLock // otherwise, new_value has not been modified and the pubkey has to be added to the maps with a write lock. call upsert_new pub fn update_key_if_exists(