replace AccountsIndex btree with hashmap of 8k bins (#19212)
This commit is contained in:
committed by
GitHub
parent
4aaca73e42
commit
02b050e0f5
@ -802,6 +802,7 @@ impl Accounts {
|
|||||||
"load_to_collect_rent_eagerly_scan_elapsed",
|
"load_to_collect_rent_eagerly_scan_elapsed",
|
||||||
ancestors,
|
ancestors,
|
||||||
range,
|
range,
|
||||||
|
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)
|
||||||
},
|
},
|
||||||
|
@ -2643,6 +2643,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,
|
||||||
) -> A
|
) -> A
|
||||||
where
|
where
|
||||||
F: Fn(&mut A, (&Pubkey, LoadedAccount, Slot)),
|
F: Fn(&mut A, (&Pubkey, LoadedAccount, Slot)),
|
||||||
@ -2660,6 +2661,7 @@ impl AccountsDb {
|
|||||||
scan_func(&mut collector, (pubkey, loaded_account, slot));
|
scan_func(&mut collector, (pubkey, loaded_account, slot));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
collect_all_unsorted,
|
||||||
);
|
);
|
||||||
collector
|
collector
|
||||||
}
|
}
|
||||||
@ -2669,6 +2671,7 @@ impl AccountsDb {
|
|||||||
metric_name: &'static str,
|
metric_name: &'static str,
|
||||||
ancestors: &Ancestors,
|
ancestors: &Ancestors,
|
||||||
range: R,
|
range: R,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
scan_func: F,
|
scan_func: F,
|
||||||
) -> A
|
) -> A
|
||||||
where
|
where
|
||||||
@ -2681,6 +2684,7 @@ impl AccountsDb {
|
|||||||
metric_name,
|
metric_name,
|
||||||
ancestors,
|
ancestors,
|
||||||
range,
|
range,
|
||||||
|
collect_all_unsorted,
|
||||||
|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.
|
||||||
@ -4589,7 +4593,11 @@ impl AccountsDb {
|
|||||||
.accounts_index
|
.accounts_index
|
||||||
.account_maps
|
.account_maps
|
||||||
.iter()
|
.iter()
|
||||||
.map(|btree| btree.read().unwrap().keys().cloned().collect::<Vec<_>>())
|
.map(|map| {
|
||||||
|
let mut keys = map.read().unwrap().keys().cloned().collect::<Vec<_>>();
|
||||||
|
keys.sort_unstable(); // hashmap is not ordered, but bins are relative to each other
|
||||||
|
keys
|
||||||
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
collect.stop();
|
collect.stop();
|
||||||
@ -7152,6 +7160,8 @@ 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();
|
||||||
@ -7182,6 +7192,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,
|
||||||
);
|
);
|
||||||
assert_eq!(accounts, vec![account1]);
|
assert_eq!(accounts, vec![account1]);
|
||||||
}
|
}
|
||||||
@ -8717,6 +8728,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,
|
||||||
);
|
);
|
||||||
assert_eq!(accounts, vec![account0]);
|
assert_eq!(accounts, vec![account0]);
|
||||||
|
|
||||||
@ -8727,6 +8739,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,
|
||||||
);
|
);
|
||||||
assert_eq!(accounts.len(), 2);
|
assert_eq!(accounts.len(), 2);
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,7 @@ use solana_sdk::{
|
|||||||
pubkey::{Pubkey, PUBKEY_BYTES},
|
pubkey::{Pubkey, PUBKEY_BYTES},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{
|
collections::{btree_map::BTreeMap, hash_map::Entry, HashMap, HashSet},
|
||||||
btree_map::{self, BTreeMap, Entry},
|
|
||||||
HashSet,
|
|
||||||
},
|
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
ops::{
|
ops::{
|
||||||
Bound,
|
Bound,
|
||||||
@ -32,7 +29,7 @@ use std::{
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub const ITER_BATCH_SIZE: usize = 1000;
|
pub const ITER_BATCH_SIZE: usize = 1000;
|
||||||
pub const BINS_DEFAULT: usize = 16;
|
pub const BINS_DEFAULT: usize = 8192;
|
||||||
pub const ACCOUNTS_INDEX_CONFIG_FOR_TESTING: AccountsIndexConfig = AccountsIndexConfig {
|
pub const ACCOUNTS_INDEX_CONFIG_FOR_TESTING: AccountsIndexConfig = AccountsIndexConfig {
|
||||||
bins: Some(BINS_DEFAULT),
|
bins: Some(BINS_DEFAULT),
|
||||||
};
|
};
|
||||||
@ -43,7 +40,7 @@ pub type ScanResult<T> = Result<T, ScanError>;
|
|||||||
pub type SlotList<T> = Vec<(Slot, T)>;
|
pub type SlotList<T> = Vec<(Slot, T)>;
|
||||||
pub type SlotSlice<'s, T> = &'s [(Slot, T)];
|
pub type SlotSlice<'s, T> = &'s [(Slot, T)];
|
||||||
pub type RefCount = u64;
|
pub type RefCount = u64;
|
||||||
pub type AccountMap<K, V> = BTreeMap<K, V>;
|
pub type AccountMap<K, V> = HashMap<K, V>;
|
||||||
|
|
||||||
type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>;
|
type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>;
|
||||||
|
|
||||||
@ -624,9 +621,30 @@ pub struct AccountsIndexIterator<'a, T> {
|
|||||||
start_bound: Bound<Pubkey>,
|
start_bound: Bound<Pubkey>,
|
||||||
end_bound: Bound<Pubkey>,
|
end_bound: Bound<Pubkey>,
|
||||||
is_finished: bool,
|
is_finished: bool,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> AccountsIndexIterator<'a, T> {
|
impl<'a, T> AccountsIndexIterator<'a, T> {
|
||||||
|
fn range<'b, R>(
|
||||||
|
map: &'b AccountMapsReadLock<'b, T>,
|
||||||
|
range: R,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
|
) -> Vec<(&'b Pubkey, &'b AccountMapEntry<T>)>
|
||||||
|
where
|
||||||
|
R: RangeBounds<Pubkey>,
|
||||||
|
{
|
||||||
|
let mut result = Vec::with_capacity(map.len());
|
||||||
|
for (k, v) in map.iter() {
|
||||||
|
if range.contains(k) {
|
||||||
|
result.push((k, v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !collect_all_unsorted {
|
||||||
|
result.sort_unstable_by(|a, b| a.0.cmp(b.0));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn clone_bound(bound: Bound<&Pubkey>) -> Bound<Pubkey> {
|
fn clone_bound(bound: Bound<&Pubkey>) -> Bound<Pubkey> {
|
||||||
match bound {
|
match bound {
|
||||||
Unbounded => Unbounded,
|
Unbounded => Unbounded,
|
||||||
@ -670,7 +688,7 @@ impl<'a, T> AccountsIndexIterator<'a, T> {
|
|||||||
(start_bin, bin_range)
|
(start_bin, bin_range)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<R>(index: &'a AccountsIndex<T>, range: Option<R>) -> Self
|
pub fn new<R>(index: &'a AccountsIndex<T>, range: Option<R>, collect_all_unsorted: bool) -> Self
|
||||||
where
|
where
|
||||||
R: RangeBounds<Pubkey>,
|
R: RangeBounds<Pubkey>,
|
||||||
{
|
{
|
||||||
@ -686,6 +704,7 @@ impl<'a, T> AccountsIndexIterator<'a, T> {
|
|||||||
account_maps: &index.account_maps,
|
account_maps: &index.account_maps,
|
||||||
is_finished: false,
|
is_finished: false,
|
||||||
bin_calculator: &index.bin_calculator,
|
bin_calculator: &index.bin_calculator,
|
||||||
|
collect_all_unsorted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,10 +718,12 @@ impl<'a, T: 'static + Clone> Iterator for AccountsIndexIterator<'a, T> {
|
|||||||
let (start_bin, bin_range) = self.bin_start_and_range();
|
let (start_bin, bin_range) = self.bin_start_and_range();
|
||||||
let mut chunk: Vec<(Pubkey, AccountMapEntry<T>)> = Vec::with_capacity(ITER_BATCH_SIZE);
|
let mut chunk: Vec<(Pubkey, AccountMapEntry<T>)> = Vec::with_capacity(ITER_BATCH_SIZE);
|
||||||
'outer: for i in self.account_maps.iter().skip(start_bin).take(bin_range) {
|
'outer: for i in self.account_maps.iter().skip(start_bin).take(bin_range) {
|
||||||
for (pubkey, account_map_entry) in
|
for (pubkey, account_map_entry) in Self::range(
|
||||||
i.read().unwrap().range((self.start_bound, self.end_bound))
|
&i.read().unwrap(),
|
||||||
{
|
(self.start_bound, self.end_bound),
|
||||||
if chunk.len() >= ITER_BATCH_SIZE {
|
self.collect_all_unsorted,
|
||||||
|
) {
|
||||||
|
if chunk.len() >= ITER_BATCH_SIZE && !self.collect_all_unsorted {
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
let item = (*pubkey, account_map_entry.clone());
|
let item = (*pubkey, account_map_entry.clone());
|
||||||
@ -713,6 +734,8 @@ impl<'a, T: 'static + Clone> Iterator for AccountsIndexIterator<'a, T> {
|
|||||||
if chunk.is_empty() {
|
if chunk.is_empty() {
|
||||||
self.is_finished = true;
|
self.is_finished = true;
|
||||||
return None;
|
return None;
|
||||||
|
} else if self.collect_all_unsorted {
|
||||||
|
self.is_finished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_bound = Excluded(chunk.last().unwrap().0);
|
self.start_bound = Excluded(chunk.last().unwrap().0);
|
||||||
@ -807,11 +830,11 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
(account_maps, bin_calculator)
|
(account_maps, bin_calculator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter<R>(&self, range: Option<R>) -> AccountsIndexIterator<T>
|
fn iter<R>(&self, range: Option<R>, collect_all_unsorted: bool) -> AccountsIndexIterator<T>
|
||||||
where
|
where
|
||||||
R: RangeBounds<Pubkey>,
|
R: RangeBounds<Pubkey>,
|
||||||
{
|
{
|
||||||
AccountsIndexIterator::new(self, range)
|
AccountsIndexIterator::new(self, range, collect_all_unsorted)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_checked_scan_accounts<F, R>(
|
fn do_checked_scan_accounts<F, R>(
|
||||||
@ -821,6 +844,7 @@ impl<T: IsCached> 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,
|
||||||
) -> Result<(), ScanError>
|
) -> Result<(), ScanError>
|
||||||
where
|
where
|
||||||
F: FnMut(&Pubkey, (&T, Slot)),
|
F: FnMut(&Pubkey, (&T, Slot)),
|
||||||
@ -973,7 +997,14 @@ impl<T: IsCached> 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(metric_name, ancestors, func, range, Some(max_root));
|
self.do_scan_accounts(
|
||||||
|
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(
|
||||||
@ -1037,11 +1068,19 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
ancestors: &Ancestors,
|
ancestors: &Ancestors,
|
||||||
func: F,
|
func: F,
|
||||||
range: Option<R>,
|
range: Option<R>,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&Pubkey, (&T, Slot)),
|
F: FnMut(&Pubkey, (&T, Slot)),
|
||||||
R: RangeBounds<Pubkey>,
|
R: RangeBounds<Pubkey>,
|
||||||
{
|
{
|
||||||
self.do_scan_accounts(metric_name, ancestors, func, range, None);
|
self.do_scan_accounts(
|
||||||
|
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:
|
||||||
@ -1054,6 +1093,7 @@ impl<T: IsCached> 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,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&Pubkey, (&T, Slot)),
|
F: FnMut(&Pubkey, (&T, Slot)),
|
||||||
R: RangeBounds<Pubkey>,
|
R: RangeBounds<Pubkey>,
|
||||||
@ -1067,7 +1107,7 @@ impl<T: IsCached> 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) {
|
for pubkey_list in self.iter(range, 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 {
|
||||||
@ -1185,7 +1225,7 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
if !dead_keys.is_empty() {
|
if !dead_keys.is_empty() {
|
||||||
for key in dead_keys.iter() {
|
for key in dead_keys.iter() {
|
||||||
let mut w_index = self.get_account_maps_write_lock(key);
|
let mut w_index = self.get_account_maps_write_lock(key);
|
||||||
if let btree_map::Entry::Occupied(index_entry) = w_index.entry(**key) {
|
if let Entry::Occupied(index_entry) = w_index.entry(**key) {
|
||||||
if index_entry.get().slot_list.read().unwrap().is_empty() {
|
if index_entry.get().slot_list.read().unwrap().is_empty() {
|
||||||
index_entry.remove();
|
index_entry.remove();
|
||||||
|
|
||||||
@ -1209,6 +1249,7 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
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(
|
||||||
"",
|
"",
|
||||||
@ -1216,6 +1257,7 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
scan_bank_id,
|
scan_bank_id,
|
||||||
func,
|
func,
|
||||||
ScanTypes::Unindexed(None::<Range<Pubkey>>),
|
ScanTypes::Unindexed(None::<Range<Pubkey>>),
|
||||||
|
collect_all_unsorted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,10 +1266,17 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
metric_name: &'static str,
|
metric_name: &'static str,
|
||||||
ancestors: &Ancestors,
|
ancestors: &Ancestors,
|
||||||
func: F,
|
func: F,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&Pubkey, (&T, Slot)),
|
F: FnMut(&Pubkey, (&T, Slot)),
|
||||||
{
|
{
|
||||||
self.do_unchecked_scan_accounts(metric_name, ancestors, func, None::<Range<Pubkey>>);
|
self.do_unchecked_scan_accounts(
|
||||||
|
metric_name,
|
||||||
|
ancestors,
|
||||||
|
func,
|
||||||
|
None::<Range<Pubkey>>,
|
||||||
|
collect_all_unsorted,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// call func with every pubkey and index visible from a given set of ancestors with range
|
/// call func with every pubkey and index visible from a given set of ancestors with range
|
||||||
@ -1236,13 +1285,20 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
metric_name: &'static str,
|
metric_name: &'static str,
|
||||||
ancestors: &Ancestors,
|
ancestors: &Ancestors,
|
||||||
range: R,
|
range: R,
|
||||||
|
collect_all_unsorted: bool,
|
||||||
func: F,
|
func: F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&Pubkey, (&T, Slot)),
|
F: FnMut(&Pubkey, (&T, Slot)),
|
||||||
R: RangeBounds<Pubkey>,
|
R: RangeBounds<Pubkey>,
|
||||||
{
|
{
|
||||||
// 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(metric_name, ancestors, func, Some(range));
|
self.do_unchecked_scan_accounts(
|
||||||
|
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
|
||||||
@ -1256,6 +1312,8 @@ impl<T: IsCached> AccountsIndex<T> {
|
|||||||
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(
|
||||||
"",
|
"",
|
||||||
@ -1263,6 +1321,7 @@ impl<T: IsCached> 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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2584,6 +2643,8 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const COLLECT_ALL_UNSORTED_FALSE: bool = false;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_empty() {
|
fn test_get_empty() {
|
||||||
let key = Keypair::new();
|
let key = Keypair::new();
|
||||||
@ -2593,7 +2654,12 @@ pub mod tests {
|
|||||||
assert!(index.get(&key.pubkey(), None, None).is_none());
|
assert!(index.get(&key.pubkey(), None, None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2666,7 +2732,12 @@ pub mod tests {
|
|||||||
assert!(index.get(&key.pubkey(), None, None).is_none());
|
assert!(index.get(&key.pubkey(), None, None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2699,12 +2770,22 @@ pub mod tests {
|
|||||||
assert!(index.get(pubkey, None, None).is_none());
|
assert!(index.get(pubkey, None, None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
ancestors.insert(slot, 0);
|
ancestors.insert(slot, 0);
|
||||||
assert!(index.get(pubkey, Some(&ancestors), None).is_some());
|
assert!(index.get(pubkey, Some(&ancestors), None).is_some());
|
||||||
assert_eq!(index.ref_count_from_storage(pubkey), 1);
|
assert_eq!(index.ref_count_from_storage(pubkey), 1);
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 1);
|
assert_eq!(num, 1);
|
||||||
|
|
||||||
// not zero lamports
|
// not zero lamports
|
||||||
@ -2718,12 +2799,22 @@ pub mod tests {
|
|||||||
assert!(index.get(pubkey, None, None).is_none());
|
assert!(index.get(pubkey, None, None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
ancestors.insert(slot, 0);
|
ancestors.insert(slot, 0);
|
||||||
assert!(index.get(pubkey, Some(&ancestors), None).is_some());
|
assert!(index.get(pubkey, Some(&ancestors), None).is_some());
|
||||||
assert_eq!(index.ref_count_from_storage(pubkey), 0); // cached, so 0
|
assert_eq!(index.ref_count_from_storage(pubkey), 0); // cached, so 0
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 1);
|
assert_eq!(num, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2915,11 +3006,21 @@ pub mod tests {
|
|||||||
assert!(index.get(&key.pubkey(), None, None).is_none());
|
assert!(index.get(&key.pubkey(), None, None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
ancestors.insert(slot, 0);
|
ancestors.insert(slot, 0);
|
||||||
assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_some());
|
assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_some());
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 1);
|
assert_eq!(num, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2944,7 +3045,12 @@ pub mod tests {
|
|||||||
assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
|
assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
|
||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |_pubkey, _index| num += 1);
|
index.unchecked_scan_accounts(
|
||||||
|
"",
|
||||||
|
&ancestors,
|
||||||
|
|_pubkey, _index| num += 1,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 0);
|
assert_eq!(num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2971,12 +3077,17 @@ pub mod tests {
|
|||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
let mut found_key = false;
|
let mut found_key = false;
|
||||||
index.unchecked_scan_accounts("", &ancestors, |pubkey, _index| {
|
index.unchecked_scan_accounts(
|
||||||
if pubkey == &key.pubkey() {
|
"",
|
||||||
found_key = true
|
&ancestors,
|
||||||
};
|
|pubkey, _index| {
|
||||||
num += 1
|
if pubkey == &key.pubkey() {
|
||||||
});
|
found_key = true
|
||||||
|
};
|
||||||
|
num += 1
|
||||||
|
},
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 1);
|
assert_eq!(num, 1);
|
||||||
assert!(found_key);
|
assert!(found_key);
|
||||||
}
|
}
|
||||||
@ -3044,9 +3155,15 @@ pub mod tests {
|
|||||||
|
|
||||||
let ancestors = Ancestors::default();
|
let ancestors = Ancestors::default();
|
||||||
let mut scanned_keys = HashSet::new();
|
let mut scanned_keys = HashSet::new();
|
||||||
index.range_scan_accounts("", &ancestors, pubkey_range, |pubkey, _index| {
|
index.range_scan_accounts(
|
||||||
scanned_keys.insert(*pubkey);
|
"",
|
||||||
});
|
&ancestors,
|
||||||
|
pubkey_range,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
|pubkey, _index| {
|
||||||
|
scanned_keys.insert(*pubkey);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let mut expected_len = 0;
|
let mut expected_len = 0;
|
||||||
for key in &pubkeys[index_start..index_end] {
|
for key in &pubkeys[index_start..index_end] {
|
||||||
@ -3115,9 +3232,14 @@ pub mod tests {
|
|||||||
let ancestors = Ancestors::default();
|
let ancestors = Ancestors::default();
|
||||||
|
|
||||||
let mut scanned_keys = HashSet::new();
|
let mut scanned_keys = HashSet::new();
|
||||||
index.unchecked_scan_accounts("", &ancestors, |pubkey, _index| {
|
index.unchecked_scan_accounts(
|
||||||
scanned_keys.insert(*pubkey);
|
"",
|
||||||
});
|
&ancestors,
|
||||||
|
|pubkey, _index| {
|
||||||
|
scanned_keys.insert(*pubkey);
|
||||||
|
},
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(scanned_keys.len(), num_pubkeys);
|
assert_eq!(scanned_keys.len(), num_pubkeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3133,7 +3255,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_accounts_iter_finished() {
|
fn test_accounts_iter_finished() {
|
||||||
let (index, _) = setup_accounts_index_keys(0);
|
let (index, _) = setup_accounts_index_keys(0);
|
||||||
let mut iter = index.iter(None::<Range<Pubkey>>);
|
let mut iter = index.iter(None::<Range<Pubkey>>, COLLECT_ALL_UNSORTED_FALSE);
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
let mut gc = vec![];
|
let mut gc = vec![];
|
||||||
index.upsert(
|
index.upsert(
|
||||||
@ -3412,13 +3534,18 @@ pub mod tests {
|
|||||||
|
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
let mut found_key = false;
|
let mut found_key = false;
|
||||||
index.unchecked_scan_accounts("", &Ancestors::default(), |pubkey, _index| {
|
index.unchecked_scan_accounts(
|
||||||
if pubkey == &key.pubkey() {
|
"",
|
||||||
found_key = true;
|
&Ancestors::default(),
|
||||||
assert_eq!(_index, (&true, 3));
|
|pubkey, _index| {
|
||||||
};
|
if pubkey == &key.pubkey() {
|
||||||
num += 1
|
found_key = true;
|
||||||
});
|
assert_eq!(_index, (&true, 3));
|
||||||
|
};
|
||||||
|
num += 1
|
||||||
|
},
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(num, 1);
|
assert_eq!(num, 1);
|
||||||
assert!(found_key);
|
assert!(found_key);
|
||||||
}
|
}
|
||||||
@ -3976,20 +4103,40 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_bin_start_and_range() {
|
fn test_bin_start_and_range() {
|
||||||
let index = AccountsIndex::<bool>::default_for_tests();
|
let index = AccountsIndex::<bool>::default_for_tests();
|
||||||
let iter = AccountsIndexIterator::new(&index, None::<RangeInclusive<Pubkey>>);
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
None::<RangeInclusive<Pubkey>>,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!((0, usize::MAX), iter.bin_start_and_range());
|
assert_eq!((0, usize::MAX), iter.bin_start_and_range());
|
||||||
|
|
||||||
let key_0 = Pubkey::new(&[0; 32]);
|
let key_0 = Pubkey::new(&[0; 32]);
|
||||||
let key_ff = Pubkey::new(&[0xff; 32]);
|
let key_ff = Pubkey::new(&[0xff; 32]);
|
||||||
|
|
||||||
let iter = AccountsIndexIterator::new(&index, Some(RangeInclusive::new(key_0, key_ff)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some(RangeInclusive::new(key_0, key_ff)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
let bins = index.bins();
|
let bins = index.bins();
|
||||||
assert_eq!((0, bins), iter.bin_start_and_range());
|
assert_eq!((0, bins), iter.bin_start_and_range());
|
||||||
let iter = AccountsIndexIterator::new(&index, Some(RangeInclusive::new(key_ff, key_0)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some(RangeInclusive::new(key_ff, key_0)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!((bins - 1, 0), iter.bin_start_and_range());
|
assert_eq!((bins - 1, 0), iter.bin_start_and_range());
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Included(key_0), Unbounded)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Included(key_0), Unbounded)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!((0, usize::MAX), iter.bin_start_and_range());
|
assert_eq!((0, usize::MAX), iter.bin_start_and_range());
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Included(key_ff), Unbounded)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Included(key_ff), Unbounded)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!((bins - 1, usize::MAX), iter.bin_start_and_range());
|
assert_eq!((bins - 1, usize::MAX), iter.bin_start_and_range());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -4006,30 +4153,58 @@ pub mod tests {
|
|||||||
fn test_start_end_bin() {
|
fn test_start_end_bin() {
|
||||||
let index = AccountsIndex::<bool>::default_for_tests();
|
let index = AccountsIndex::<bool>::default_for_tests();
|
||||||
assert_eq!(index.bins(), BINS_DEFAULT);
|
assert_eq!(index.bins(), BINS_DEFAULT);
|
||||||
let iter = AccountsIndexIterator::new(&index, None::<RangeInclusive<Pubkey>>);
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
None::<RangeInclusive<Pubkey>>,
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), 0); // no range, so 0
|
assert_eq!(iter.start_bin(), 0); // no range, so 0
|
||||||
assert_eq!(iter.end_bin_inclusive(), usize::MAX); // no range, so max
|
assert_eq!(iter.end_bin_inclusive(), usize::MAX); // no range, so max
|
||||||
|
|
||||||
let key = Pubkey::new(&[0; 32]);
|
let key = Pubkey::new(&[0; 32]);
|
||||||
let iter = AccountsIndexIterator::new(&index, Some(RangeInclusive::new(key, key)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some(RangeInclusive::new(key, key)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
||||||
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Included(key), Excluded(key))));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Included(key), Excluded(key))),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
||||||
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Excluded(key), Excluded(key))));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Excluded(key), Excluded(key))),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
|
||||||
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
|
||||||
|
|
||||||
let key = Pubkey::new(&[0xff; 32]);
|
let key = Pubkey::new(&[0xff; 32]);
|
||||||
let iter = AccountsIndexIterator::new(&index, Some(RangeInclusive::new(key, key)));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some(RangeInclusive::new(key, key)),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
let bins = index.bins();
|
let bins = index.bins();
|
||||||
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
||||||
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Included(key), Excluded(key))));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Included(key), Excluded(key))),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
||||||
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
||||||
let iter = AccountsIndexIterator::new(&index, Some((Excluded(key), Excluded(key))));
|
let iter = AccountsIndexIterator::new(
|
||||||
|
&index,
|
||||||
|
Some((Excluded(key), Excluded(key))),
|
||||||
|
COLLECT_ALL_UNSORTED_FALSE,
|
||||||
|
);
|
||||||
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
|
||||||
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
assert_eq!(iter.end_bin_inclusive(), bins - 1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user