Add ability to abort scan (#21314)

This commit is contained in:
Jeff Washington (jwash) 2021-11-17 13:10:29 -06:00 committed by GitHub
parent e540b1cf3c
commit 0f69a14247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 242 additions and 121 deletions

View File

@ -28,7 +28,7 @@ use solana_ledger::{
use solana_measure::measure::Measure; use solana_measure::measure::Measure;
use solana_runtime::{ use solana_runtime::{
accounts_db::AccountsDbConfig, accounts_db::AccountsDbConfig,
accounts_index::AccountsIndexConfig, accounts_index::{AccountsIndexConfig, ScanConfig},
bank::{Bank, RewardCalculationEvent}, bank::{Bank, RewardCalculationEvent},
bank_forks::BankForks, bank_forks::BankForks,
cost_model::CostModel, cost_model::CostModel,
@ -2251,7 +2251,7 @@ fn main() {
if remove_stake_accounts { if remove_stake_accounts {
for (address, mut account) in bank for (address, mut account) in bank
.get_program_accounts(&stake::program::id()) .get_program_accounts(&stake::program::id(), ScanConfig::default())
.unwrap() .unwrap()
.into_iter() .into_iter()
{ {
@ -2275,7 +2275,7 @@ fn main() {
if !vote_accounts_to_destake.is_empty() { if !vote_accounts_to_destake.is_empty() {
for (address, mut account) in bank for (address, mut account) in bank
.get_program_accounts(&stake::program::id()) .get_program_accounts(&stake::program::id(), ScanConfig::default())
.unwrap() .unwrap()
.into_iter() .into_iter()
{ {
@ -2313,7 +2313,7 @@ fn main() {
// Delete existing vote accounts // Delete existing vote accounts
for (address, mut account) in bank for (address, mut account) in bank
.get_program_accounts(&solana_vote_program::id()) .get_program_accounts(&solana_vote_program::id(), ScanConfig::default())
.unwrap() .unwrap()
.into_iter() .into_iter()
{ {

View File

@ -39,7 +39,7 @@ use {
solana_perf::packet::PACKET_DATA_SIZE, solana_perf::packet::PACKET_DATA_SIZE,
solana_runtime::{ solana_runtime::{
accounts::AccountAddressFilter, accounts::AccountAddressFilter,
accounts_index::{AccountIndex, AccountSecondaryIndexes, IndexKey}, accounts_index::{AccountIndex, AccountSecondaryIndexes, IndexKey, ScanConfig},
bank::{Bank, TransactionSimulationResult}, bank::{Bank, TransactionSimulationResult},
bank_forks::BankForks, bank_forks::BankForks,
commitment::{BlockCommitmentArray, BlockCommitmentCache, CommitmentSlots}, commitment::{BlockCommitmentArray, BlockCommitmentCache, CommitmentSlots},
@ -1830,20 +1830,24 @@ impl JsonRpcRequestProcessor {
}); });
} }
Ok(bank Ok(bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(*program_id), |account| { .get_filtered_indexed_accounts(
&IndexKey::ProgramId(*program_id),
|account| {
// The program-id account index checks for Account owner on inclusion. However, due // The program-id account index checks for Account owner on inclusion. However, due
// to the current AccountsDb implementation, an account may remain in storage as a // to the current AccountsDb implementation, an account may remain in storage as a
// zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later // zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
// updates. We include the redundant filters here to avoid returning these // updates. We include the redundant filters here to avoid returning these
// accounts. // accounts.
account.owner() == program_id && filter_closure(account) account.owner() == program_id && filter_closure(account)
}) },
ScanConfig::default(),
)
.map_err(|e| RpcCustomError::ScanError { .map_err(|e| RpcCustomError::ScanError {
message: e.to_string(), message: e.to_string(),
})?) })?)
} else { } else {
Ok(bank Ok(bank
.get_filtered_program_accounts(program_id, filter_closure) .get_filtered_program_accounts(program_id, filter_closure, ScanConfig::default())
.map_err(|e| RpcCustomError::ScanError { .map_err(|e| RpcCustomError::ScanError {
message: e.to_string(), message: e.to_string(),
})?) })?)
@ -1884,13 +1888,21 @@ impl JsonRpcRequestProcessor {
}); });
} }
Ok(bank Ok(bank
.get_filtered_indexed_accounts(&IndexKey::SplTokenOwner(*owner_key), |account| { .get_filtered_indexed_accounts(
&IndexKey::SplTokenOwner(*owner_key),
|account| {
account.owner() == &spl_token_id_v2_0() account.owner() == &spl_token_id_v2_0()
&& filters.iter().all(|filter_type| match filter_type { && filters.iter().all(|filter_type| match filter_type {
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size, RpcFilterType::DataSize(size) => {
RpcFilterType::Memcmp(compare) => compare.bytes_match(account.data()), account.data().len() as u64 == *size
}) }
RpcFilterType::Memcmp(compare) => {
compare.bytes_match(account.data())
}
}) })
},
ScanConfig::default(),
)
.map_err(|e| RpcCustomError::ScanError { .map_err(|e| RpcCustomError::ScanError {
message: e.to_string(), message: e.to_string(),
})?) })?)
@ -1932,13 +1944,21 @@ impl JsonRpcRequestProcessor {
}); });
} }
Ok(bank Ok(bank
.get_filtered_indexed_accounts(&IndexKey::SplTokenMint(*mint_key), |account| { .get_filtered_indexed_accounts(
&IndexKey::SplTokenMint(*mint_key),
|account| {
account.owner() == &spl_token_id_v2_0() account.owner() == &spl_token_id_v2_0()
&& filters.iter().all(|filter_type| match filter_type { && filters.iter().all(|filter_type| match filter_type {
RpcFilterType::DataSize(size) => account.data().len() as u64 == *size, RpcFilterType::DataSize(size) => {
RpcFilterType::Memcmp(compare) => compare.bytes_match(account.data()), account.data().len() as u64 == *size
}) }
RpcFilterType::Memcmp(compare) => {
compare.bytes_match(account.data())
}
}) })
},
ScanConfig::default(),
)
.map_err(|e| RpcCustomError::ScanError { .map_err(|e| RpcCustomError::ScanError {
message: e.to_string(), message: e.to_string(),
})?) })?)

View File

@ -9,7 +9,7 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use solana_runtime::{ use solana_runtime::{
accounts::{create_test_accounts, AccountAddressFilter, Accounts}, accounts::{create_test_accounts, AccountAddressFilter, Accounts},
accounts_db::AccountShrinkThreshold, accounts_db::AccountShrinkThreshold,
accounts_index::AccountSecondaryIndexes, accounts_index::{AccountSecondaryIndexes, ScanConfig},
ancestors::Ancestors, ancestors::Ancestors,
bank::*, bank::*,
}; };
@ -267,6 +267,7 @@ fn bench_concurrent_scan_write(bencher: &mut Bencher) {
&Ancestors::default(), &Ancestors::default(),
0, 0,
AccountSharedData::default().owner(), AccountSharedData::default().owner(),
ScanConfig::default(),
) )
.unwrap(), .unwrap(),
); );

View File

@ -4,7 +4,7 @@ use crate::{
LoadHint, LoadedAccount, ScanStorageResult, ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, LoadHint, LoadedAccount, ScanStorageResult, ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS,
ACCOUNTS_DB_CONFIG_FOR_TESTING, ACCOUNTS_DB_CONFIG_FOR_TESTING,
}, },
accounts_index::{AccountSecondaryIndexes, IndexKey, ScanResult}, accounts_index::{AccountSecondaryIndexes, IndexKey, ScanConfig, ScanResult},
accounts_update_notifier_interface::AccountsUpdateNotifier, accounts_update_notifier_interface::AccountsUpdateNotifier,
ancestors::Ancestors, ancestors::Ancestors,
bank::{ bank::{
@ -667,6 +667,7 @@ impl Accounts {
collector.push(Reverse((account.lamports(), *pubkey))); collector.push(Reverse((account.lamports(), *pubkey)));
} }
}, },
ScanConfig::default(),
)?; )?;
Ok(account_balances Ok(account_balances
.into_sorted_vec() .into_sorted_vec()
@ -744,6 +745,7 @@ impl Accounts {
ancestors: &Ancestors, ancestors: &Ancestors,
bank_id: BankId, bank_id: BankId,
program_id: &Pubkey, program_id: &Pubkey,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.accounts_db.scan_accounts( self.accounts_db.scan_accounts(
ancestors, ancestors,
@ -753,6 +755,7 @@ impl Accounts {
account.owner() == program_id account.owner() == program_id
}) })
}, },
config,
) )
} }
@ -762,6 +765,7 @@ impl Accounts {
bank_id: BankId, bank_id: BankId,
program_id: &Pubkey, program_id: &Pubkey,
filter: F, filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.accounts_db.scan_accounts( self.accounts_db.scan_accounts(
ancestors, ancestors,
@ -771,6 +775,7 @@ impl Accounts {
account.owner() == program_id && filter(account) account.owner() == program_id && filter(account)
}) })
}, },
config,
) )
} }
@ -780,6 +785,7 @@ impl Accounts {
bank_id: BankId, bank_id: BankId,
index_key: &IndexKey, index_key: &IndexKey,
filter: F, filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.accounts_db self.accounts_db
.index_scan_accounts( .index_scan_accounts(
@ -791,6 +797,7 @@ impl Accounts {
filter(account) filter(account)
}) })
}, },
config,
) )
.map(|result| result.0) .map(|result| result.0)
} }
@ -814,6 +821,7 @@ impl Accounts {
collector.push((*pubkey, account, slot)) collector.push((*pubkey, account, slot))
} }
}, },
ScanConfig::default(),
) )
} }
@ -835,7 +843,7 @@ impl Accounts {
"load_to_collect_rent_eagerly_scan_elapsed", "load_to_collect_rent_eagerly_scan_elapsed",
ancestors, ancestors,
range, range,
true, ScanConfig::new(true),
|collector: &mut Vec<(Pubkey, AccountSharedData)>, option| { |collector: &mut Vec<(Pubkey, AccountSharedData)>, option| {
Self::load_while_filtering(collector, option, |_| true) Self::load_while_filtering(collector, option, |_| true)
}, },

View File

@ -24,8 +24,8 @@ use crate::{
accounts_hash::{AccountsHash, CalculateHashIntermediate, HashStats, PreviousPass}, accounts_hash::{AccountsHash, CalculateHashIntermediate, HashStats, PreviousPass},
accounts_index::{ accounts_index::{
AccountIndexGetResult, AccountSecondaryIndexes, AccountsIndex, AccountsIndexConfig, AccountIndexGetResult, AccountSecondaryIndexes, AccountsIndex, AccountsIndexConfig,
AccountsIndexRootsStats, IndexKey, IndexValue, IsCached, RefCount, ScanResult, SlotList, AccountsIndexRootsStats, IndexKey, IndexValue, IsCached, RefCount, ScanConfig, ScanResult,
SlotSlice, ZeroLamport, ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS, SlotList, SlotSlice, ZeroLamport, ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS,
ACCOUNTS_INDEX_CONFIG_FOR_TESTING, ACCOUNTS_INDEX_CONFIG_FOR_TESTING,
}, },
accounts_update_notifier_interface::AccountsUpdateNotifier, accounts_update_notifier_interface::AccountsUpdateNotifier,
@ -3059,6 +3059,7 @@ impl AccountsDb {
ancestors: &Ancestors, ancestors: &Ancestors,
bank_id: BankId, bank_id: BankId,
scan_func: F, scan_func: F,
config: ScanConfig,
) -> ScanResult<A> ) -> ScanResult<A>
where where
F: Fn(&mut A, Option<(&Pubkey, AccountSharedData, Slot)>), F: Fn(&mut A, Option<(&Pubkey, AccountSharedData, Slot)>),
@ -3067,14 +3068,18 @@ impl AccountsDb {
let mut collector = A::default(); let mut collector = A::default();
// This can error out if the slots being scanned over are aborted // This can error out if the slots being scanned over are aborted
self.accounts_index self.accounts_index.scan_accounts(
.scan_accounts(ancestors, bank_id, |pubkey, (account_info, slot)| { ancestors,
bank_id,
|pubkey, (account_info, slot)| {
let account_slot = self let account_slot = self
.get_account_accessor(slot, pubkey, account_info.store_id, account_info.offset) .get_account_accessor(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)
})?; },
config,
)?;
Ok(collector) Ok(collector)
} }
@ -3084,7 +3089,7 @@ impl AccountsDb {
metric_name: &'static str, metric_name: &'static str,
ancestors: &Ancestors, ancestors: &Ancestors,
scan_func: F, scan_func: F,
collect_all_unsorted: bool, config: ScanConfig,
) -> A ) -> A
where where
F: Fn(&mut A, (&Pubkey, LoadedAccount, Slot)), F: Fn(&mut A, (&Pubkey, LoadedAccount, Slot)),
@ -3102,7 +3107,7 @@ impl AccountsDb {
scan_func(&mut collector, (pubkey, loaded_account, slot)); scan_func(&mut collector, (pubkey, loaded_account, slot));
} }
}, },
collect_all_unsorted, config,
); );
collector collector
} }
@ -3112,7 +3117,7 @@ impl AccountsDb {
metric_name: &'static str, metric_name: &'static str,
ancestors: &Ancestors, ancestors: &Ancestors,
range: R, range: R,
collect_all_unsorted: bool, config: ScanConfig,
scan_func: F, scan_func: F,
) -> A ) -> A
where where
@ -3125,7 +3130,7 @@ impl AccountsDb {
metric_name, metric_name,
ancestors, ancestors,
range, range,
collect_all_unsorted, config,
|pubkey, (account_info, slot)| { |pubkey, (account_info, slot)| {
// unlike other scan fns, this is called from Bank::collect_rent_eagerly(), // unlike other scan fns, this is called from Bank::collect_rent_eagerly(),
// which is on-consensus processing in the banking/replaying stage. // which is on-consensus processing in the banking/replaying stage.
@ -3153,6 +3158,7 @@ impl AccountsDb {
bank_id: BankId, bank_id: BankId,
index_key: IndexKey, index_key: IndexKey,
scan_func: F, scan_func: F,
config: ScanConfig,
) -> ScanResult<(A, bool)> ) -> ScanResult<(A, bool)>
where where
F: Fn(&mut A, Option<(&Pubkey, AccountSharedData, Slot)>), F: Fn(&mut A, Option<(&Pubkey, AccountSharedData, Slot)>),
@ -3166,7 +3172,7 @@ impl AccountsDb {
if !self.account_indexes.include_key(key) { if !self.account_indexes.include_key(key) {
// the requested key was not indexed in the secondary index, so do a normal scan // the requested key was not indexed in the secondary index, so do a normal scan
let used_index = false; let used_index = false;
let scan_result = self.scan_accounts(ancestors, bank_id, scan_func)?; let scan_result = self.scan_accounts(ancestors, bank_id, scan_func, config)?;
return Ok((scan_result, used_index)); return Ok((scan_result, used_index));
} }
@ -3182,6 +3188,7 @@ impl AccountsDb {
.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)
}, },
config,
)?; )?;
let used_index = true; let used_index = true;
Ok((collector, used_index)) Ok((collector, used_index))
@ -8035,8 +8042,6 @@ pub mod tests {
); );
} }
const COLLECT_ALL_UNSORTED_FALSE: bool = false;
#[test] #[test]
fn test_accountsdb_latest_ancestor() { fn test_accountsdb_latest_ancestor() {
solana_logger::setup(); solana_logger::setup();
@ -8067,7 +8072,7 @@ pub mod tests {
|accounts: &mut Vec<AccountSharedData>, option| { |accounts: &mut Vec<AccountSharedData>, option| {
accounts.push(option.1.take_account()); accounts.push(option.1.take_account());
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(accounts, vec![account1]); assert_eq!(accounts, vec![account1]);
} }
@ -8970,9 +8975,15 @@ pub mod tests {
let bank_id = 0; let bank_id = 0;
accounts accounts
.accounts_index .accounts_index
.index_scan_accounts(&Ancestors::default(), bank_id, index_key, |key, _| { .index_scan_accounts(
&Ancestors::default(),
bank_id,
index_key,
|key, _| {
found_accounts.insert(*key); found_accounts.insert(*key);
}) },
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert_eq!(found_accounts.len(), 2); assert_eq!(found_accounts.len(), 2);
assert!(found_accounts.contains(&pubkey1)); assert!(found_accounts.contains(&pubkey1));
@ -8992,6 +9003,7 @@ pub mod tests {
|collection: &mut HashSet<Pubkey>, account| { |collection: &mut HashSet<Pubkey>, account| {
collection.insert(*account.unwrap().0); collection.insert(*account.unwrap().0);
}, },
ScanConfig::default(),
) )
.unwrap(); .unwrap();
assert!(!found_accounts.1); assert!(!found_accounts.1);
@ -9010,6 +9022,7 @@ pub mod tests {
|collection: &mut HashSet<Pubkey>, account| { |collection: &mut HashSet<Pubkey>, account| {
collection.insert(*account.unwrap().0); collection.insert(*account.unwrap().0);
}, },
ScanConfig::default(),
) )
.unwrap(); .unwrap();
assert!(found_accounts.1); assert!(found_accounts.1);
@ -9043,6 +9056,7 @@ pub mod tests {
bank_id, bank_id,
IndexKey::SplTokenMint(mint_key), IndexKey::SplTokenMint(mint_key),
|key, _| found_accounts.push(*key), |key, _| found_accounts.push(*key),
ScanConfig::default(),
) )
.unwrap(); .unwrap();
assert_eq!(found_accounts, vec![pubkey2]); assert_eq!(found_accounts, vec![pubkey2]);
@ -9598,7 +9612,7 @@ pub mod tests {
|accounts: &mut Vec<AccountSharedData>, option| { |accounts: &mut Vec<AccountSharedData>, option| {
accounts.push(option.1.take_account()); accounts.push(option.1.take_account());
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(accounts, vec![account0]); assert_eq!(accounts, vec![account0]);
@ -9609,7 +9623,7 @@ pub mod tests {
|accounts: &mut Vec<AccountSharedData>, option| { |accounts: &mut Vec<AccountSharedData>, option| {
accounts.push(option.1.take_account()); accounts.push(option.1.take_account());
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(accounts.len(), 2); assert_eq!(accounts.len(), 2);
} }
@ -11783,6 +11797,7 @@ pub mod tests {
} }
} }
}, },
ScanConfig::default(),
) )
.unwrap(); .unwrap();
}) })

