-
Notifications
You must be signed in to change notification settings - Fork 920
Allows scanning slot and getting stored account info without data #5840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,8 +29,9 @@ use { | |
| crate::{ | ||
| account_info::{AccountInfo, Offset, StorageLocation}, | ||
| account_storage::{ | ||
| meta::StoredAccountMeta, stored_account_info::StoredAccountInfo, AccountStorage, | ||
| AccountStorageStatus, ShrinkInProgress, | ||
| meta::StoredAccountMeta, | ||
| stored_account_info::{StoredAccountInfo, StoredAccountInfoWithoutData}, | ||
| AccountStorage, AccountStorageStatus, ShrinkInProgress, | ||
| }, | ||
| accounts_cache::{AccountsCache, CachedAccount, SlotCache}, | ||
| accounts_db::stats::{ | ||
|
|
@@ -173,6 +174,8 @@ impl StoreTo<'_> { | |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| pub(crate) enum ScanAccountStorageData { | ||
| /// callback for accounts in storage will not include `data` | ||
| // Note, currently only used in tests, but do not remove. | ||
| #[cfg_attr(not(test), allow(dead_code))] | ||
| NoData, | ||
| /// return data (&[u8]) for each account. | ||
| /// This can be expensive to get and is not necessary for many scan operations. | ||
|
|
@@ -4924,20 +4927,32 @@ impl AccountsDb { | |
| &self, | ||
| slot: Slot, | ||
| cache_map_func: impl Fn(&LoadedAccount) -> Option<R> + Sync, | ||
| storage_scan_func: impl Fn(&mut B, &LoadedAccount, Option<&[u8]>) + Sync, | ||
| storage_scan_func: impl for<'a, 'b, 'storage> Fn( | ||
| &'b mut B, | ||
| &'a StoredAccountInfoWithoutData<'storage>, | ||
| Option<&'storage [u8]>, // account data | ||
| ) + Sync, | ||
| scan_account_storage_data: ScanAccountStorageData, | ||
| ) -> ScanStorageResult<R, B> | ||
| where | ||
| R: Send, | ||
| B: Send + Default + Sync, | ||
| { | ||
| self.scan_cache_storage_fallback(slot, cache_map_func, |retval, storage| { | ||
| storage.scan_accounts(|account| { | ||
| let loaded_account = LoadedAccount::Stored(account); | ||
| let data = (scan_account_storage_data == ScanAccountStorageData::DataRefForStorage) | ||
| .then_some(loaded_account.data()); | ||
| storage_scan_func(retval, &loaded_account, data) | ||
| }); | ||
| match scan_account_storage_data { | ||
| ScanAccountStorageData::NoData => { | ||
| storage.scan_accounts(|account| { | ||
| let account_without_data = StoredAccountInfoWithoutData::new_from(&account); | ||
| storage_scan_func(retval, &account_without_data, None); | ||
| }); | ||
| } | ||
| ScanAccountStorageData::DataRefForStorage => { | ||
| storage.scan_accounts(|account| { | ||
| let account_without_data = StoredAccountInfoWithoutData::new_from(&account); | ||
| storage_scan_func(retval, &account_without_data, Some(account.data)); | ||
| }); | ||
| } | ||
| }; | ||
| }) | ||
| } | ||
|
|
||
|
|
@@ -7495,20 +7510,23 @@ impl AccountsDb { | |
| let scan_result: ScanStorageResult<(Pubkey, AccountHash), HashMap<Pubkey, AccountHash>> = | ||
| self.scan_account_storage( | ||
| slot, | ||
| |loaded_account: &LoadedAccount| { | ||
| |loaded_account| { | ||
| // Cache only has one version per key, don't need to worry about versioning | ||
| Some((*loaded_account.pubkey(), loaded_account.loaded_hash())) | ||
| }, | ||
| |accum: &mut HashMap<Pubkey, AccountHash>, | ||
| loaded_account: &LoadedAccount, | ||
| _data| { | ||
| |accum: &mut HashMap<_, _>, stored_account, data| { | ||
| // SAFETY: We called scan_account_storage() with | ||
| // ScanAccountStorageData::DataRefForStorage, so `data` must be Some. | ||
| let data = data.unwrap(); | ||
| let loaded_account = | ||
| LoadedAccount::Stored(StoredAccountInfo::new_from(stored_account, data)); | ||
| let mut loaded_hash = loaded_account.loaded_hash(); | ||
| if loaded_hash == AccountHash(Hash::default()) { | ||
| loaded_hash = Self::hash_account(loaded_account, loaded_account.pubkey()) | ||
| loaded_hash = Self::hash_account(&loaded_account, loaded_account.pubkey()) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're hashing the account, so we do need the account data. |
||
| } | ||
| accum.insert(*loaded_account.pubkey(), loaded_hash); | ||
| }, | ||
| ScanAccountStorageData::NoData, | ||
| ScanAccountStorageData::DataRefForStorage, | ||
| ); | ||
| scan.stop(); | ||
|
|
||
|
|
@@ -7529,11 +7547,16 @@ impl AccountsDb { | |
| // Cache only has one version per key, don't need to worry about versioning | ||
| Some((*loaded_account.pubkey(), loaded_account.take_account())) | ||
| }, | ||
| |accum: &mut HashMap<_, _>, loaded_account, _data| { | ||
| |accum: &mut HashMap<_, _>, stored_account, data| { | ||
| // SAFETY: We called scan_account_storage() with | ||
| // ScanAccountStorageData::DataRefForStorage, so `data` must be Some. | ||
| let data = data.unwrap(); | ||
| let loaded_account = | ||
| LoadedAccount::Stored(StoredAccountInfo::new_from(stored_account, data)); | ||
| // Storage may have duplicates so only keep the latest version for each key | ||
| accum.insert(*loaded_account.pubkey(), loaded_account.take_account()); | ||
| }, | ||
| ScanAccountStorageData::NoData, | ||
| ScanAccountStorageData::DataRefForStorage, | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're returning the account, so we do need the account data. |
||
| ); | ||
|
|
||
| match scan_result { | ||
|
|
@@ -7548,27 +7571,30 @@ impl AccountsDb { | |
| ScanStorageResult<PubkeyHashAccount, HashMap<Pubkey, (AccountHash, AccountSharedData)>>; | ||
| let scan_result: ScanResult = self.scan_account_storage( | ||
| slot, | ||
| |loaded_account: &LoadedAccount| { | ||
| |loaded_account| { | ||
| // Cache only has one version per key, don't need to worry about versioning | ||
| Some(PubkeyHashAccount { | ||
| pubkey: *loaded_account.pubkey(), | ||
| hash: loaded_account.loaded_hash(), | ||
| account: loaded_account.take_account(), | ||
| }) | ||
| }, | ||
| |accum: &mut HashMap<Pubkey, (AccountHash, AccountSharedData)>, | ||
| loaded_account: &LoadedAccount, | ||
| _data| { | ||
| // Storage may have duplicates so only keep the latest version for each key | ||
| |accum: &mut HashMap<_, _>, stored_account, data| { | ||
| // SAFETY: We called scan_account_storage() with | ||
| // ScanAccountStorageData::DataRefForStorage, so `data` must be Some. | ||
| let data = data.unwrap(); | ||
| let loaded_account = | ||
| LoadedAccount::Stored(StoredAccountInfo::new_from(stored_account, data)); | ||
| let mut loaded_hash = loaded_account.loaded_hash(); | ||
| let key = *loaded_account.pubkey(); | ||
| let account = loaded_account.take_account(); | ||
| if loaded_hash == AccountHash(Hash::default()) { | ||
| loaded_hash = Self::hash_account(&account, &key) | ||
| } | ||
| // Storage may have duplicates so only keep the latest version for each key | ||
| accum.insert(key, (loaded_hash, account)); | ||
| }, | ||
| ScanAccountStorageData::NoData, | ||
| ScanAccountStorageData::DataRefForStorage, | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing, we're hashing the account here. |
||
| ); | ||
|
|
||
| match scan_result { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the next PR we can add an
AccountsFile::scan_accounts_without_data()function, so we'll actually not load the account data here.