in-mem acct idx hash map uses rwlock (#19878)

This commit is contained in:
Jeff Washington (jwash) 2021-09-14 18:01:34 -05:00 committed by GitHub
parent fc647eed19
commit 229b378ed1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 16 additions and 12 deletions

View File

@ -8,7 +8,7 @@ use solana_measure::measure::Measure;
use solana_sdk::{clock::Slot, pubkey::Pubkey}; use solana_sdk::{clock::Slot, pubkey::Pubkey};
use std::collections::{hash_map::Entry, HashMap}; use std::collections::{hash_map::Entry, HashMap};
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc; use std::sync::{Arc, RwLock};
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::RangeBounds; use std::ops::RangeBounds;
@ -18,7 +18,7 @@ type K = Pubkey;
#[derive(Debug)] #[derive(Debug)]
pub struct InMemAccountsIndex<T: IndexValue> { pub struct InMemAccountsIndex<T: IndexValue> {
// backing store // backing store
map: HashMap<Pubkey, AccountMapEntry<T>>, map: RwLock<HashMap<Pubkey, AccountMapEntry<T>>>,
storage: Arc<BucketMapHolder<T>>, storage: Arc<BucketMapHolder<T>>,
bin: usize, bin: usize,
} }
@ -26,7 +26,7 @@ pub struct InMemAccountsIndex<T: IndexValue> {
impl<T: IndexValue> InMemAccountsIndex<T> { impl<T: IndexValue> InMemAccountsIndex<T> {
pub fn new(storage: &AccountsIndexStorage<T>, bin: usize) -> Self { pub fn new(storage: &AccountsIndexStorage<T>, bin: usize) -> Self {
Self { Self {
map: HashMap::new(), map: RwLock::default(),
storage: storage.storage().clone(), storage: storage.storage().clone(),
bin, bin,
} }
@ -41,8 +41,9 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
R: RangeBounds<Pubkey> + std::fmt::Debug, R: RangeBounds<Pubkey> + std::fmt::Debug,
{ {
Self::update_stat(&self.stats().items, 1); Self::update_stat(&self.stats().items, 1);
let mut result = Vec::with_capacity(self.map.len()); let map = self.map.read().unwrap();
self.map.iter().for_each(|(k, v)| { let mut result = Vec::with_capacity(map.len());
map.iter().for_each(|(k, v)| {
if range.map(|range| range.contains(k)).unwrap_or(true) { if range.map(|range| range.contains(k)).unwrap_or(true) {
result.push((*k, v.clone())); result.push((*k, v.clone()));
} }
@ -52,12 +53,12 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
pub fn keys(&self) -> Vec<Pubkey> { pub fn keys(&self) -> Vec<Pubkey> {
Self::update_stat(&self.stats().keys, 1); Self::update_stat(&self.stats().keys, 1);
self.map.keys().cloned().collect() self.map.read().unwrap().keys().cloned().collect()
} }
pub fn get(&self, key: &K) -> Option<AccountMapEntry<T>> { pub fn get(&self, key: &K) -> Option<AccountMapEntry<T>> {
let m = Measure::start("get"); let m = Measure::start("get");
let result = self.map.get(key).cloned(); let result = self.map.read().unwrap().get(key).cloned();
let stats = self.stats(); let stats = self.stats();
let (count, time) = if result.is_some() { let (count, time) = if result.is_some() {
(&stats.gets_from_mem, &stats.get_mem_us) (&stats.gets_from_mem, &stats.get_mem_us)
@ -73,7 +74,8 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
// Return false otherwise. // Return false otherwise.
pub fn remove_if_slot_list_empty(&mut self, pubkey: Pubkey) -> bool { pub fn remove_if_slot_list_empty(&mut self, pubkey: Pubkey) -> bool {
let m = Measure::start("entry"); let m = Measure::start("entry");
let entry = self.map.entry(pubkey); let mut map = self.map.write().unwrap();
let entry = map.entry(pubkey);
let stats = &self.storage.stats; let stats = &self.storage.stats;
let (count, time) = if matches!(entry, Entry::Occupied(_)) { let (count, time) = if matches!(entry, Entry::Occupied(_)) {
(&stats.entries_from_mem, &stats.entry_mem_us) (&stats.entries_from_mem, &stats.entry_mem_us)
@ -101,7 +103,8 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
previous_slot_entry_was_cached: bool, previous_slot_entry_was_cached: bool,
) { ) {
let m = Measure::start("entry"); let m = Measure::start("entry");
let entry = self.map.entry(*pubkey); let mut map = self.map.write().unwrap();
let entry = map.entry(*pubkey);
let stats = &self.storage.stats; let stats = &self.storage.stats;
let (count, time) = if matches!(entry, Entry::Occupied(_)) { let (count, time) = if matches!(entry, Entry::Occupied(_)) {
(&stats.entries_from_mem, &stats.entry_mem_us) (&stats.entries_from_mem, &stats.entry_mem_us)
@ -194,7 +197,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
reclaims: &mut SlotList<T>, reclaims: &mut SlotList<T>,
previous_slot_entry_was_cached: bool, previous_slot_entry_was_cached: bool,
) -> bool { ) -> bool {
if let Some(current) = self.map.get(pubkey) { if let Some(current) = self.map.read().unwrap().get(pubkey) {
Self::lock_and_update_slot_list( Self::lock_and_update_slot_list(
current, current,
new_value, new_value,
@ -208,7 +211,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.map.len() self.map.read().unwrap().len()
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
@ -223,7 +226,8 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
new_entry: AccountMapEntry<T>, new_entry: AccountMapEntry<T>,
) -> Option<(WriteAccountMapEntry<T>, T, Pubkey)> { ) -> Option<(WriteAccountMapEntry<T>, T, Pubkey)> {
let m = Measure::start("entry"); let m = Measure::start("entry");
let entry = self.map.entry(pubkey); let mut map = self.map.write().unwrap();
let entry = map.entry(pubkey);
let stats = &self.storage.stats; let stats = &self.storage.stats;
let (count, time) = if matches!(entry, Entry::Occupied(_)) { let (count, time) = if matches!(entry, Entry::Occupied(_)) {
(&stats.entries_from_mem, &stats.entry_mem_us) (&stats.entries_from_mem, &stats.entry_mem_us)