View File

@ -59,6 +59,34 @@ pub type SlotSlice<'s, T> = &'s [(Slot, T)];
pub type RefCount = u64; pub type RefCount = u64;
pub type AccountMap<V> = Arc<InMemAccountsIndex<V>>; pub type AccountMap<V> = Arc<InMemAccountsIndex<V>>;
#[derive(Debug, Default)]
pub struct ScanConfig {
/// checked by the scan. When true, abort scan.
abort: Option<Arc<AtomicBool>>,
/// true to allow return of all matching items and allow them to be unsorted.
/// This is more efficient.
collect_all_unsorted: bool,
}
impl ScanConfig {
pub fn new(collect_all_unsorted: bool) -> Self {
Self {
collect_all_unsorted,
..ScanConfig::default()
}
}
/// true if scan should abort
pub fn is_aborted(&self) -> bool {
if let Some(abort) = self.abort.as_ref() {
abort.load(Ordering::Relaxed)
} else {
false
}
}
}
pub(crate) type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>; pub(crate) type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>;
pub trait IsCached: pub trait IsCached:
@ -837,7 +865,7 @@ impl<T: IndexValue> AccountsIndex<T> {
scan_bank_id: BankId, scan_bank_id: BankId,
func: F, func: F,
scan_type: ScanTypes<R>, scan_type: ScanTypes<R>,
collect_all_unsorted: bool, config: ScanConfig,
) -> Result<(), ScanError> ) -> Result<(), ScanError>
where where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
@ -990,14 +1018,7 @@ impl<T: IndexValue> AccountsIndex<T> {
match scan_type { match scan_type {
ScanTypes::Unindexed(range) => { ScanTypes::Unindexed(range) => {
// Pass "" not to log metrics, so RPC doesn't get spammy // Pass "" not to log metrics, so RPC doesn't get spammy
self.do_scan_accounts( self.do_scan_accounts(metric_name, ancestors, func, range, Some(max_root), config);
metric_name,
ancestors,
func,
range,
Some(max_root),
collect_all_unsorted,
);
} }
ScanTypes::Indexed(IndexKey::ProgramId(program_id)) => { ScanTypes::Indexed(IndexKey::ProgramId(program_id)) => {
self.do_scan_secondary_index( self.do_scan_secondary_index(
@ -1006,6 +1027,7 @@ impl<T: IndexValue> AccountsIndex<T> {
&self.program_id_index, &self.program_id_index,
&program_id, &program_id,
Some(max_root), Some(max_root),
config,
); );
} }
ScanTypes::Indexed(IndexKey::SplTokenMint(mint_key)) => { ScanTypes::Indexed(IndexKey::SplTokenMint(mint_key)) => {
@ -1015,6 +1037,7 @@ impl<T: IndexValue> AccountsIndex<T> {
&self.spl_token_mint_index, &self.spl_token_mint_index,
&mint_key, &mint_key,
Some(max_root), Some(max_root),
config,
); );
} }
ScanTypes::Indexed(IndexKey::SplTokenOwner(owner_key)) => { ScanTypes::Indexed(IndexKey::SplTokenOwner(owner_key)) => {
@ -1024,6 +1047,7 @@ impl<T: IndexValue> AccountsIndex<T> {
&self.spl_token_owner_index, &self.spl_token_owner_index,
&owner_key, &owner_key,
Some(max_root), Some(max_root),
config,
); );
} }
} }
@ -1061,19 +1085,12 @@ impl<T: IndexValue> AccountsIndex<T> {
ancestors: &Ancestors, ancestors: &Ancestors,
func: F, func: F,
range: Option<R>, range: Option<R>,
collect_all_unsorted: bool, config: ScanConfig,
) where ) where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
R: RangeBounds<Pubkey> + std::fmt::Debug, R: RangeBounds<Pubkey> + std::fmt::Debug,
{ {
self.do_scan_accounts( self.do_scan_accounts(metric_name, ancestors, func, range, None, config);
metric_name,
ancestors,
func,
range,
None,
collect_all_unsorted,
);
} }
// Scan accounts and return latest version of each account that is either: // Scan accounts and return latest version of each account that is either:
@ -1086,7 +1103,7 @@ impl<T: IndexValue> AccountsIndex<T> {
mut func: F, mut func: F,
range: Option<R>, range: Option<R>,
max_root: Option<Slot>, max_root: Option<Slot>,
collect_all_unsorted: bool, config: ScanConfig,
) where ) where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
R: RangeBounds<Pubkey> + std::fmt::Debug, R: RangeBounds<Pubkey> + std::fmt::Debug,
@ -1100,7 +1117,7 @@ impl<T: IndexValue> AccountsIndex<T> {
let mut read_lock_elapsed = 0; let mut read_lock_elapsed = 0;
let mut iterator_elapsed = 0; let mut iterator_elapsed = 0;
let mut iterator_timer = Measure::start("iterator_elapsed"); let mut iterator_timer = Measure::start("iterator_elapsed");
for pubkey_list in self.iter(range.as_ref(), collect_all_unsorted) { for pubkey_list in self.iter(range.as_ref(), config.collect_all_unsorted) {
iterator_timer.stop(); iterator_timer.stop();
iterator_elapsed += iterator_timer.as_us(); iterator_elapsed += iterator_timer.as_us();
for (pubkey, list) in pubkey_list { for (pubkey, list) in pubkey_list {
@ -1118,6 +1135,9 @@ impl<T: IndexValue> AccountsIndex<T> {
load_account_timer.stop(); load_account_timer.stop();
load_account_elapsed += load_account_timer.as_us(); load_account_elapsed += load_account_timer.as_us();
} }
if config.is_aborted() {
return;
}
} }
iterator_timer = Measure::start("iterator_elapsed"); iterator_timer = Measure::start("iterator_elapsed");
} }
@ -1146,6 +1166,7 @@ impl<T: IndexValue> AccountsIndex<T> {
index: &SecondaryIndex<SecondaryIndexEntryType>, index: &SecondaryIndex<SecondaryIndexEntryType>,
index_key: &Pubkey, index_key: &Pubkey,
max_root: Option<Slot>, max_root: Option<Slot>,
config: ScanConfig,
) where ) where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
{ {
@ -1160,6 +1181,9 @@ impl<T: IndexValue> AccountsIndex<T> {
(&list_r.slot_list()[index].1, list_r.slot_list()[index].0), (&list_r.slot_list()[index].1, list_r.slot_list()[index].0),
); );
} }
if config.is_aborted() {
break;
}
} }
} }
@ -1212,11 +1236,11 @@ impl<T: IndexValue> AccountsIndex<T> {
ancestors: &Ancestors, ancestors: &Ancestors,
scan_bank_id: BankId, scan_bank_id: BankId,
func: F, func: F,
config: ScanConfig,
) -> Result<(), ScanError> ) -> Result<(), ScanError>
where where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
{ {
let collect_all_unsorted = false;
// Pass "" not to log metrics, so RPC doesn't get spammy // Pass "" not to log metrics, so RPC doesn't get spammy
self.do_checked_scan_accounts( self.do_checked_scan_accounts(
"", "",
@ -1224,7 +1248,7 @@ impl<T: IndexValue> AccountsIndex<T> {
scan_bank_id, scan_bank_id,
func, func,
ScanTypes::Unindexed(None::<Range<Pubkey>>), ScanTypes::Unindexed(None::<Range<Pubkey>>),
collect_all_unsorted, config,
) )
} }
@ -1233,7 +1257,7 @@ impl<T: IndexValue> AccountsIndex<T> {
metric_name: &'static str, metric_name: &'static str,
ancestors: &Ancestors, ancestors: &Ancestors,
func: F, func: F,
collect_all_unsorted: bool, config: ScanConfig,
) where ) where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
{ {
@ -1242,7 +1266,7 @@ impl<T: IndexValue> AccountsIndex<T> {
ancestors, ancestors,
func, func,
None::<Range<Pubkey>>, None::<Range<Pubkey>>,
collect_all_unsorted, config,
); );
} }
@ -1252,20 +1276,14 @@ impl<T: IndexValue> AccountsIndex<T> {
metric_name: &'static str, metric_name: &'static str,
ancestors: &Ancestors, ancestors: &Ancestors,
range: R, range: R,
collect_all_unsorted: bool, config: ScanConfig,
func: F, func: F,
) where ) where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
R: RangeBounds<Pubkey> + std::fmt::Debug, R: RangeBounds<Pubkey> + std::fmt::Debug,
{ {
// Only the rent logic should be calling this, which doesn't need the safety checks // Only the rent logic should be calling this, which doesn't need the safety checks
self.do_unchecked_scan_accounts( self.do_unchecked_scan_accounts(metric_name, ancestors, func, Some(range), config);
metric_name,
ancestors,
func,
Some(range),
collect_all_unsorted,
);
} }
/// call func with every pubkey and index visible from a given set of ancestors /// call func with every pubkey and index visible from a given set of ancestors
@ -1275,12 +1293,11 @@ impl<T: IndexValue> AccountsIndex<T> {
scan_bank_id: BankId, scan_bank_id: BankId,
index_key: IndexKey, index_key: IndexKey,
func: F, func: F,
config: ScanConfig,
) -> Result<(), ScanError> ) -> Result<(), ScanError>
where where
F: FnMut(&Pubkey, (&T, Slot)), F: FnMut(&Pubkey, (&T, Slot)),
{ {
let collect_all_unsorted = false;
// Pass "" not to log metrics, so RPC doesn't get spammy // Pass "" not to log metrics, so RPC doesn't get spammy
self.do_checked_scan_accounts( self.do_checked_scan_accounts(
"", "",
@ -1288,7 +1305,7 @@ impl<T: IndexValue> AccountsIndex<T> {
scan_bank_id, scan_bank_id,
func, func,
ScanTypes::<Range<Pubkey>>::Indexed(index_key), ScanTypes::<Range<Pubkey>>::Indexed(index_key),
collect_all_unsorted, config,
) )
} }
@ -2676,7 +2693,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
} }
@ -2754,7 +2771,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
} }
@ -2793,7 +2810,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
ancestors.insert(slot, 0); ancestors.insert(slot, 0);
@ -2803,7 +2820,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 1); assert_eq!(num, 1);
@ -2822,7 +2839,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
ancestors.insert(slot, 0); ancestors.insert(slot, 0);
@ -2832,7 +2849,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 1); assert_eq!(num, 1);
} }
@ -3019,7 +3036,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
ancestors.insert(slot, 0); ancestors.insert(slot, 0);
@ -3028,7 +3045,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 1); assert_eq!(num, 1);
} }
@ -3058,7 +3075,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
|_pubkey, _index| num += 1, |_pubkey, _index| num += 1,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 0); assert_eq!(num, 0);
} }
@ -3095,7 +3112,7 @@ pub mod tests {
}; };
num += 1 num += 1
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 1); assert_eq!(num, 1);
assert!(found_key); assert!(found_key);
@ -3168,7 +3185,7 @@ pub mod tests {
"", "",
&ancestors, &ancestors,
pubkey_range, pubkey_range,
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
|pubkey, _index| { |pubkey, _index| {
scanned_keys.insert(*pubkey); scanned_keys.insert(*pubkey);
}, },
@ -3247,7 +3264,7 @@ pub mod tests {
|pubkey, _index| { |pubkey, _index| {
scanned_keys.insert(*pubkey); scanned_keys.insert(*pubkey);
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(scanned_keys.len(), num_pubkeys); assert_eq!(scanned_keys.len(), num_pubkeys);
} }
@ -3553,7 +3570,7 @@ pub mod tests {
}; };
num += 1 num += 1
}, },
COLLECT_ALL_UNSORTED_FALSE, ScanConfig::default(),
); );
assert_eq!(num, 1); assert_eq!(num, 1);
assert!(found_key); assert!(found_key);

