AcctIdex: use StorageLocation (#21853)
This commit is contained in:
parent
b610e5503e
commit
ec583bd12d
|
@ -11,11 +11,45 @@ use crate::{
|
||||||
pub type Offset = usize;
|
pub type Offset = usize;
|
||||||
|
|
||||||
/// specify where account data is located
|
/// specify where account data is located
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum StorageLocation {
|
pub enum StorageLocation {
|
||||||
AppendVec(AppendVecId, Offset),
|
AppendVec(AppendVecId, Offset),
|
||||||
Cached,
|
Cached,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StorageLocation {
|
||||||
|
pub fn is_offset_equal(&self, other: &StorageLocation) -> bool {
|
||||||
|
match self {
|
||||||
|
StorageLocation::Cached => {
|
||||||
|
matches!(other, StorageLocation::Cached) // technically, 2 cached entries match in offset
|
||||||
|
}
|
||||||
|
StorageLocation::AppendVec(_, offset) => {
|
||||||
|
match other {
|
||||||
|
StorageLocation::Cached => {
|
||||||
|
false // 1 cached, 1 not
|
||||||
|
}
|
||||||
|
StorageLocation::AppendVec(_, other_offset) => other_offset == offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_store_id_equal(&self, other: &StorageLocation) -> bool {
|
||||||
|
match self {
|
||||||
|
StorageLocation::Cached => {
|
||||||
|
matches!(other, StorageLocation::Cached) // 2 cached entries are same store id
|
||||||
|
}
|
||||||
|
StorageLocation::AppendVec(store_id, _) => {
|
||||||
|
match other {
|
||||||
|
StorageLocation::Cached => {
|
||||||
|
false // 1 cached, 1 not
|
||||||
|
}
|
||||||
|
StorageLocation::AppendVec(other_store_id, _) => other_store_id == store_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Clone, Copy)]
|
#[derive(Default, Debug, PartialEq, Clone, Copy)]
|
||||||
pub struct AccountInfo {
|
pub struct AccountInfo {
|
||||||
/// index identifying the append storage
|
/// index identifying the append storage
|
||||||
|
@ -45,6 +79,12 @@ impl IsCached for AccountInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IsCached for StorageLocation {
|
||||||
|
fn is_cached(&self) -> bool {
|
||||||
|
matches!(self, StorageLocation::Cached)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AccountInfo {
|
impl AccountInfo {
|
||||||
pub fn new(storage_location: StorageLocation, mut stored_size: usize, lamports: u64) -> Self {
|
pub fn new(storage_location: StorageLocation, mut stored_size: usize, lamports: u64) -> Self {
|
||||||
let (store_id, offset) = match storage_location {
|
let (store_id, offset) = match storage_location {
|
||||||
|
@ -74,4 +114,12 @@ impl AccountInfo {
|
||||||
// elminate the special bit that indicates the info references an account with zero lamports
|
// elminate the special bit that indicates the info references an account with zero lamports
|
||||||
self.stored_size & !ZERO_LAMPORT_BIT
|
self.stored_size & !ZERO_LAMPORT_BIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn storage_location(&self) -> StorageLocation {
|
||||||
|
if self.is_cached() {
|
||||||
|
StorageLocation::Cached
|
||||||
|
} else {
|
||||||
|
StorageLocation::AppendVec(self.store_id, self.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3081,12 +3081,7 @@ impl AccountsDb {
|
||||||
bank_id,
|
bank_id,
|
||||||
|pubkey, (account_info, slot)| {
|
|pubkey, (account_info, slot)| {
|
||||||
let account_slot = self
|
let account_slot = self
|
||||||
.get_account_accessor(
|
.get_account_accessor(slot, pubkey, &account_info.storage_location())
|
||||||
slot,
|
|
||||||
pubkey,
|
|
||||||
account_info.store_id(),
|
|
||||||
account_info.offset(),
|
|
||||||
)
|
|
||||||
.get_loaded_account()
|
.get_loaded_account()
|
||||||
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot));
|
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot));
|
||||||
scan_func(&mut collector, account_slot)
|
scan_func(&mut collector, account_slot)
|
||||||
|
@ -3114,12 +3109,7 @@ impl AccountsDb {
|
||||||
ancestors,
|
ancestors,
|
||||||
|pubkey, (account_info, slot)| {
|
|pubkey, (account_info, slot)| {
|
||||||
if let Some(loaded_account) = self
|
if let Some(loaded_account) = self
|
||||||
.get_account_accessor(
|
.get_account_accessor(slot, pubkey, &account_info.storage_location())
|
||||||
slot,
|
|
||||||
pubkey,
|
|
||||||
account_info.store_id(),
|
|
||||||
account_info.offset(),
|
|
||||||
)
|
|
||||||
.get_loaded_account()
|
.get_loaded_account()
|
||||||
{
|
{
|
||||||
scan_func(&mut collector, (pubkey, loaded_account, slot));
|
scan_func(&mut collector, (pubkey, loaded_account, slot));
|
||||||
|
@ -3160,12 +3150,7 @@ impl AccountsDb {
|
||||||
// changes to the index entry.
|
// changes to the index entry.
|
||||||
// For details, see the comment in retry_to_get_account_accessor()
|
// For details, see the comment in retry_to_get_account_accessor()
|
||||||
let account_slot = self
|
let account_slot = self
|
||||||
.get_account_accessor(
|
.get_account_accessor(slot, pubkey, &account_info.storage_location())
|
||||||
slot,
|
|
||||||
pubkey,
|
|
||||||
account_info.store_id(),
|
|
||||||
account_info.offset(),
|
|
||||||
)
|
|
||||||
.get_loaded_account()
|
.get_loaded_account()
|
||||||
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot))
|
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -3206,12 +3191,7 @@ impl AccountsDb {
|
||||||
index_key,
|
index_key,
|
||||||
|pubkey, (account_info, slot)| {
|
|pubkey, (account_info, slot)| {
|
||||||
let account_slot = self
|
let account_slot = self
|
||||||
.get_account_accessor(
|
.get_account_accessor(slot, pubkey, &account_info.storage_location())
|
||||||
slot,
|
|
||||||
pubkey,
|
|
||||||
account_info.store_id(),
|
|
||||||
account_info.offset(),
|
|
||||||
)
|
|
||||||
.get_loaded_account()
|
.get_loaded_account()
|
||||||
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot));
|
.map(|loaded_account| (pubkey, loaded_account.take_account(), slot));
|
||||||
scan_func(&mut collector, account_slot)
|
scan_func(&mut collector, account_slot)
|
||||||
|
@ -3328,7 +3308,7 @@ impl AccountsDb {
|
||||||
pubkey: &'a Pubkey,
|
pubkey: &'a Pubkey,
|
||||||
max_root: Option<Slot>,
|
max_root: Option<Slot>,
|
||||||
clone_in_lock: bool,
|
clone_in_lock: bool,
|
||||||
) -> Option<(Slot, AppendVecId, usize, Option<LoadedAccountAccessor<'a>>)> {
|
) -> Option<(Slot, StorageLocation, Option<LoadedAccountAccessor<'a>>)> {
|
||||||
let (lock, index) = match self.accounts_index.get(pubkey, Some(ancestors), max_root) {
|
let (lock, index) = match self.accounts_index.get(pubkey, Some(ancestors), max_root) {
|
||||||
AccountIndexGetResult::Found(lock, index) => (lock, index),
|
AccountIndexGetResult::Found(lock, index) => (lock, index),
|
||||||
// we bail out pretty early for missing.
|
// we bail out pretty early for missing.
|
||||||
|
@ -3339,8 +3319,7 @@ impl AccountsDb {
|
||||||
|
|
||||||
let slot_list = lock.slot_list();
|
let slot_list = lock.slot_list();
|
||||||
let (slot, info) = slot_list[index];
|
let (slot, info) = slot_list[index];
|
||||||
let store_id = info.store_id();
|
let storage_location = info.storage_location();
|
||||||
let offset = info.offset();
|
|
||||||
let some_from_slow_path = if clone_in_lock {
|
let some_from_slow_path = if clone_in_lock {
|
||||||
// the fast path must have failed.... so take the slower approach
|
// the fast path must have failed.... so take the slower approach
|
||||||
// of copying potentially large Account::data inside the lock.
|
// of copying potentially large Account::data inside the lock.
|
||||||
|
@ -3348,12 +3327,12 @@ impl AccountsDb {
|
||||||
// calling check_and_get_loaded_account is safe as long as we're guaranteed to hold
|
// calling check_and_get_loaded_account is safe as long as we're guaranteed to hold
|
||||||
// the lock during the time and there should be no purge thanks to alive ancestors
|
// the lock during the time and there should be no purge thanks to alive ancestors
|
||||||
// held by our caller.
|
// held by our caller.
|
||||||
Some(self.get_account_accessor(slot, pubkey, store_id, offset))
|
Some(self.get_account_accessor(slot, pubkey, &storage_location))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((slot, store_id, offset, some_from_slow_path))
|
Some((slot, storage_location, some_from_slow_path))
|
||||||
// `lock` is dropped here rather pretty quickly with clone_in_lock = false,
|
// `lock` is dropped here rather pretty quickly with clone_in_lock = false,
|
||||||
// so the entry could be raced for mutation by other subsystems,
|
// so the entry could be raced for mutation by other subsystems,
|
||||||
// before we actually provision an account data for caller's use from now on.
|
// before we actually provision an account data for caller's use from now on.
|
||||||
|
@ -3365,8 +3344,7 @@ impl AccountsDb {
|
||||||
fn retry_to_get_account_accessor<'a>(
|
fn retry_to_get_account_accessor<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
mut slot: Slot,
|
mut slot: Slot,
|
||||||
mut store_id: AppendVecId,
|
mut storage_location: StorageLocation,
|
||||||
mut offset: usize,
|
|
||||||
ancestors: &'a Ancestors,
|
ancestors: &'a Ancestors,
|
||||||
pubkey: &'a Pubkey,
|
pubkey: &'a Pubkey,
|
||||||
max_root: Option<Slot>,
|
max_root: Option<Slot>,
|
||||||
|
@ -3484,7 +3462,7 @@ impl AccountsDb {
|
||||||
// Failsafe for potential race conditions with other subsystems
|
// Failsafe for potential race conditions with other subsystems
|
||||||
let mut num_acceptable_failed_iterations = 0;
|
let mut num_acceptable_failed_iterations = 0;
|
||||||
loop {
|
loop {
|
||||||
let account_accessor = self.get_account_accessor(slot, pubkey, store_id, offset);
|
let account_accessor = self.get_account_accessor(slot, pubkey, &storage_location);
|
||||||
match account_accessor {
|
match account_accessor {
|
||||||
LoadedAccountAccessor::Cached(Some(_)) | LoadedAccountAccessor::Stored(Some(_)) => {
|
LoadedAccountAccessor::Cached(Some(_)) | LoadedAccountAccessor::Stored(Some(_)) => {
|
||||||
// Great! There was no race, just return :) This is the most usual situation
|
// Great! There was no race, just return :) This is the most usual situation
|
||||||
|
@ -3571,8 +3549,8 @@ impl AccountsDb {
|
||||||
// accounts/purge_slots
|
// accounts/purge_slots
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"do_load() failed to get key: {} from storage, latest attempt was for \
|
"do_load() failed to get key: {} from storage, latest attempt was for \
|
||||||
slot: {}, storage_entry: {} offset: {}, load_hint: {:?}",
|
slot: {}, storage_location: {:?}, load_hint: {:?}",
|
||||||
pubkey, slot, store_id, offset, load_hint,
|
pubkey, slot, storage_location, load_hint,
|
||||||
);
|
);
|
||||||
datapoint_warn!("accounts_db-do_load_warn", ("warn", message, String));
|
datapoint_warn!("accounts_db-do_load_warn", ("warn", message, String));
|
||||||
true
|
true
|
||||||
|
@ -3581,7 +3559,7 @@ impl AccountsDb {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Because reading from the cache/storage failed, retry from the index read
|
// Because reading from the cache/storage failed, retry from the index read
|
||||||
let (new_slot, new_store_id, new_offset, maybe_account_accessor) = self
|
let (new_slot, new_storage_location, maybe_account_accessor) = self
|
||||||
.read_index_for_accessor_or_load_slow(
|
.read_index_for_accessor_or_load_slow(
|
||||||
ancestors,
|
ancestors,
|
||||||
pubkey,
|
pubkey,
|
||||||
|
@ -3590,16 +3568,16 @@ impl AccountsDb {
|
||||||
)?;
|
)?;
|
||||||
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
||||||
|
|
||||||
if new_slot == slot && new_store_id == store_id {
|
if new_slot == slot && new_storage_location.is_store_id_equal(&storage_location) {
|
||||||
// Considering that we're failed to get accessor above and further that
|
// Considering that we're failed to get accessor above and further that
|
||||||
// the index still returned the same (slot, store_id) tuple, offset must be same
|
// the index still returned the same (slot, store_id) tuple, offset must be same
|
||||||
// too.
|
// too.
|
||||||
assert!(new_offset == offset);
|
assert!(new_storage_location.is_offset_equal(&storage_location));
|
||||||
|
|
||||||
// If the entry was missing from the cache, that means it must have been flushed,
|
// If the entry was missing from the cache, that means it must have been flushed,
|
||||||
// and the accounts index is always updated before cache flush, so store_id must
|
// and the accounts index is always updated before cache flush, so store_id must
|
||||||
// not indicate being cached at this point.
|
// not indicate being cached at this point.
|
||||||
assert!(new_store_id != CACHE_VIRTUAL_STORAGE_ID);
|
assert!(!new_storage_location.is_cached());
|
||||||
|
|
||||||
// If this is not a cache entry, then this was a minor fork slot
|
// If this is not a cache entry, then this was a minor fork slot
|
||||||
// that had its storage entries cleaned up by purge_slots() but hasn't been
|
// that had its storage entries cleaned up by purge_slots() but hasn't been
|
||||||
|
@ -3617,8 +3595,8 @@ impl AccountsDb {
|
||||||
// For details, see the comment in AccountIndex::do_checked_scan_accounts(),
|
// For details, see the comment in AccountIndex::do_checked_scan_accounts(),
|
||||||
// which is referring back here.
|
// which is referring back here.
|
||||||
panic!(
|
panic!(
|
||||||
"Bad index entry detected ({}, {}, {}, {}, {:?})",
|
"Bad index entry detected ({}, {}, {:?}, {:?})",
|
||||||
pubkey, slot, store_id, offset, load_hint
|
pubkey, slot, storage_location, load_hint
|
||||||
);
|
);
|
||||||
} else if fallback_to_slow_path {
|
} else if fallback_to_slow_path {
|
||||||
// the above bad-index-entry check must had been checked first to retain the same
|
// the above bad-index-entry check must had been checked first to retain the same
|
||||||
|
@ -3630,8 +3608,7 @@ impl AccountsDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = new_slot;
|
slot = new_slot;
|
||||||
store_id = new_store_id;
|
storage_location = new_storage_location;
|
||||||
offset = new_offset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3645,11 +3622,11 @@ impl AccountsDb {
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
assert!(max_root.is_none());
|
assert!(max_root.is_none());
|
||||||
|
|
||||||
let (slot, store_id, offset, _maybe_account_accesor) =
|
let (slot, storage_location, _maybe_account_accesor) =
|
||||||
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, max_root, false)?;
|
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, max_root, false)?;
|
||||||
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
||||||
|
|
||||||
if self.caching_enabled && store_id != CACHE_VIRTUAL_STORAGE_ID {
|
if self.caching_enabled && !storage_location.is_cached() {
|
||||||
let result = self.read_only_accounts_cache.load(pubkey, slot);
|
let result = self.read_only_accounts_cache.load(pubkey, slot);
|
||||||
if let Some(account) = result {
|
if let Some(account) = result {
|
||||||
return Some((account, slot));
|
return Some((account, slot));
|
||||||
|
@ -3657,7 +3634,12 @@ impl AccountsDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut account_accessor, slot) = self.retry_to_get_account_accessor(
|
let (mut account_accessor, slot) = self.retry_to_get_account_accessor(
|
||||||
slot, store_id, offset, ancestors, pubkey, max_root, load_hint,
|
slot,
|
||||||
|
storage_location,
|
||||||
|
ancestors,
|
||||||
|
pubkey,
|
||||||
|
max_root,
|
||||||
|
load_hint,
|
||||||
)?;
|
)?;
|
||||||
let loaded_account = account_accessor.check_and_get_loaded_account();
|
let loaded_account = account_accessor.check_and_get_loaded_account();
|
||||||
let is_cached = loaded_account.is_cached();
|
let is_cached = loaded_account.is_cached();
|
||||||
|
@ -3688,12 +3670,17 @@ impl AccountsDb {
|
||||||
max_root: Option<Slot>,
|
max_root: Option<Slot>,
|
||||||
load_hint: LoadHint,
|
load_hint: LoadHint,
|
||||||
) -> Option<Hash> {
|
) -> Option<Hash> {
|
||||||
let (slot, store_id, offset, _maybe_account_accesor) =
|
let (slot, storage_location, _maybe_account_accesor) =
|
||||||
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, max_root, false)?;
|
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, max_root, false)?;
|
||||||
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
// Notice the subtle `?` at previous line, we bail out pretty early if missing.
|
||||||
|
|
||||||
let (mut account_accessor, _) = self.retry_to_get_account_accessor(
|
let (mut account_accessor, _) = self.retry_to_get_account_accessor(
|
||||||
slot, store_id, offset, ancestors, pubkey, max_root, load_hint,
|
slot,
|
||||||
|
storage_location,
|
||||||
|
ancestors,
|
||||||
|
pubkey,
|
||||||
|
max_root,
|
||||||
|
load_hint,
|
||||||
)?;
|
)?;
|
||||||
let loaded_account = account_accessor.check_and_get_loaded_account();
|
let loaded_account = account_accessor.check_and_get_loaded_account();
|
||||||
Some(loaded_account.loaded_hash())
|
Some(loaded_account.loaded_hash())
|
||||||
|
@ -3703,20 +3690,22 @@ impl AccountsDb {
|
||||||
&'a self,
|
&'a self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
pubkey: &'a Pubkey,
|
pubkey: &'a Pubkey,
|
||||||
store_id: AppendVecId,
|
storage_location: &StorageLocation,
|
||||||
offset: usize,
|
|
||||||
) -> LoadedAccountAccessor<'a> {
|
) -> LoadedAccountAccessor<'a> {
|
||||||
if store_id == CACHE_VIRTUAL_STORAGE_ID {
|
match storage_location {
|
||||||
|
StorageLocation::Cached => {
|
||||||
let maybe_cached_account = self.accounts_cache.load(slot, pubkey).map(Cow::Owned);
|
let maybe_cached_account = self.accounts_cache.load(slot, pubkey).map(Cow::Owned);
|
||||||
LoadedAccountAccessor::Cached(maybe_cached_account)
|
LoadedAccountAccessor::Cached(maybe_cached_account)
|
||||||
} else {
|
}
|
||||||
|
StorageLocation::AppendVec(store_id, offset) => {
|
||||||
let maybe_storage_entry = self
|
let maybe_storage_entry = self
|
||||||
.storage
|
.storage
|
||||||
.get_account_storage_entry(slot, store_id)
|
.get_account_storage_entry(slot, *store_id)
|
||||||
.map(|account_storage_entry| (account_storage_entry, offset));
|
.map(|account_storage_entry| (account_storage_entry, *offset));
|
||||||
LoadedAccountAccessor::Stored(maybe_storage_entry)
|
LoadedAccountAccessor::Stored(maybe_storage_entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_recycle_and_insert_store(
|
fn try_recycle_and_insert_store(
|
||||||
&self,
|
&self,
|
||||||
|
@ -5124,8 +5113,7 @@ impl AccountsDb {
|
||||||
self.get_account_accessor(
|
self.get_account_accessor(
|
||||||
*slot,
|
*slot,
|
||||||
pubkey,
|
pubkey,
|
||||||
account_info.store_id(),
|
&account_info.storage_location(),
|
||||||
account_info.offset(),
|
|
||||||
)
|
)
|
||||||
.get_loaded_account()
|
.get_loaded_account()
|
||||||
.and_then(
|
.and_then(
|
||||||
|
|
Loading…
Reference in New Issue