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_runtime::{
accounts_db::AccountsDbConfig,
accounts_index::AccountsIndexConfig,
accounts_index::{AccountsIndexConfig, ScanConfig},
bank::{Bank, RewardCalculationEvent},
bank_forks::BankForks,
cost_model::CostModel,
@ -2251,7 +2251,7 @@ fn main() {
if remove_stake_accounts {
for (address, mut account) in bank
.get_program_accounts(&stake::program::id())
.get_program_accounts(&stake::program::id(), ScanConfig::default())
.unwrap()
.into_iter()
{
@ -2275,7 +2275,7 @@ fn main() {
if !vote_accounts_to_destake.is_empty() {
for (address, mut account) in bank
.get_program_accounts(&stake::program::id())
.get_program_accounts(&stake::program::id(), ScanConfig::default())
.unwrap()
.into_iter()
{
@ -2313,7 +2313,7 @@ fn main() {
// Delete existing vote accounts
for (address, mut account) in bank
.get_program_accounts(&solana_vote_program::id())
.get_program_accounts(&solana_vote_program::id(), ScanConfig::default())
.unwrap()
.into_iter()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ use crate::{
AccountShrinkThreshold, AccountsDbConfig, ErrorCounters, SnapshotStorages,
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,
ancestors::{Ancestors, AncestorsForSerialization},
blockhash_queue::BlockhashQueue,
@ -5254,22 +5254,25 @@ impl Bank {
pub fn get_program_accounts(
&self,
program_id: &Pubkey,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc
.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>(
&self,
program_id: &Pubkey,
filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc.accounts.load_by_program_with_filter(
&self.ancestors,
self.bank_id,
program_id,
filter,
config,
)
}
@ -5277,12 +5280,14 @@ impl Bank {
&self,
index_key: &IndexKey,
filter: F,
config: ScanConfig,
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
self.rc.accounts.load_by_index_key_with_filter(
&self.ancestors,
self.bank_id,
index_key,
filter,
config,
)
}
@ -10495,11 +10500,15 @@ pub(crate) mod tests {
let bank1 = Arc::new(new_from_parent(&bank0));
bank1.squash();
assert_eq!(
bank0.get_program_accounts(&program_id).unwrap(),
bank0
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap(),
vec![(pubkey0, account0.clone())]
);
assert_eq!(
bank1.get_program_accounts(&program_id).unwrap(),
bank1
.get_program_accounts(&program_id, ScanConfig::default(),)
.unwrap(),
vec![(pubkey0, account0)]
);
assert_eq!(
@ -10518,8 +10527,20 @@ pub(crate) mod tests {
let bank3 = Arc::new(new_from_parent(&bank2));
bank3.squash();
assert_eq!(bank1.get_program_accounts(&program_id).unwrap().len(), 2);
assert_eq!(bank3.get_program_accounts(&program_id).unwrap().len(), 2);
assert_eq!(
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]
@ -10540,7 +10561,11 @@ pub(crate) mod tests {
bank.store_account(&address, &account);
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();
assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, account));
@ -10553,27 +10578,39 @@ pub(crate) mod tests {
let bank = Arc::new(new_from_parent(&bank));
bank.store_account(&address, &new_account);
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();
assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account.clone()));
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();
assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account.clone()));
// Post-processing filter
let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(program_id), |account| {
account.owner() == &program_id
})
.get_filtered_indexed_accounts(
&IndexKey::ProgramId(program_id),
|account| account.owner() == &program_id,
ScanConfig::default(),
)
.unwrap();
assert!(indexed_accounts.is_empty());
let indexed_accounts = bank
.get_filtered_indexed_accounts(&IndexKey::ProgramId(another_program_id), |account| {
account.owner() == &another_program_id
})
.get_filtered_indexed_accounts(
&IndexKey::ProgramId(another_program_id),
|account| account.owner() == &another_program_id,
ScanConfig::default(),
)
.unwrap();
assert_eq!(indexed_accounts.len(), 1);
assert_eq!(indexed_accounts[0], (address, new_account));
@ -13206,13 +13243,25 @@ pub(crate) mod tests {
let bank2 =
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
bank2.collect_rent_in_partition((0, 0, 1)); // all range
// 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
@ -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!(sysvars
.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!(sysvars
.iter()
@ -13357,7 +13410,9 @@ pub(crate) mod tests {
&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!(sysvars
.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!(sysvars
.iter()
@ -13761,7 +13818,8 @@ pub(crate) mod tests {
bank_to_scan_receiver.recv_timeout(Duration::from_millis(10))
{
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());
num_banks_scanned.fetch_add(1, Relaxed);
match (&acceptable_scan_results, accounts_result.is_err()) {

View File

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