diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 1ba6b6d5a1320d..8b57a6076c4cce 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -53,63 +53,61 @@ pub type Ancestors = HashMap; pub type RefCount = u64; pub type AccountMap = BTreeMap; -#[derive(Clone, Debug)] -pub struct AccountMapEntry { - ref_count: Arc, - pub slot_list: Arc>>, +type AccountMapEntry = Arc>; + +#[derive(Debug)] +pub struct AccountMapEntryInner { + ref_count: AtomicU64, + pub slot_list: RwLock>, } +#[self_referencing] pub struct ReadAccountMapEntry { - ref_count: Arc, - slot_list: OwningReadGuard>, + pub owned_entry: Arc>, + #[borrows(owned_entry)] + pub slot_list_guard: RwLockReadGuard<'this, SlotList>, } impl ReadAccountMapEntry { pub fn from_account_map_entry(account_map_entry: AccountMapEntry) -> Self { - let slot_list = OwningReadGuardBuilder { - lock: account_map_entry.slot_list, - guard_builder: |lock| lock.read().unwrap(), - } - .build(); - Self { - ref_count: account_map_entry.ref_count, - slot_list, + ReadAccountMapEntryBuilder { + owned_entry: Arc::new(account_map_entry), + slot_list_guard_builder: |lock| lock.slot_list.read().unwrap(), } + .build() } pub fn slot_list(&self) -> &SlotList { - &*self.slot_list + &*self.slot_list_guard } - pub fn ref_count(&self) -> u64 { - self.ref_count.load(Ordering::Relaxed) + pub fn ref_count(&self) -> &AtomicU64 { + &self.owned_entry.ref_count } } +#[self_referencing] pub struct WriteAccountMapEntry { - ref_count: Arc, - slot_list: OwningWriteGuard>, + pub owned_entry: Arc>, + #[borrows(owned_entry)] + pub slot_list_guard: RwLockWriteGuard<'this, SlotList>, } impl WriteAccountMapEntry { pub fn from_account_map_entry(account_map_entry: AccountMapEntry) -> Self { - let slot_list = OwningWriteGuardBuilder { - lock: account_map_entry.slot_list, - guard_builder: |lock| lock.write().unwrap(), - } - .build(); - Self { - ref_count: account_map_entry.ref_count, - slot_list, + WriteAccountMapEntryBuilder { + owned_entry: Arc::new(account_map_entry), + slot_list_guard_builder: |lock| lock.slot_list.write().unwrap(), } + .build() } - pub fn slot_list(&self) -> &SlotList { - &*self.slot_list + pub fn slot_list_mut(&mut self) -> &mut SlotList { + &mut *self.slot_list_guard } - pub fn ref_count(&self) -> u64 { - self.ref_count.load(Ordering::Relaxed) + pub fn ref_count(&self) -> &AtomicU64 { + &self.owned_entry.ref_count } // Try to update an item in account_maps. If the account is not @@ -119,7 +117,7 @@ impl WriteAccountMapEntry { pub fn update(&mut self, slot: Slot, account_info: T, reclaims: &mut SlotList) { // filter out other dirty entries from the same slot let mut same_slot_previous_updates: Vec<(usize, (Slot, &T))> = self - .slot_list + .slot_list_mut() .iter() .enumerate() .filter_map(|(i, (s, value))| { @@ -134,12 +132,12 @@ impl WriteAccountMapEntry { if let Some((list_index, (s, previous_update_value))) = same_slot_previous_updates.pop() { reclaims.push((s, previous_update_value.clone())); - self.slot_list.remove(list_index); + self.slot_list_mut().remove(list_index); } else { // Only increment ref count if the account was not prevously updated in this slot - self.ref_count.fetch_add(1, Ordering::Relaxed); + self.ref_count().fetch_add(1, Ordering::Relaxed); } - self.slot_list.push((slot, account_info)); + self.slot_list_mut().push((slot, account_info)); } } @@ -268,10 +266,10 @@ impl AccountsIndex { let mut w_account_entry = self.get_account_write_entry(pubkey); let mut is_newly_inserted = false; if w_account_entry.is_none() { - let new_entry = AccountMapEntry { - ref_count: Arc::new(AtomicU64::new(0)), - slot_list: Arc::new(RwLock::new(SlotList::with_capacity(32))), - }; + let new_entry = Arc::new(AccountMapEntryInner { + ref_count: AtomicU64::new(0), + slot_list: RwLock::new(SlotList::with_capacity(32)), + }); let mut w_account_maps = self.account_maps.write().unwrap(); let account_entry = w_account_maps.entry(*pubkey).or_insert_with(|| { is_newly_inserted = true; @@ -330,23 +328,23 @@ impl AccountsIndex { ) -> (SlotList, RefCount) { ( self.get_rooted_entries(&locked_account_entry.slot_list()), - locked_account_entry.ref_count(), + locked_account_entry.ref_count().load(Ordering::Relaxed), ) } // filter any rooted entries and return them along with a bool that indicates // if this account has no more entries. pub fn purge(&self, pubkey: &Pubkey) -> (SlotList, bool) { - let WriteAccountMapEntry { mut slot_list, .. } = - self.get_account_write_entry(pubkey).unwrap(); + let mut write_account_map_entry = self.get_account_write_entry(pubkey).unwrap(); + let slot_list = write_account_map_entry.slot_list_mut(); let reclaims = self.get_rooted_entries(&slot_list); slot_list.retain(|(slot, _)| !self.is_root(*slot)); (reclaims, slot_list.is_empty()) } pub fn purge_exact(&self, pubkey: &Pubkey, slots: HashSet) -> (SlotList, bool) { - let WriteAccountMapEntry { mut slot_list, .. } = - self.get_account_write_entry(pubkey).unwrap(); + let mut write_account_map_entry = self.get_account_write_entry(pubkey).unwrap(); + let slot_list = write_account_map_entry.slot_list_mut(); let reclaims = slot_list .iter() .filter(|(slot, _)| slots.contains(&slot)) @@ -442,13 +440,13 @@ impl AccountsIndex { pub fn unref_from_storage(&self, pubkey: &Pubkey) { if let Some(locked_entry) = self.get_account_read_entry(pubkey) { - locked_entry.ref_count.fetch_sub(1, Ordering::Relaxed); + locked_entry.ref_count().fetch_sub(1, Ordering::Relaxed); } } pub fn ref_count_from_storage(&self, pubkey: &Pubkey) -> RefCount { if let Some(locked_entry) = self.get_account_read_entry(pubkey) { - locked_entry.ref_count.load(Ordering::Relaxed) + locked_entry.ref_count().load(Ordering::Relaxed) } else { 0 } @@ -478,9 +476,8 @@ impl AccountsIndex { reclaims: &mut SlotList, max_clean_root: Option, ) { - if let Some(locked_entry) = self.get_account_write_entry(pubkey) { - let WriteAccountMapEntry { mut slot_list, .. } = locked_entry; - self.purge_older_root_entries(&mut *slot_list, reclaims, max_clean_root); + if let Some(mut locked_entry) = self.get_account_write_entry(pubkey) { + self.purge_older_root_entries(locked_entry.slot_list_mut(), reclaims, max_clean_root); } } @@ -490,8 +487,8 @@ impl AccountsIndex { pubkey: &Pubkey, reclaims: &mut SlotList, ) { - if let Some(locked_entry) = self.get_account_write_entry(pubkey) { - let WriteAccountMapEntry { mut slot_list, .. } = locked_entry; + if let Some(mut locked_entry) = self.get_account_write_entry(pubkey) { + let slot_list = locked_entry.slot_list_mut(); slot_list.retain(|(slot, entry)| { if *slot == purge_slot { reclaims.push((*slot, entry.clone()));