View File

@ -39,7 +39,7 @@ use crate::{
AccountShrinkThreshold, AccountsDbConfig, ErrorCounters, SnapshotStorages, AccountShrinkThreshold, AccountsDbConfig, ErrorCounters, SnapshotStorages,
ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, ACCOUNTS_DB_CONFIG_FOR_TESTING, ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, ACCOUNTS_DB_CONFIG_FOR_TESTING,
}, },
accounts_index::{AccountSecondaryIndexes, IndexKey, ScanResult}, accounts_index::{AccountSecondaryIndexes, IndexKey, ScanConfig, ScanResult},
accounts_update_notifier_interface::AccountsUpdateNotifier, accounts_update_notifier_interface::AccountsUpdateNotifier,
ancestors::{Ancestors, AncestorsForSerialization}, ancestors::{Ancestors, AncestorsForSerialization},
blockhash_queue::BlockhashQueue, blockhash_queue::BlockhashQueue,
@ -5254,22 +5254,25 @@ impl Bank {
pub fn get_program_accounts( pub fn get_program_accounts(
&self, &self,
program_id: &Pubkey, program_id: &Pubkey,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc self.rc
.accounts .accounts
.load_by_program(&self.ancestors, self.bank_id, program_id) .load_by_program(&self.ancestors, self.bank_id, program_id, config)
} }
pub fn get_filtered_program_accounts<F: Fn(&AccountSharedData) -> bool>( pub fn get_filtered_program_accounts<F: Fn(&AccountSharedData) -> bool>(
&self, &self,
program_id: &Pubkey, program_id: &Pubkey,
filter: F, filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc.accounts.load_by_program_with_filter( self.rc.accounts.load_by_program_with_filter(
&self.ancestors, &self.ancestors,
self.bank_id, self.bank_id,
program_id, program_id,
filter, filter,
config,
) )
} }
@ -5277,12 +5280,14 @@ impl Bank {
&self, &self,
index_key: &IndexKey, index_key: &IndexKey,
filter: F, filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> { ) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc.accounts.load_by_index_key_with_filter( self.rc.accounts.load_by_index_key_with_filter(
&self.ancestors, &self.ancestors,
self.bank_id, self.bank_id,
index_key, index_key,
filter, filter,
config,
) )
} }
@ -10495,11 +10500,15 @@ pub(crate) mod tests {
let bank1 = Arc::new(new_from_parent(&bank0)); let bank1 = Arc::new(new_from_parent(&bank0));
bank1.squash(); bank1.squash();
assert_eq!( assert_eq!(
bank0.get_program_accounts(&program_id).unwrap(), bank0
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap(),
vec![(pubkey0, account0.clone())] vec![(pubkey0, account0.clone())]
); );
assert_eq!( assert_eq!(
bank1.get_program_accounts(&program_id).unwrap(), bank1
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap(),
vec![(pubkey0, account0)] vec![(pubkey0, account0)]
); );
assert_eq!( assert_eq!(
@ -10518,8 +10527,20 @@ pub(crate) mod tests {
let bank3 = Arc::new(new_from_parent(&bank2)); let bank3 = Arc::new(new_from_parent(&bank2));
bank3.squash(); bank3.squash();
assert_eq!(bank1.get_program_accounts(&program_id).unwrap().len(), 2); assert_eq!(
assert_eq!(bank3.get_program_accounts(&program_id).unwrap().len(), 2); bank1
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap()
.len(),
2
);
assert_eq!(
bank3
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap()
.len(),
2
);
} }
#[test] #[test]
@ -10540,7 +10561,11 @@ pub(crate) mod tests {
bank.store_account(&address, &account); bank.store_account(&address, &account);
let indexed_accounts = bank let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(program_id), |_| true) .get_filtered_indexed_accounts(
&IndexKey::ProgramId(program_id),
|_| true,
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert_eq!(indexed_accounts.len(), 1); assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, account)); assert_eq!(indexed_accounts[0], (address, account));
@ -10553,27 +10578,39 @@ pub(crate) mod tests {
let bank = Arc::new(new_from_parent(&bank)); let bank = Arc::new(new_from_parent(&bank));
bank.store_account(&address, &new_account); bank.store_account(&address, &new_account);
let indexed_accounts = bank let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(program_id), |_| true) .get_filtered_indexed_accounts(
&IndexKey::ProgramId(program_id),
|_| true,
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert_eq!(indexed_accounts.len(), 1); assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account.clone())); assert_eq!(indexed_accounts[0], (address, new_account.clone()));
let indexed_accounts = bank let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(another_program_id), |_| true) .get_filtered_indexed_accounts(
&IndexKey::ProgramId(another_program_id),
|_| true,
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert_eq!(indexed_accounts.len(), 1); assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account.clone())); assert_eq!(indexed_accounts[0], (address, new_account.clone()));
// Post-processing filter // Post-processing filter
let indexed_accounts = bank let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(program_id), |account| { .get_filtered_indexed_accounts(
account.owner() == &program_id &IndexKey::ProgramId(program_id),
}) |account| account.owner() == &program_id,
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert!(indexed_accounts.is_empty()); assert!(indexed_accounts.is_empty());
let indexed_accounts = bank let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(another_program_id), |account| { .get_filtered_indexed_accounts(
account.owner() == &another_program_id &IndexKey::ProgramId(another_program_id),
}) |account| account.owner() == &another_program_id,
ScanConfig::default(),
)
.unwrap(); .unwrap();
assert_eq!(indexed_accounts.len(), 1); assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account)); assert_eq!(indexed_accounts[0], (address, new_account));
@ -13206,13 +13243,25 @@ pub(crate) mod tests {
let bank2 = let bank2 =
Bank::new_from_parent(&bank1, &Pubkey::default(), bank1.first_slot_in_next_epoch()); Bank::new_from_parent(&bank1, &Pubkey::default(), bank1.first_slot_in_next_epoch());
assert_eq!(bank2.get_program_accounts(&sysvar::id()).unwrap().len(), 8); assert_eq!(
bank2
.get_program_accounts(&sysvar::id(), ScanConfig::default(),)
.unwrap()
.len(),
8
);
// force rent collection for sysvars // force rent collection for sysvars
bank2.collect_rent_in_partition((0, 0, 1)); // all range bank2.collect_rent_in_partition((0, 0, 1)); // all range
// no sysvar should be deleted due to rent // no sysvar should be deleted due to rent
assert_eq!(bank2.get_program_accounts(&sysvar::id()).unwrap().len(), 8); assert_eq!(
bank2
.get_program_accounts(&sysvar::id(), ScanConfig::default(),)
.unwrap()
.len(),
8
);
} }
// this test can be removed after rent_for_sysvars activation on mainnet-beta // this test can be removed after rent_for_sysvars activation on mainnet-beta
@ -13245,7 +13294,9 @@ pub(crate) mod tests {
); );
{ {
let sysvars = bank1.get_program_accounts(&sysvar::id()).unwrap(); let sysvars = bank1
.get_program_accounts(&sysvar::id(), ScanConfig::default())
.unwrap();
assert_eq!(sysvars.len(), 8); assert_eq!(sysvars.len(), 8);
assert!(sysvars assert!(sysvars
.iter() .iter()
@ -13280,7 +13331,9 @@ pub(crate) mod tests {
); );
{ {
let sysvars = bank2.get_program_accounts(&sysvar::id()).unwrap(); let sysvars = bank2
.get_program_accounts(&sysvar::id(), ScanConfig::default())
.unwrap();
assert_eq!(sysvars.len(), 8); assert_eq!(sysvars.len(), 8);
assert!(sysvars assert!(sysvars
.iter() .iter()
@ -13357,7 +13410,9 @@ pub(crate) mod tests {
&feature::create_account(&Feature { activated_at: None }, feature_balance), &feature::create_account(&Feature { activated_at: None }, feature_balance),
); );
{ {
let sysvars = bank1.get_program_accounts(&sysvar::id()).unwrap(); let sysvars = bank1
.get_program_accounts(&sysvar::id(), ScanConfig::default())
.unwrap();
assert_eq!(sysvars.len(), 9); assert_eq!(sysvars.len(), 9);
assert!(sysvars assert!(sysvars
.iter() .iter()
@ -13392,7 +13447,9 @@ pub(crate) mod tests {
}, },
); );
{ {
let sysvars = bank2.get_program_accounts(&sysvar::id()).unwrap(); let sysvars = bank2
.get_program_accounts(&sysvar::id(), ScanConfig::default())
.unwrap();
assert_eq!(sysvars.len(), 9); assert_eq!(sysvars.len(), 9);
assert!(sysvars assert!(sysvars
.iter() .iter()
@ -13761,7 +13818,8 @@ pub(crate) mod tests {
bank_to_scan_receiver.recv_timeout(Duration::from_millis(10)) bank_to_scan_receiver.recv_timeout(Duration::from_millis(10))
{ {
info!("scanning program accounts for slot {}", bank_to_scan.slot()); info!("scanning program accounts for slot {}", bank_to_scan.slot());
let accounts_result = bank_to_scan.get_program_accounts(&program_id); let accounts_result = bank_to_scan
.get_program_accounts(&program_id, ScanConfig::default());
let _ = scan_finished_sender.send(bank_to_scan.bank_id()); let _ = scan_finished_sender.send(bank_to_scan.bank_id());
num_banks_scanned.fetch_add(1, Relaxed); num_banks_scanned.fetch_add(1, Relaxed);
match (&acceptable_scan_results, accounts_result.is_err()) { match (&acceptable_scan_results, accounts_result.is_err()) {

View File

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
accounts_index::{AccountIndex, IndexKey, ScanResult}, accounts_index::{AccountIndex, IndexKey, ScanConfig, ScanResult},
bank::Bank, bank::Bank,
}, },
log::*, log::*,
@ -28,6 +28,7 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> ScanResult<NonCircu
let withdraw_authority_list = withdraw_authority(); let withdraw_authority_list = withdraw_authority();
let clock = bank.clock(); let clock = bank.clock();
let config = ScanConfig::default();
let stake_accounts = if bank let stake_accounts = if bank
.rc .rc
.accounts .accounts
@ -42,9 +43,10 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> ScanResult<NonCircu
// zero-lamport Account::Default() after being wiped and reinitialized in later // zero-lamport Account::Default() after being wiped and reinitialized in later
// updates. We include the redundant filter here to avoid returning these accounts. // updates. We include the redundant filter here to avoid returning these accounts.
|account| account.owner() == &stake::program::id(), |account| account.owner() == &stake::program::id(),
config,
)? )?
} else { } else {
bank.get_program_accounts(&stake::program::id())? bank.get_program_accounts(&stake::program::id(), config)?
}; };
for (pubkey, account) in stake_accounts.iter() { for (pubkey, account) in stake_accounts.iter() {