2021-12-03 09:00:31 -08:00
use {
crate ::{
2022-03-23 09:53:37 -07:00
accounts_index_storage ::{ AccountsIndexStorage , Startup } ,
2021-12-03 09:00:31 -08:00
ancestors ::Ancestors ,
bucket_map_holder ::{ Age , BucketMapHolder } ,
contains ::Contains ,
in_mem_accounts_index ::{ InMemAccountsIndex , InsertNewEntryResults } ,
2022-02-16 16:23:25 -08:00
inline_spl_token ::{ self , GenericTokenAccount } ,
inline_spl_token_2022 ,
2021-12-03 09:00:31 -08:00
pubkey_bins ::PubkeyBinCalculator24 ,
2022-03-25 08:37:00 -07:00
rolling_bit_field ::RollingBitField ,
2021-12-03 09:00:31 -08:00
secondary_index ::* ,
} ,
log ::* ,
ouroboros ::self_referencing ,
rand ::{ thread_rng , Rng } ,
2021-12-21 15:31:48 -08:00
rayon ::{
iter ::{ IntoParallelIterator , ParallelIterator } ,
ThreadPool ,
} ,
2021-12-03 09:00:31 -08:00
solana_measure ::measure ::Measure ,
solana_sdk ::{
2022-02-23 15:01:23 -08:00
account ::ReadableAccount ,
2021-12-03 09:00:31 -08:00
clock ::{ BankId , Slot } ,
2022-02-16 16:23:25 -08:00
pubkey ::Pubkey ,
2020-12-31 18:06:03 -08:00
} ,
2021-12-03 09:00:31 -08:00
std ::{
collections ::{ btree_map ::BTreeMap , HashSet } ,
fmt ::Debug ,
ops ::{
Bound ,
Bound ::{ Excluded , Included , Unbounded } ,
Range , RangeBounds ,
} ,
path ::PathBuf ,
sync ::{
atomic ::{ AtomicBool , AtomicU64 , AtomicU8 , Ordering } ,
Arc , Mutex , RwLock , RwLockReadGuard , RwLockWriteGuard ,
} ,
2020-12-31 18:06:03 -08:00
} ,
2021-12-03 09:00:31 -08:00
thiserror ::Error ,
2020-01-28 17:03:20 -08:00
} ;
2020-12-31 18:06:03 -08:00
2020-11-16 17:23:11 -08:00
pub const ITER_BATCH_SIZE : usize = 1000 ;
2021-08-26 16:12:43 -07:00
pub const BINS_DEFAULT : usize = 8192 ;
2021-09-18 07:53:44 -07:00
pub const BINS_FOR_TESTING : usize = 2 ; // we want > 1, but each bin is a few disk files with a disk based index, so fewer is better
2022-05-06 11:35:18 -07:00
pub const BINS_FOR_BENCHMARKS : usize = 8192 ;
2021-09-17 15:02:43 -07:00
pub const FLUSH_THREADS_TESTING : usize = 1 ;
2021-08-17 12:50:01 -07:00
pub const ACCOUNTS_INDEX_CONFIG_FOR_TESTING : AccountsIndexConfig = AccountsIndexConfig {
2021-08-30 16:40:10 -07:00
bins : Some ( BINS_FOR_TESTING ) ,
2021-09-17 15:02:43 -07:00
flush_threads : Some ( FLUSH_THREADS_TESTING ) ,
2021-09-18 07:54:57 -07:00
drives : None ,
2022-04-12 07:38:09 -07:00
index_limit_mb : IndexLimitMb ::Unspecified ,
2021-09-19 18:22:09 -07:00
ages_to_stay_in_cache : None ,
2021-11-19 07:00:19 -08:00
scan_results_limit_bytes : None ,
2022-02-22 07:40:12 -08:00
started_from_validator : false ,
2021-08-17 12:50:01 -07:00
} ;
pub const ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS : AccountsIndexConfig = AccountsIndexConfig {
2021-08-30 16:40:10 -07:00
bins : Some ( BINS_FOR_BENCHMARKS ) ,
2021-09-17 15:02:43 -07:00
flush_threads : Some ( FLUSH_THREADS_TESTING ) ,
2021-09-18 07:54:57 -07:00
drives : None ,
2022-04-12 07:38:09 -07:00
index_limit_mb : IndexLimitMb ::Unspecified ,
2021-09-19 18:22:09 -07:00
ages_to_stay_in_cache : None ,
2021-11-19 07:00:19 -08:00
scan_results_limit_bytes : None ,
2022-02-22 07:40:12 -08:00
started_from_validator : false ,
2021-08-17 12:50:01 -07:00
} ;
2021-06-14 21:04:01 -07:00
pub type ScanResult < T > = Result < T , ScanError > ;
2020-03-25 21:08:56 -07:00
pub type SlotList < T > = Vec < ( Slot , T ) > ;
pub type SlotSlice < ' s , T > = & ' s [ ( Slot , T ) ] ;
2020-03-12 22:14:37 -07:00
pub type RefCount = u64 ;
2021-09-15 10:36:08 -07:00
pub type AccountMap < V > = Arc < InMemAccountsIndex < V > > ;
2019-04-15 17:15:50 -07:00
2021-11-17 11:10:29 -08:00
#[ derive(Debug, Default) ]
pub struct ScanConfig {
/// checked by the scan. When true, abort scan.
2021-11-19 07:00:19 -08:00
pub abort : Option < Arc < AtomicBool > > ,
2021-11-17 11:10:29 -08:00
/// true to allow return of all matching items and allow them to be unsorted.
/// This is more efficient.
2021-11-19 07:00:19 -08:00
pub collect_all_unsorted : bool ,
2021-11-17 11:10:29 -08:00
}
impl ScanConfig {
pub fn new ( collect_all_unsorted : bool ) -> Self {
Self {
collect_all_unsorted ,
.. ScanConfig ::default ( )
}
}
2021-12-08 12:09:34 -08:00
/// mark the scan as aborted
2021-11-19 07:00:19 -08:00
pub fn abort ( & self ) {
if let Some ( abort ) = self . abort . as_ref ( ) {
abort . store ( true , Ordering ::Relaxed )
}
}
2021-12-08 12:09:34 -08:00
/// use existing 'abort' if available, otherwise allocate one
pub fn recreate_with_abort ( & self ) -> Self {
ScanConfig {
abort : Some ( self . abort . as_ref ( ) . map ( Arc ::clone ) . unwrap_or_default ( ) ) ,
collect_all_unsorted : self . collect_all_unsorted ,
}
}
2021-11-17 11:10:29 -08:00
/// 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
}
}
}
2021-09-10 19:09:51 -07:00
pub ( crate ) type AccountMapEntry < T > = Arc < AccountMapEntryInner < T > > ;
2020-10-21 17:05:27 -07:00
2021-12-01 10:19:06 -08:00
pub trait IsCached {
2021-01-11 17:00:23 -08:00
fn is_cached ( & self ) -> bool ;
}
2021-09-14 15:51:07 -07:00
pub trait IndexValue :
'static + IsCached + Clone + Debug + PartialEq + ZeroLamport + Copy + Default + Sync + Send
{
}
2022-05-22 18:00:42 -07:00
#[ derive(Error, Debug, PartialEq, Eq) ]
2021-06-14 21:04:01 -07:00
pub enum ScanError {
#[ error( " Node detected it replayed bad version of slot {slot:?} with id {bank_id:?}, thus the scan on said slot was aborted " ) ]
SlotRemoved { slot : Slot , bank_id : BankId } ,
2021-11-19 07:00:19 -08:00
#[ error( " scan aborted: {0} " ) ]
Aborted ( String ) ,
2021-06-14 21:04:01 -07:00
}
2020-12-31 18:06:03 -08:00
enum ScanTypes < R : RangeBounds < Pubkey > > {
Unindexed ( Option < R > ) ,
Indexed ( IndexKey ) ,
}
#[ derive(Debug, Clone, Copy) ]
pub enum IndexKey {
ProgramId ( Pubkey ) ,
SplTokenMint ( Pubkey ) ,
SplTokenOwner ( Pubkey ) ,
}
#[ derive(Debug, Clone, PartialEq, Eq, Hash) ]
pub enum AccountIndex {
ProgramId ,
SplTokenMint ,
SplTokenOwner ,
}
2021-05-11 15:06:22 -07:00
#[ derive(Debug, PartialEq, Eq, Clone) ]
pub struct AccountSecondaryIndexesIncludeExclude {
pub exclude : bool ,
pub keys : HashSet < Pubkey > ,
}
2022-04-12 07:38:09 -07:00
/// specification of how much memory in-mem portion of account index can use
#[ derive(Debug, Clone) ]
pub enum IndexLimitMb {
/// nothing explicit specified, so default
Unspecified ,
/// limit was specified, use disk index for rest
Limit ( usize ) ,
/// in-mem-only was specified, no disk index
InMemOnly ,
}
impl Default for IndexLimitMb {
fn default ( ) -> Self {
Self ::Unspecified
}
}
2021-09-07 18:09:40 -07:00
#[ derive(Debug, Default, Clone) ]
2021-08-17 12:50:01 -07:00
pub struct AccountsIndexConfig {
pub bins : Option < usize > ,
2021-09-17 15:02:43 -07:00
pub flush_threads : Option < usize > ,
2021-09-18 07:54:57 -07:00
pub drives : Option < Vec < PathBuf > > ,
2022-04-12 07:38:09 -07:00
pub index_limit_mb : IndexLimitMb ,
2021-09-19 18:22:09 -07:00
pub ages_to_stay_in_cache : Option < Age > ,
2021-11-19 07:00:19 -08:00
pub scan_results_limit_bytes : Option < usize > ,
2022-02-22 07:40:12 -08:00
/// true if the accounts index is being created as a result of being started as a validator (as opposed to test, etc.)
pub started_from_validator : bool ,
2021-08-17 12:50:01 -07:00
}
2021-05-11 15:06:22 -07:00
#[ derive(Debug, Default, Clone) ]
pub struct AccountSecondaryIndexes {
pub keys : Option < AccountSecondaryIndexesIncludeExclude > ,
pub indexes : HashSet < AccountIndex > ,
}
impl AccountSecondaryIndexes {
pub fn is_empty ( & self ) -> bool {
self . indexes . is_empty ( )
}
pub fn contains ( & self , index : & AccountIndex ) -> bool {
self . indexes . contains ( index )
}
pub fn include_key ( & self , key : & Pubkey ) -> bool {
match & self . keys {
Some ( options ) = > options . exclude ^ options . keys . contains ( key ) ,
None = > true , // include all keys
}
}
}
2021-05-10 07:22:48 -07:00
2021-09-16 19:36:23 -07:00
#[ derive(Debug, Default) ]
2022-02-28 13:00:53 -08:00
/// data per entry in in-mem accounts index
/// used to keep track of consistency with disk index
2021-09-16 19:36:23 -07:00
pub struct AccountMapEntryMeta {
2022-02-28 13:00:53 -08:00
/// true if entry in in-mem idx has changes and needs to be written to disk
2021-09-16 19:36:23 -07:00
pub dirty : AtomicBool ,
2022-02-28 13:00:53 -08:00
/// 'age' at which this entry should be purged from the cache (implements lru)
2021-09-18 07:56:26 -07:00
pub age : AtomicU8 ,
2021-09-16 19:36:23 -07:00
}
impl AccountMapEntryMeta {
2021-09-19 18:22:09 -07:00
pub fn new_dirty < T : IndexValue > ( storage : & Arc < BucketMapHolder < T > > ) -> Self {
2021-09-16 19:36:23 -07:00
AccountMapEntryMeta {
dirty : AtomicBool ::new ( true ) ,
2021-09-19 18:22:09 -07:00
age : AtomicU8 ::new ( storage . future_age_to_flush ( ) ) ,
2021-09-16 19:36:23 -07:00
}
}
2022-02-24 08:17:35 -08:00
pub fn new_clean < T : IndexValue > ( storage : & Arc < BucketMapHolder < T > > ) -> Self {
AccountMapEntryMeta {
dirty : AtomicBool ::new ( false ) ,
age : AtomicU8 ::new ( storage . future_age_to_flush ( ) ) ,
}
}
2021-09-16 19:36:23 -07:00
}
2021-09-10 16:32:10 -07:00
#[ derive(Debug, Default) ]
2022-02-28 13:00:53 -08:00
/// one entry in the in-mem accounts index
/// Represents the value for an account key in the in-memory accounts index
2020-10-21 17:05:27 -07:00
pub struct AccountMapEntryInner < T > {
2022-02-28 13:00:53 -08:00
/// number of alive slots that contain >= 1 instances of account data for this pubkey
/// where alive represents a slot that has not yet been removed by clean via AccountsDB::clean_stored_dead_slots() for containing no up to date account information
2020-10-21 17:05:27 -07:00
ref_count : AtomicU64 ,
2022-02-28 13:00:53 -08:00
/// list of slots in which this pubkey was updated
/// Note that 'clean' removes outdated entries (ie. older roots) from this slot_list
/// purge_slot() also removes non-rooted slots from this list
2020-10-21 17:05:27 -07:00
pub slot_list : RwLock < SlotList < T > > ,
2022-02-28 13:00:53 -08:00
/// synchronization metadata for in-memory state since last flush to disk accounts index
2021-09-16 19:36:23 -07:00
pub meta : AccountMapEntryMeta ,
2020-10-21 17:05:27 -07:00
}
2021-09-14 15:51:07 -07:00
impl < T : IndexValue > AccountMapEntryInner < T > {
2021-09-21 10:40:07 -07:00
pub fn new ( slot_list : SlotList < T > , ref_count : RefCount , meta : AccountMapEntryMeta ) -> Self {
Self {
slot_list : RwLock ::new ( slot_list ) ,
ref_count : AtomicU64 ::new ( ref_count ) ,
meta ,
}
}
2021-09-02 16:25:27 -07:00
pub fn ref_count ( & self ) -> RefCount {
2021-02-04 09:11:05 -08:00
self . ref_count . load ( Ordering ::Relaxed )
}
2021-09-02 16:25:27 -07:00
pub fn add_un_ref ( & self , add : bool ) {
if add {
self . ref_count . fetch_add ( 1 , Ordering ::Relaxed ) ;
} else {
self . ref_count . fetch_sub ( 1 , Ordering ::Relaxed ) ;
}
2021-09-16 19:36:23 -07:00
self . set_dirty ( true ) ;
}
pub fn dirty ( & self ) -> bool {
2021-09-22 09:24:16 -07:00
self . meta . dirty . load ( Ordering ::Acquire )
2021-09-16 19:36:23 -07:00
}
2021-09-22 09:24:16 -07:00
pub fn set_dirty ( & self , value : bool ) {
self . meta . dirty . store ( value , Ordering ::Release )
2021-09-02 16:25:27 -07:00
}
2021-09-21 06:41:17 -07:00
2021-10-10 11:47:52 -07:00
/// set dirty to false, return true if was dirty
pub fn clear_dirty ( & self ) -> bool {
self . meta
. dirty
. compare_exchange ( true , false , Ordering ::AcqRel , Ordering ::Relaxed )
. is_ok ( )
}
2021-09-21 06:41:17 -07:00
pub fn age ( & self ) -> Age {
2022-03-18 10:20:42 -07:00
self . meta . age . load ( Ordering ::Acquire )
2021-09-21 06:41:17 -07:00
}
pub fn set_age ( & self , value : Age ) {
2022-03-18 10:20:42 -07:00
self . meta . age . store ( value , Ordering ::Release )
}
/// set age to 'next_age' if 'self.age' is 'expected_age'
pub fn try_exchange_age ( & self , next_age : Age , expected_age : Age ) {
let _ = self . meta . age . compare_exchange (
expected_age ,
next_age ,
Ordering ::AcqRel ,
Ordering ::Relaxed ,
) ;
2021-09-21 06:41:17 -07:00
}
2021-02-04 09:11:05 -08:00
}
2021-12-13 19:16:17 -08:00
pub enum AccountIndexGetResult < T : IndexValue > {
2022-01-21 08:51:58 -08:00
/// (index entry, index in slot list)
2021-04-23 07:33:14 -07:00
Found ( ReadAccountMapEntry < T > , usize ) ,
2021-12-13 19:16:17 -08:00
NotFound ,
2021-04-23 07:33:14 -07:00
}
2020-10-21 17:05:27 -07:00
#[ self_referencing ]
2021-09-14 15:51:07 -07:00
pub struct ReadAccountMapEntry < T : IndexValue > {
2020-11-13 01:12:41 -08:00
owned_entry : AccountMapEntry < T > ,
2020-10-21 17:05:27 -07:00
#[ borrows(owned_entry) ]
2021-06-24 23:53:54 -07:00
#[ covariant ]
2020-11-13 01:12:41 -08:00
slot_list_guard : RwLockReadGuard < ' this , SlotList < T > > ,
2020-10-21 17:05:27 -07:00
}
2021-09-14 15:51:07 -07:00
impl < T : IndexValue > Debug for ReadAccountMapEntry < T > {
2021-09-01 19:52:16 -07:00
fn fmt ( & self , f : & mut std ::fmt ::Formatter ) -> std ::fmt ::Result {
write! ( f , " {:?} " , self . borrow_owned_entry ( ) )
}
}
2021-09-14 15:51:07 -07:00
impl < T : IndexValue > ReadAccountMapEntry < T > {
2020-10-21 17:05:27 -07:00
pub fn from_account_map_entry ( account_map_entry : AccountMapEntry < T > ) -> Self {
ReadAccountMapEntryBuilder {
owned_entry : account_map_entry ,
slot_list_guard_builder : | lock | lock . slot_list . read ( ) . unwrap ( ) ,
}
. build ( )
}
pub fn slot_list ( & self ) -> & SlotList < T > {
2020-11-13 01:12:41 -08:00
& * self . borrow_slot_list_guard ( )
2020-10-21 17:05:27 -07:00
}
2021-08-09 06:59:56 -07:00
pub fn ref_count ( & self ) -> RefCount {
2021-09-02 16:25:27 -07:00
self . borrow_owned_entry ( ) . ref_count ( )
2020-10-21 17:05:27 -07:00
}
2021-02-04 12:44:19 -08:00
pub fn unref ( & self ) {
2021-09-02 16:25:27 -07:00
self . borrow_owned_entry ( ) . add_un_ref ( false ) ;
2021-02-04 12:44:19 -08:00
}
2021-06-02 00:51:46 -07:00
pub fn addref ( & self ) {
2021-09-02 16:25:27 -07:00
self . borrow_owned_entry ( ) . add_un_ref ( true ) ;
2021-06-02 00:51:46 -07:00
}
2020-10-21 17:05:27 -07:00
}
2021-11-22 13:52:45 -08:00
/// can be used to pre-allocate structures for insertion into accounts index outside of lock
pub enum PreAllocatedAccountMapEntry < T : IndexValue > {
Entry ( AccountMapEntry < T > ) ,
Raw ( ( Slot , T ) ) ,
2021-09-23 06:11:32 -07:00
}
2021-12-01 08:21:01 -08:00
impl < T : IndexValue > ZeroLamport for PreAllocatedAccountMapEntry < T > {
fn is_zero_lamport ( & self ) -> bool {
match self {
PreAllocatedAccountMapEntry ::Entry ( entry ) = > {
entry . slot_list . read ( ) . unwrap ( ) [ 0 ] . 1. is_zero_lamport ( )
}
PreAllocatedAccountMapEntry ::Raw ( raw ) = > raw . 1. is_zero_lamport ( ) ,
}
}
}
2021-09-23 06:11:32 -07:00
impl < T : IndexValue > From < PreAllocatedAccountMapEntry < T > > for ( Slot , T ) {
fn from ( source : PreAllocatedAccountMapEntry < T > ) -> ( Slot , T ) {
2021-11-22 13:52:45 -08:00
match source {
PreAllocatedAccountMapEntry ::Entry ( entry ) = > entry . slot_list . write ( ) . unwrap ( ) . remove ( 0 ) ,
PreAllocatedAccountMapEntry ::Raw ( raw ) = > raw ,
}
2021-09-23 06:11:32 -07:00
}
}
impl < T : IndexValue > PreAllocatedAccountMapEntry < T > {
/// create an entry that is equivalent to this process:
/// 1. new empty (refcount=0, slot_list={})
/// 2. update(slot, account_info)
/// This code is called when the first entry [ie. (slot,account_info)] for a pubkey is inserted into the index.
pub fn new (
slot : Slot ,
account_info : T ,
storage : & Arc < BucketMapHolder < T > > ,
2021-11-22 13:52:45 -08:00
store_raw : bool ,
2021-09-23 06:11:32 -07:00
) -> PreAllocatedAccountMapEntry < T > {
2021-11-22 13:52:45 -08:00
if store_raw {
Self ::Raw ( ( slot , account_info ) )
} else {
Self ::Entry ( Self ::allocate ( slot , account_info , storage ) )
}
2021-09-23 06:11:32 -07:00
}
2021-11-22 13:52:45 -08:00
fn allocate (
2021-09-23 06:11:32 -07:00
slot : Slot ,
account_info : T ,
2021-11-22 13:52:45 -08:00
storage : & Arc < BucketMapHolder < T > > ,
) -> AccountMapEntry < T > {
2021-09-23 06:11:32 -07:00
let ref_count = if account_info . is_cached ( ) { 0 } else { 1 } ;
2021-11-22 13:52:45 -08:00
let meta = AccountMapEntryMeta ::new_dirty ( storage ) ;
Arc ::new ( AccountMapEntryInner ::new (
vec! [ ( slot , account_info ) ] ,
ref_count ,
meta ,
) )
}
pub fn into_account_map_entry ( self , storage : & Arc < BucketMapHolder < T > > ) -> AccountMapEntry < T > {
match self {
Self ::Entry ( entry ) = > entry ,
Self ::Raw ( ( slot , account_info ) ) = > Self ::allocate ( slot , account_info , storage ) ,
2021-09-23 06:11:32 -07:00
}
}
}
2021-04-12 10:11:33 -07:00
#[ derive(Debug) ]
2020-10-21 17:05:27 -07:00
pub struct RootsTracker {
2022-04-04 09:06:01 -07:00
/// Current roots where appendvecs or write cache has account data.
/// Constructed during load from snapshots.
/// Updated every time we add a new root or clean/shrink an append vec into irrelevancy.
/// Range is approximately the last N slots where N is # slots per epoch.
2022-04-02 10:00:52 -07:00
pub ( crate ) alive_roots : RollingBitField ,
2022-04-04 09:06:01 -07:00
/// Set of roots that are roots now or were roots at one point in time.
/// Range is approximately the last N slots where N is # slots per epoch.
2022-03-30 06:52:45 -07:00
/// A root could remain here if all entries in the append vec at that root are cleaned/shrunk and there are no
2022-04-04 09:06:01 -07:00
/// more entries for that slot. 'alive_roots' will no longer contain such roots.
/// This is a superset of 'alive_roots'
2022-04-04 07:12:12 -07:00
pub ( crate ) historical_roots : RollingBitField ,
2020-10-21 17:05:27 -07:00
uncleaned_roots : HashSet < Slot > ,
previous_uncleaned_roots : HashSet < Slot > ,
}
2019-05-30 21:31:35 -07:00
2021-04-12 10:11:33 -07:00
impl Default for RootsTracker {
fn default ( ) -> Self {
// we expect to keep a rolling set of 400k slots around at a time
2021-04-20 19:18:15 -07:00
// 4M gives us plenty of extra(?!) room to handle a width 10x what we should need.
// cost is 4M bits of memory, which is .5MB
RootsTracker ::new ( 4194304 )
2021-04-12 10:11:33 -07:00
}
}
impl RootsTracker {
pub fn new ( max_width : u64 ) -> Self {
Self {
2022-04-02 10:00:52 -07:00
alive_roots : RollingBitField ::new ( max_width ) ,
2022-04-04 07:12:12 -07:00
historical_roots : RollingBitField ::new ( max_width ) ,
2021-04-12 10:11:33 -07:00
uncleaned_roots : HashSet ::new ( ) ,
previous_uncleaned_roots : HashSet ::new ( ) ,
}
}
2021-06-08 07:32:16 -07:00
2022-04-02 10:00:52 -07:00
pub fn min_alive_root ( & self ) -> Option < Slot > {
self . alive_roots . min ( )
2021-06-08 07:32:16 -07:00
}
2021-04-12 10:11:33 -07:00
}
2021-01-27 01:39:47 -08:00
#[ derive(Debug, Default) ]
pub struct AccountsIndexRootsStats {
2022-05-10 11:56:30 -07:00
pub roots_len : Option < usize > ,
pub uncleaned_roots_len : Option < usize > ,
pub previous_uncleaned_roots_len : Option < usize > ,
pub roots_range : Option < u64 > ,
pub historical_roots_len : Option < usize > ,
2021-04-28 11:24:01 -07:00
pub rooted_cleaned_count : usize ,
pub unrooted_cleaned_count : usize ,
2021-10-04 16:21:45 -07:00
pub clean_unref_from_storage_us : u64 ,
pub clean_dead_slot_us : u64 ,
2021-01-27 01:39:47 -08:00
}
2021-09-14 15:51:07 -07:00
pub struct AccountsIndexIterator < ' a , T : IndexValue > {
2021-06-28 13:03:57 -07:00
account_maps : & ' a LockMapTypeSlice < T > ,
2021-10-18 12:05:16 -07:00
bin_calculator : & ' a PubkeyBinCalculator24 ,
2020-10-21 17:05:27 -07:00
start_bound : Bound < Pubkey > ,
end_bound : Bound < Pubkey > ,
is_finished : bool ,
2021-08-26 16:12:43 -07:00
collect_all_unsorted : bool ,
2019-04-15 17:15:50 -07:00
}
2021-09-14 15:51:07 -07:00
impl < ' a , T : IndexValue > AccountsIndexIterator < ' a , T > {
2021-09-10 15:52:49 -07:00
fn range < R > (
map : & AccountMapsReadLock < T > ,
2021-08-26 16:12:43 -07:00
range : R ,
collect_all_unsorted : bool ,
2021-09-10 15:52:49 -07:00
) -> Vec < ( Pubkey , AccountMapEntry < T > ) >
2021-08-26 16:12:43 -07:00
where
2021-09-12 19:57:15 -07:00
R : RangeBounds < Pubkey > + std ::fmt ::Debug ,
2021-08-26 16:12:43 -07:00
{
2021-12-17 07:59:29 -08:00
let mut result = map . items ( & range ) ;
2021-08-26 16:12:43 -07:00
if ! collect_all_unsorted {
2021-09-10 15:52:49 -07:00
result . sort_unstable_by ( | a , b | a . 0. cmp ( & b . 0 ) ) ;
2021-08-26 16:12:43 -07:00
}
result
}
2020-10-21 17:05:27 -07:00
fn clone_bound ( bound : Bound < & Pubkey > ) -> Bound < Pubkey > {
match bound {
Unbounded = > Unbounded ,
Included ( k ) = > Included ( * k ) ,
Excluded ( k ) = > Excluded ( * k ) ,
}
}
2021-08-04 07:18:05 -07:00
fn bin_from_bound ( & self , bound : & Bound < Pubkey > , unbounded_bin : usize ) -> usize {
2021-07-27 11:40:45 -07:00
match bound {
2021-08-04 07:18:05 -07:00
Bound ::Included ( bound ) | Bound ::Excluded ( bound ) = > {
self . bin_calculator . bin_from_pubkey ( bound )
}
2021-07-27 11:40:45 -07:00
Bound ::Unbounded = > unbounded_bin ,
}
}
2021-07-15 08:26:50 -07:00
fn start_bin ( & self ) -> usize {
// start in bin where 'start_bound' would exist
2021-08-04 07:18:05 -07:00
self . bin_from_bound ( & self . start_bound , 0 )
2021-07-27 11:40:45 -07:00
}
fn end_bin_inclusive ( & self ) -> usize {
// end in bin where 'end_bound' would exist
2021-08-04 07:18:05 -07:00
self . bin_from_bound ( & self . end_bound , usize ::MAX )
2021-07-27 11:40:45 -07:00
}
fn bin_start_and_range ( & self ) -> ( usize , usize ) {
let start_bin = self . start_bin ( ) ;
// calculate the max range of bins to look in
let end_bin_inclusive = self . end_bin_inclusive ( ) ;
let bin_range = if start_bin > end_bin_inclusive {
0 // empty range
} else if end_bin_inclusive = = usize ::MAX {
usize ::MAX
} else {
// the range is end_inclusive + 1 - start
// end_inclusive could be usize::MAX already if no bound was specified
end_bin_inclusive . saturating_add ( 1 ) - start_bin
} ;
( start_bin , bin_range )
2021-07-15 08:26:50 -07:00
}
2021-09-03 16:00:49 -07:00
pub fn new < R > (
index : & ' a AccountsIndex < T > ,
range : Option < & R > ,
collect_all_unsorted : bool ,
) -> Self
2020-10-21 17:05:27 -07:00
where
R : RangeBounds < Pubkey > ,
{
Self {
start_bound : range
. as_ref ( )
. map ( | r | Self ::clone_bound ( r . start_bound ( ) ) )
. unwrap_or ( Unbounded ) ,
end_bound : range
. as_ref ( )
. map ( | r | Self ::clone_bound ( r . end_bound ( ) ) )
. unwrap_or ( Unbounded ) ,
2021-08-04 07:18:05 -07:00
account_maps : & index . account_maps ,
2020-10-21 17:05:27 -07:00
is_finished : false ,
2021-08-04 07:18:05 -07:00
bin_calculator : & index . bin_calculator ,
2021-08-26 16:12:43 -07:00
collect_all_unsorted ,
2020-10-21 17:05:27 -07:00
}
}
2021-09-17 15:19:29 -07:00
2021-12-21 15:31:48 -08:00
pub fn hold_range_in_memory < R > ( & self , range : & R , start_holding : bool , thread_pool : & ThreadPool )
2021-09-17 15:19:29 -07:00
where
2021-12-21 15:31:48 -08:00
R : RangeBounds < Pubkey > + Debug + Sync ,
2021-09-17 15:19:29 -07:00
{
// forward this hold request ONLY to the bins which contain keys in the specified range
let ( start_bin , bin_range ) = self . bin_start_and_range ( ) ;
2021-12-21 15:31:48 -08:00
// the idea is this range shouldn't be more than a few buckets, but the process of loading from disk buckets is very slow
// so, parallelize the bucket loads
thread_pool . install ( | | {
( 0 .. bin_range ) . into_par_iter ( ) . for_each ( | idx | {
let map = & self . account_maps [ idx + start_bin ] ;
2021-09-17 15:19:29 -07:00
map . read ( )
. unwrap ( )
. hold_range_in_memory ( range , start_holding ) ;
} ) ;
2021-12-21 15:31:48 -08:00
} ) ;
2021-09-17 15:19:29 -07:00
}
2020-10-21 17:05:27 -07:00
}
2021-09-14 15:51:07 -07:00
impl < ' a , T : IndexValue > Iterator for AccountsIndexIterator < ' a , T > {
2020-10-21 17:05:27 -07:00
type Item = Vec < ( Pubkey , AccountMapEntry < T > ) > ;
fn next ( & mut self ) -> Option < Self ::Item > {
if self . is_finished {
return None ;
}
2021-07-27 11:40:45 -07:00
let ( start_bin , bin_range ) = self . bin_start_and_range ( ) ;
2021-08-31 18:03:42 -07:00
let mut chunk = Vec ::with_capacity ( ITER_BATCH_SIZE ) ;
2021-07-27 11:40:45 -07:00
' outer : for i in self . account_maps . iter ( ) . skip ( start_bin ) . take ( bin_range ) {
2021-08-26 16:12:43 -07:00
for ( pubkey , account_map_entry ) in Self ::range (
& i . read ( ) . unwrap ( ) ,
( self . start_bound , self . end_bound ) ,
self . collect_all_unsorted ,
) {
if chunk . len ( ) > = ITER_BATCH_SIZE & & ! self . collect_all_unsorted {
2021-07-13 09:11:17 -07:00
break 'outer ;
}
2021-09-10 15:52:49 -07:00
let item = ( pubkey , account_map_entry ) ;
2021-07-13 09:11:17 -07:00
chunk . push ( item ) ;
}
}
2020-10-21 17:05:27 -07:00
if chunk . is_empty ( ) {
self . is_finished = true ;
return None ;
2021-08-26 16:12:43 -07:00
} else if self . collect_all_unsorted {
self . is_finished = true ;
2020-10-21 17:05:27 -07:00
}
self . start_bound = Excluded ( chunk . last ( ) . unwrap ( ) . 0 ) ;
Some ( chunk )
}
}
2021-01-24 09:50:19 -08:00
pub trait ZeroLamport {
fn is_zero_lamport ( & self ) -> bool ;
}
2021-09-10 19:09:51 -07:00
type MapType < T > = AccountMap < T > ;
2021-06-28 13:03:57 -07:00
type LockMapType < T > = Vec < RwLock < MapType < T > > > ;
type LockMapTypeSlice < T > = [ RwLock < MapType < T > > ] ;
2021-06-17 12:41:52 -07:00
type AccountMapsWriteLock < ' a , T > = RwLockWriteGuard < ' a , MapType < T > > ;
type AccountMapsReadLock < ' a , T > = RwLockReadGuard < ' a , MapType < T > > ;
2021-05-14 13:27:10 -07:00
2021-06-14 21:04:01 -07:00
#[ derive(Debug, Default) ]
pub struct ScanSlotTracker {
is_removed : bool ,
}
impl ScanSlotTracker {
pub fn is_removed ( & self ) -> bool {
self . is_removed
}
pub fn mark_removed ( & mut self ) {
self . is_removed = true ;
}
}
2021-05-12 15:29:30 -07:00
#[ derive(Debug) ]
2021-09-14 15:51:07 -07:00
pub struct AccountsIndex < T : IndexValue > {
2021-06-17 12:41:52 -07:00
pub account_maps : LockMapType < T > ,
2021-10-18 12:05:16 -07:00
pub bin_calculator : PubkeyBinCalculator24 ,
2020-12-31 18:06:03 -08:00
program_id_index : SecondaryIndex < DashMapSecondaryIndexEntry > ,
spl_token_mint_index : SecondaryIndex < DashMapSecondaryIndexEntry > ,
spl_token_owner_index : SecondaryIndex < RwLockSecondaryIndexEntry > ,
2022-03-24 08:06:24 -07:00
pub ( crate ) roots_tracker : RwLock < RootsTracker > ,
2020-11-16 17:23:11 -08:00
ongoing_scan_roots : RwLock < BTreeMap < Slot , u64 > > ,
2021-06-14 21:04:01 -07:00
// Each scan has some latest slot `S` that is the tip of the fork the scan
// is iterating over. The unique id of that slot `S` is recorded here (note we don't use
// `S` as the id because there can be more than one version of a slot `S`). If a fork
// is abandoned, all of the slots on that fork up to `S` will be removed via
// `AccountsDb::remove_unrooted_slots()`. When the scan finishes, it'll realize that the
// results of the scan may have been corrupted by `remove_unrooted_slots` and abort its results.
//
// `removed_bank_ids` tracks all the slot ids that were removed via `remove_unrooted_slots()` so any attempted scans
// on any of these slots fails. This is safe to purge once the associated Bank is dropped and
// scanning the fork with that Bank at the tip is no longer possible.
pub removed_bank_ids : Mutex < HashSet < BankId > > ,
2021-09-12 15:14:59 -07:00
2021-09-13 20:59:03 -07:00
storage : AccountsIndexStorage < T > ,
2021-11-19 07:00:19 -08:00
/// when a scan's accumulated data exceeds this limit, abort the scan
pub scan_results_limit_bytes : Option < usize > ,
2020-10-21 17:05:27 -07:00
}
2021-09-14 15:51:07 -07:00
impl < T : IndexValue > AccountsIndex < T > {
2021-08-04 19:58:53 -07:00
pub fn default_for_tests ( ) -> Self {
2022-02-22 07:40:12 -08:00
Self ::new ( Some ( ACCOUNTS_INDEX_CONFIG_FOR_TESTING ) )
2021-08-04 19:58:53 -07:00
}
2021-08-17 12:50:01 -07:00
pub fn new ( config : Option < AccountsIndexConfig > ) -> Self {
2021-11-19 07:00:19 -08:00
let scan_results_limit_bytes = config
. as_ref ( )
. and_then ( | config | config . scan_results_limit_bytes ) ;
2021-09-12 15:14:59 -07:00
let ( account_maps , bin_calculator , storage ) = Self ::allocate_accounts_index ( config ) ;
2021-05-12 15:29:30 -07:00
Self {
2021-08-04 13:28:35 -07:00
account_maps ,
bin_calculator ,
2021-05-12 15:29:30 -07:00
program_id_index : SecondaryIndex ::< DashMapSecondaryIndexEntry > ::new (
" program_id_index_stats " ,
) ,
spl_token_mint_index : SecondaryIndex ::< DashMapSecondaryIndexEntry > ::new (
" spl_token_mint_index_stats " ,
) ,
spl_token_owner_index : SecondaryIndex ::< RwLockSecondaryIndexEntry > ::new (
" spl_token_owner_index_stats " ,
) ,
roots_tracker : RwLock ::< RootsTracker > ::default ( ) ,
ongoing_scan_roots : RwLock ::< BTreeMap < Slot , u64 > > ::default ( ) ,
2021-06-14 21:04:01 -07:00
removed_bank_ids : Mutex ::< HashSet < BankId > > ::default ( ) ,
2021-09-12 15:14:59 -07:00
storage ,
2021-11-19 07:00:19 -08:00
scan_results_limit_bytes ,
2021-05-12 15:29:30 -07:00
}
}
2021-08-17 12:50:01 -07:00
fn allocate_accounts_index (
config : Option < AccountsIndexConfig > ,
2021-09-13 20:59:03 -07:00
) -> (
LockMapType < T > ,
2021-10-18 12:05:16 -07:00
PubkeyBinCalculator24 ,
2021-09-13 20:59:03 -07:00
AccountsIndexStorage < T > ,
) {
2021-08-17 12:50:01 -07:00
let bins = config
2021-09-17 09:39:41 -07:00
. as_ref ( )
2021-08-17 12:50:01 -07:00
. and_then ( | config | config . bins )
. unwrap_or ( BINS_DEFAULT ) ;
2021-09-02 15:58:07 -07:00
// create bin_calculator early to verify # bins is reasonable
2021-10-18 12:05:16 -07:00
let bin_calculator = PubkeyBinCalculator24 ::new ( bins ) ;
2021-09-17 09:39:41 -07:00
let storage = AccountsIndexStorage ::new ( bins , & config ) ;
2021-08-04 13:28:35 -07:00
let account_maps = ( 0 .. bins )
. into_iter ( )
2021-09-16 14:12:22 -07:00
. map ( | bin | RwLock ::new ( Arc ::clone ( & storage . in_mem [ bin ] ) ) )
2021-08-04 13:28:35 -07:00
. collect ::< Vec < _ > > ( ) ;
2021-09-12 15:14:59 -07:00
( account_maps , bin_calculator , storage )
2021-08-04 13:28:35 -07:00
}
2021-08-04 19:58:53 -07:00
2021-09-03 16:00:49 -07:00
fn iter < R > ( & self , range : Option < & R > , collect_all_unsorted : bool ) -> AccountsIndexIterator < T >
2020-10-21 17:05:27 -07:00
where
R : RangeBounds < Pubkey > ,
{
2021-08-26 16:12:43 -07:00
AccountsIndexIterator ::new ( self , range , collect_all_unsorted )
2020-10-21 17:05:27 -07:00
}
2021-12-08 14:52:22 -08:00
/// is the accounts index using disk as a backing store
pub fn is_disk_index_enabled ( & self ) -> bool {
self . storage . storage . is_disk_index_enabled ( )
}
2020-12-31 18:06:03 -08:00
fn do_checked_scan_accounts < F , R > (
& self ,
2021-02-03 15:00:42 -08:00
metric_name : & 'static str ,
2020-12-31 18:06:03 -08:00
ancestors : & Ancestors ,
2021-06-14 21:04:01 -07:00
scan_bank_id : BankId ,
2020-12-31 18:06:03 -08:00
func : F ,
scan_type : ScanTypes < R > ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-06-14 21:04:01 -07:00
) -> Result < ( ) , ScanError >
where
2020-11-16 17:23:11 -08:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
2021-09-01 06:13:56 -07:00
R : RangeBounds < Pubkey > + std ::fmt ::Debug ,
2020-11-16 17:23:11 -08:00
{
2021-06-14 21:04:01 -07:00
{
let locked_removed_bank_ids = self . removed_bank_ids . lock ( ) . unwrap ( ) ;
if locked_removed_bank_ids . contains ( & scan_bank_id ) {
return Err ( ScanError ::SlotRemoved {
slot : ancestors . max_slot ( ) ,
bank_id : scan_bank_id ,
} ) ;
}
}
2020-11-16 17:23:11 -08:00
let max_root = {
let mut w_ongoing_scan_roots = self
// This lock is also grabbed by clean_accounts(), so clean
// has at most cleaned up to the current `max_root` (since
// clean only happens *after* BankForks::set_root() which sets
// the `max_root`)
. ongoing_scan_roots
. write ( )
. unwrap ( ) ;
// `max_root()` grabs a lock while
// the `ongoing_scan_roots` lock is held,
// make sure inverse doesn't happen to avoid
// deadlock
2022-02-07 11:26:53 -08:00
let max_root_inclusive = self . max_root_inclusive ( ) ;
* w_ongoing_scan_roots . entry ( max_root_inclusive ) . or_default ( ) + = 1 ;
2020-11-20 13:01:04 -08:00
2022-02-07 11:26:53 -08:00
max_root_inclusive
2020-11-16 17:23:11 -08:00
} ;
2020-11-20 13:01:04 -08:00
// First we show that for any bank `B` that is a descendant of
// the current `max_root`, it must be true that and `B.ancestors.contains(max_root)`,
2021-03-02 06:36:49 -08:00
// regardless of the pattern of `squash()` behavior, where `ancestors` is the set
2020-11-20 13:01:04 -08:00
// of ancestors that is tracked in each bank.
//
// Proof: At startup, if starting from a snapshot, generate_index() adds all banks
// in the snapshot to the index via `add_root()` and so `max_root` will be the
// greatest of these. Thus, so the claim holds at startup since there are no
// descendants of `max_root`.
//
// Now we proceed by induction on each `BankForks::set_root()`.
// Assume the claim holds when the `max_root` is `R`. Call the set of
// descendants of `R` present in BankForks `R_descendants`.
//
// Then for any banks `B` in `R_descendants`, it must be that `B.ancestors.contains(S)`,
// where `S` is any ancestor of `B` such that `S >= R`.
//
// For example:
// `R` -> `A` -> `C` -> `B`
// Then `B.ancestors == {R, A, C}`
//
// Next we call `BankForks::set_root()` at some descendant of `R`, `R_new`,
// where `R_new > R`.
//
// When we squash `R_new`, `max_root` in the AccountsIndex here is now set to `R_new`,
// and all nondescendants of `R_new` are pruned.
//
// Now consider any outstanding references to banks in the system that are descended from
// `max_root == R_new`. Take any one of these references and call it `B`. Because `B` is
// a descendant of `R_new`, this means `B` was also a descendant of `R`. Thus `B`
// must be a member of `R_descendants` because `B` was constructed and added to
// BankForks before the `set_root`.
//
// This means by the guarantees of `R_descendants` described above, because
2021-03-02 06:36:49 -08:00
// `R_new` is an ancestor of `B`, and `R < R_new < B`, then `B.ancestors.contains(R_new)`.
2020-11-20 13:01:04 -08:00
//
// Now until the next `set_root`, any new banks constructed from `new_from_parent` will
// also have `max_root == R_new` in their ancestor set, so the claim holds for those descendants
// as well. Once the next `set_root` happens, we once again update `max_root` and the same
// inductive argument can be applied again to show the claim holds.
// Check that the `max_root` is present in `ancestors`. From the proof above, if
// `max_root` is not present in `ancestors`, this means the bank `B` with the
// given `ancestors` is not descended from `max_root, which means
// either:
// 1) `B` is on a different fork or
// 2) `B` is an ancestor of `max_root`.
// In both cases we can ignore the given ancestors and instead just rely on the roots
// present as `max_root` indicates the roots present in the index are more up to date
// than the ancestors given.
2021-04-12 08:51:57 -07:00
let empty = Ancestors ::default ( ) ;
2020-11-20 13:01:04 -08:00
let ancestors = if ancestors . contains_key ( & max_root ) {
ancestors
} else {
/*
This takes of edge cases like :
Diagram 1 :
slot 0
|
slot 1
/ \
slot 2 |
| slot 3 ( max root )
slot 4 ( scan )
By the time the scan on slot 4 is called , slot 2 may already have been
cleaned by a clean on slot 3 , but slot 4 may not have been cleaned .
The state in slot 2 would have been purged and is not saved in any roots .
In this case , a scan on slot 4 wouldn ' t accurately reflect the state when bank 4
was frozen . In cases like this , we default to a scan on the latest roots by
removing all ` ancestors ` .
* /
& empty
} ;
/*
Now there are two cases , either ` ancestors ` is empty or nonempty :
1 ) If ancestors is empty , then this is the same as a scan on a rooted bank ,
and ` ongoing_scan_roots ` provides protection against cleanup of roots necessary
for the scan , and passing ` Some ( max_root ) ` to ` do_scan_accounts ( ) ` ensures newer
roots don ' t appear in the scan .
2 ) If ancestors is non - empty , then from the ` ancestors_contains ( & max_root ) ` above , we know
that the fork structure must look something like :
Diagram 2 :
Build fork structure :
slot 0
|
slot 1 ( max_root )
/ \
slot 2 |
| slot 3 ( potential newer max root )
slot 4
|
slot 5 ( scan )
Consider both types of ancestors , ancestor < = ` max_root ` and
ancestor > ` max_root ` , where ` max_root = = 1 ` as illustrated above .
a ) The set of ` ancestors < = max_root ` are all rooted , which means their state
is protected by the same guarantees as 1 ) .
b ) As for the ` ancestors > max_root ` , those banks have at least one reference discoverable
through the chain of ` Bank ::BankRc ::parent ` starting from the calling bank . For instance
bank 5 ' s parent reference keeps bank 4 alive , which will prevent the ` Bank ::drop ( ) ` from
running and cleaning up bank 4. Furthermore , no cleans can happen past the saved max_root = = 1 ,
so a potential newer max root at 3 will not clean up any of the ancestors > 1 , so slot 4
2021-04-16 08:23:32 -07:00
will not be cleaned in the middle of the scan either . ( NOTE similar reasoning is employed for
assert! ( ) justification in AccountsDb ::retry_to_get_account_accessor )
2020-11-20 13:01:04 -08:00
* /
2020-12-31 18:06:03 -08:00
match scan_type {
ScanTypes ::Unindexed ( range ) = > {
2021-02-03 15:00:42 -08:00
// Pass "" not to log metrics, so RPC doesn't get spammy
2021-11-17 11:10:29 -08:00
self . do_scan_accounts ( metric_name , ancestors , func , range , Some ( max_root ) , config ) ;
2020-12-31 18:06:03 -08:00
}
ScanTypes ::Indexed ( IndexKey ::ProgramId ( program_id ) ) = > {
self . do_scan_secondary_index (
ancestors ,
func ,
& self . program_id_index ,
& program_id ,
Some ( max_root ) ,
2021-11-17 11:10:29 -08:00
config ,
2020-12-31 18:06:03 -08:00
) ;
}
ScanTypes ::Indexed ( IndexKey ::SplTokenMint ( mint_key ) ) = > {
self . do_scan_secondary_index (
ancestors ,
func ,
& self . spl_token_mint_index ,
& mint_key ,
Some ( max_root ) ,
2021-11-17 11:10:29 -08:00
config ,
2020-12-31 18:06:03 -08:00
) ;
}
ScanTypes ::Indexed ( IndexKey ::SplTokenOwner ( owner_key ) ) = > {
self . do_scan_secondary_index (
ancestors ,
func ,
& self . spl_token_owner_index ,
& owner_key ,
Some ( max_root ) ,
2021-11-17 11:10:29 -08:00
config ,
2020-12-31 18:06:03 -08:00
) ;
}
}
2020-11-16 17:23:11 -08:00
{
let mut ongoing_scan_roots = self . ongoing_scan_roots . write ( ) . unwrap ( ) ;
let count = ongoing_scan_roots . get_mut ( & max_root ) . unwrap ( ) ;
* count - = 1 ;
if * count = = 0 {
ongoing_scan_roots . remove ( & max_root ) ;
}
}
2021-06-14 21:04:01 -07:00
// If the fork with tip at bank `scan_bank_id` was removed during our scan, then the scan
// may have been corrupted, so abort the results.
let was_scan_corrupted = self
. removed_bank_ids
. lock ( )
. unwrap ( )
. contains ( & scan_bank_id ) ;
if was_scan_corrupted {
Err ( ScanError ::SlotRemoved {
slot : ancestors . max_slot ( ) ,
bank_id : scan_bank_id ,
} )
} else {
Ok ( ( ) )
}
2020-11-16 17:23:11 -08:00
}
2021-02-03 15:00:42 -08:00
fn do_unchecked_scan_accounts < F , R > (
& self ,
metric_name : & 'static str ,
ancestors : & Ancestors ,
func : F ,
range : Option < R > ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-02-03 15:00:42 -08:00
) where
2020-11-16 17:23:11 -08:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
2021-09-01 06:13:56 -07:00
R : RangeBounds < Pubkey > + std ::fmt ::Debug ,
2020-11-16 17:23:11 -08:00
{
2021-11-17 11:10:29 -08:00
self . do_scan_accounts ( metric_name , ancestors , func , range , None , config ) ;
2020-11-16 17:23:11 -08:00
}
2020-11-20 13:01:04 -08:00
// Scan accounts and return latest version of each account that is either:
// 1) rooted or
// 2) present in ancestors
2020-12-13 17:26:34 -08:00
fn do_scan_accounts < F , R > (
& self ,
2021-02-03 15:00:42 -08:00
metric_name : & 'static str ,
2020-11-16 17:23:11 -08:00
ancestors : & Ancestors ,
mut func : F ,
range : Option < R > ,
max_root : Option < Slot > ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2020-11-16 17:23:11 -08:00
) where
2020-06-08 17:38:14 -07:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
2021-09-01 06:13:56 -07:00
R : RangeBounds < Pubkey > + std ::fmt ::Debug ,
2019-07-10 22:06:32 -07:00
{
2020-12-31 18:06:03 -08:00
// TODO: expand to use mint index to find the `pubkey_list` below more efficiently
// instead of scanning the entire range
2021-02-03 15:00:42 -08:00
let mut total_elapsed_timer = Measure ::start ( " total " ) ;
let mut num_keys_iterated = 0 ;
let mut latest_slot_elapsed = 0 ;
let mut load_account_elapsed = 0 ;
let mut read_lock_elapsed = 0 ;
let mut iterator_elapsed = 0 ;
let mut iterator_timer = Measure ::start ( " iterator_elapsed " ) ;
2021-11-17 11:10:29 -08:00
for pubkey_list in self . iter ( range . as_ref ( ) , config . collect_all_unsorted ) {
2021-02-03 15:00:42 -08:00
iterator_timer . stop ( ) ;
iterator_elapsed + = iterator_timer . as_us ( ) ;
2020-10-21 17:05:27 -07:00
for ( pubkey , list ) in pubkey_list {
2021-02-03 15:00:42 -08:00
num_keys_iterated + = 1 ;
let mut read_lock_timer = Measure ::start ( " read_lock " ) ;
2020-10-21 17:05:27 -07:00
let list_r = & list . slot_list . read ( ) . unwrap ( ) ;
2021-02-03 15:00:42 -08:00
read_lock_timer . stop ( ) ;
read_lock_elapsed + = read_lock_timer . as_us ( ) ;
let mut latest_slot_timer = Measure ::start ( " latest_slot " ) ;
2021-06-18 06:34:46 -07:00
if let Some ( index ) = self . latest_slot ( Some ( ancestors ) , list_r , max_root ) {
2021-02-03 15:00:42 -08:00
latest_slot_timer . stop ( ) ;
latest_slot_elapsed + = latest_slot_timer . as_us ( ) ;
let mut load_account_timer = Measure ::start ( " load_account " ) ;
2020-10-21 17:05:27 -07:00
func ( & pubkey , ( & list_r [ index ] . 1 , list_r [ index ] . 0 ) ) ;
2021-02-03 15:00:42 -08:00
load_account_timer . stop ( ) ;
load_account_elapsed + = load_account_timer . as_us ( ) ;
2020-10-21 17:05:27 -07:00
}
2021-11-17 11:10:29 -08:00
if config . is_aborted ( ) {
return ;
}
2020-10-21 17:05:27 -07:00
}
2021-02-03 15:00:42 -08:00
iterator_timer = Measure ::start ( " iterator_elapsed " ) ;
}
total_elapsed_timer . stop ( ) ;
if ! metric_name . is_empty ( ) {
datapoint_info! (
metric_name ,
( " total_elapsed " , total_elapsed_timer . as_us ( ) , i64 ) ,
( " latest_slot_elapsed " , latest_slot_elapsed , i64 ) ,
( " read_lock_elapsed " , read_lock_elapsed , i64 ) ,
( " load_account_elapsed " , load_account_elapsed , i64 ) ,
( " iterator_elapsed " , iterator_elapsed , i64 ) ,
( " num_keys_iterated " , num_keys_iterated , i64 ) ,
)
2020-10-21 17:05:27 -07:00
}
}
2020-12-31 18:06:03 -08:00
fn do_scan_secondary_index <
F ,
SecondaryIndexEntryType : SecondaryIndexEntry + Default + Sync + Send ,
> (
& self ,
ancestors : & Ancestors ,
mut func : F ,
index : & SecondaryIndex < SecondaryIndexEntryType > ,
index_key : & Pubkey ,
max_root : Option < Slot > ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2020-12-31 18:06:03 -08:00
) where
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
{
for pubkey in index . get ( index_key ) {
2021-03-04 23:16:53 -08:00
// Maybe these reads from the AccountsIndex can be batched every time it
2020-12-31 18:06:03 -08:00
// grabs the read lock as well...
2021-04-23 07:33:14 -07:00
if let AccountIndexGetResult ::Found ( list_r , index ) =
self . get ( & pubkey , Some ( ancestors ) , max_root )
{
2021-12-02 09:05:54 -08:00
let entry = & list_r . slot_list ( ) [ index ] ;
func ( & pubkey , ( & entry . 1 , entry . 0 ) ) ;
2020-12-31 18:06:03 -08:00
}
2021-11-17 11:10:29 -08:00
if config . is_aborted ( ) {
break ;
}
2020-12-31 18:06:03 -08:00
}
}
2020-10-21 17:05:27 -07:00
pub fn get_account_read_entry ( & self , pubkey : & Pubkey ) -> Option < ReadAccountMapEntry < T > > {
2021-06-28 13:03:57 -07:00
let lock = self . get_account_maps_read_lock ( pubkey ) ;
2021-05-21 11:59:32 -07:00
self . get_account_read_entry_with_lock ( pubkey , & lock )
}
pub fn get_account_read_entry_with_lock (
& self ,
pubkey : & Pubkey ,
lock : & AccountMapsReadLock < '_ , T > ,
) -> Option < ReadAccountMapEntry < T > > {
lock . get ( pubkey )
2020-10-21 17:05:27 -07:00
. map ( ReadAccountMapEntry ::from_account_map_entry )
}
2021-09-27 14:24:19 -07:00
fn slot_list_mut < RT > (
& self ,
pubkey : & Pubkey ,
user : impl for < ' a > FnOnce ( & mut RwLockWriteGuard < ' a , SlotList < T > > ) -> RT ,
) -> Option < RT > {
let read_lock = self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ]
2020-10-21 17:05:27 -07:00
. read ( )
2021-09-27 14:24:19 -07:00
. unwrap ( ) ;
2021-09-27 17:18:36 -07:00
read_lock . slot_list_mut ( pubkey , user )
2020-10-21 17:05:27 -07:00
}
2021-05-10 07:22:48 -07:00
pub fn handle_dead_keys (
& self ,
dead_keys : & [ & Pubkey ] ,
account_indexes : & AccountSecondaryIndexes ,
) {
2020-10-21 17:05:27 -07:00
if ! dead_keys . is_empty ( ) {
for key in dead_keys . iter ( ) {
2021-09-15 10:36:08 -07:00
let w_index = self . get_account_maps_write_lock ( key ) ;
2021-09-12 08:26:04 -07:00
if w_index . remove_if_slot_list_empty ( * * key ) {
2021-09-02 14:54:37 -07:00
// Note it's only safe to remove all the entries for this key
// because we have the lock for this key's entry in the AccountsIndex,
// so no other thread is also updating the index
self . purge_secondary_indexes_by_inner_key ( key , account_indexes ) ;
2020-10-21 17:05:27 -07:00
}
2019-07-10 22:06:32 -07:00
}
}
}
2020-05-13 00:22:14 -07:00
/// call func with every pubkey and index visible from a given set of ancestors
2021-06-14 21:04:01 -07:00
pub ( crate ) fn scan_accounts < F > (
& self ,
ancestors : & Ancestors ,
scan_bank_id : BankId ,
func : F ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-06-14 21:04:01 -07:00
) -> Result < ( ) , ScanError >
2020-05-13 00:22:14 -07:00
where
2020-06-08 17:38:14 -07:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
2020-05-13 00:22:14 -07:00
{
2021-02-03 15:00:42 -08:00
// Pass "" not to log metrics, so RPC doesn't get spammy
self . do_checked_scan_accounts (
" " ,
ancestors ,
2021-06-14 21:04:01 -07:00
scan_bank_id ,
2021-02-03 15:00:42 -08:00
func ,
ScanTypes ::Unindexed ( None ::< Range < Pubkey > > ) ,
2021-11-17 11:10:29 -08:00
config ,
2021-06-14 21:04:01 -07:00
)
2020-11-16 17:23:11 -08:00
}
2021-02-03 15:00:42 -08:00
pub ( crate ) fn unchecked_scan_accounts < F > (
& self ,
metric_name : & 'static str ,
ancestors : & Ancestors ,
func : F ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-02-03 15:00:42 -08:00
) where
2020-11-16 17:23:11 -08:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
{
2021-08-26 16:12:43 -07:00
self . do_unchecked_scan_accounts (
metric_name ,
ancestors ,
func ,
None ::< Range < Pubkey > > ,
2021-11-17 11:10:29 -08:00
config ,
2021-08-26 16:12:43 -07:00
) ;
2020-05-13 00:22:14 -07:00
}
/// call func with every pubkey and index visible from a given set of ancestors with range
2021-02-03 15:00:42 -08:00
pub ( crate ) fn range_scan_accounts < F , R > (
& self ,
metric_name : & 'static str ,
ancestors : & Ancestors ,
range : R ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-02-03 15:00:42 -08:00
func : F ,
) where
2020-06-08 17:38:14 -07:00
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
2021-09-01 06:13:56 -07:00
R : RangeBounds < Pubkey > + std ::fmt ::Debug ,
2020-05-13 00:22:14 -07:00
{
2020-11-16 17:23:11 -08:00
// Only the rent logic should be calling this, which doesn't need the safety checks
2021-11-17 11:10:29 -08:00
self . do_unchecked_scan_accounts ( metric_name , ancestors , func , Some ( range ) , config ) ;
2020-05-13 00:22:14 -07:00
}
2020-12-31 18:06:03 -08:00
/// call func with every pubkey and index visible from a given set of ancestors
2021-06-14 21:04:01 -07:00
pub ( crate ) fn index_scan_accounts < F > (
& self ,
ancestors : & Ancestors ,
scan_bank_id : BankId ,
index_key : IndexKey ,
func : F ,
2021-11-19 07:00:19 -08:00
config : & ScanConfig ,
2021-06-14 21:04:01 -07:00
) -> Result < ( ) , ScanError >
2020-12-31 18:06:03 -08:00
where
F : FnMut ( & Pubkey , ( & T , Slot ) ) ,
{
2021-02-03 15:00:42 -08:00
// Pass "" not to log metrics, so RPC doesn't get spammy
2020-12-31 18:06:03 -08:00
self . do_checked_scan_accounts (
2021-02-03 15:00:42 -08:00
" " ,
2020-12-31 18:06:03 -08:00
ancestors ,
2021-06-14 21:04:01 -07:00
scan_bank_id ,
2020-12-31 18:06:03 -08:00
func ,
ScanTypes ::< Range < Pubkey > > ::Indexed ( index_key ) ,
2021-11-17 11:10:29 -08:00
config ,
2021-06-14 21:04:01 -07:00
)
2020-12-31 18:06:03 -08:00
}
2020-11-26 13:09:20 -08:00
pub fn get_rooted_entries ( & self , slice : SlotSlice < T > , max : Option < Slot > ) -> SlotList < T > {
2021-04-05 09:26:53 -07:00
let max = max . unwrap_or ( Slot ::MAX ) ;
2022-04-02 10:00:52 -07:00
let lock = & self . roots_tracker . read ( ) . unwrap ( ) . alive_roots ;
2020-03-25 21:08:56 -07:00
slice
. iter ( )
2021-04-05 09:26:53 -07:00
. filter ( | ( slot , _ ) | * slot < = max & & lock . contains ( slot ) )
2019-10-23 12:46:48 -07:00
. cloned ( )
2019-12-02 09:51:05 -08:00
. collect ( )
}
2020-07-02 22:25:17 -07:00
// returns the rooted entries and the storage ref count
2020-10-21 17:05:27 -07:00
pub fn roots_and_ref_count (
& self ,
locked_account_entry : & ReadAccountMapEntry < T > ,
2020-11-26 13:09:20 -08:00
max : Option < Slot > ,
2020-10-21 17:05:27 -07:00
) -> ( SlotList < T > , RefCount ) {
2020-07-02 22:25:17 -07:00
(
2021-06-18 06:34:46 -07:00
self . get_rooted_entries ( locked_account_entry . slot_list ( ) , max ) ,
2021-08-09 06:59:56 -07:00
locked_account_entry . ref_count ( ) ,
2020-07-02 22:25:17 -07:00
)
2019-12-02 09:51:05 -08:00
}
2021-01-17 20:31:03 -08:00
pub fn purge_exact < ' a , C > (
& ' a self ,
2020-12-31 18:06:03 -08:00
pubkey : & Pubkey ,
2021-01-17 20:31:03 -08:00
slots_to_purge : & ' a C ,
2021-01-11 17:00:23 -08:00
reclaims : & mut SlotList < T > ,
2021-01-17 20:31:03 -08:00
) -> bool
where
C : Contains < ' a , Slot > ,
{
2021-09-27 14:24:19 -07:00
self . slot_list_mut ( pubkey , | slot_list | {
slot_list . retain ( | ( slot , item ) | {
let should_purge = slots_to_purge . contains ( slot ) ;
if should_purge {
reclaims . push ( ( * slot , * item ) ) ;
false
} else {
true
}
} ) ;
slot_list . is_empty ( )
} )
. unwrap_or ( true )
2020-07-02 22:25:17 -07:00
}
2020-11-16 17:23:11 -08:00
pub fn min_ongoing_scan_root ( & self ) -> Option < Slot > {
self . ongoing_scan_roots
. read ( )
. unwrap ( )
. keys ( )
. next ( )
. cloned ( )
}
2020-09-28 16:04:46 -07:00
// Given a SlotSlice `L`, a list of ancestors and a maximum slot, find the latest element
2020-11-16 17:23:11 -08:00
// in `L`, where the slot `S` is an ancestor or root, and if `S` is a root, then `S <= max_root`
2020-09-28 16:04:46 -07:00
fn latest_slot (
& self ,
ancestors : Option < & Ancestors > ,
slice : SlotSlice < T > ,
2020-11-16 17:23:11 -08:00
max_root : Option < Slot > ,
2020-09-28 16:04:46 -07:00
) -> Option < usize > {
let mut current_max = 0 ;
2019-04-15 17:15:50 -07:00
let mut rv = None ;
2021-04-05 09:35:14 -07:00
if let Some ( ancestors ) = ancestors {
if ! ancestors . is_empty ( ) {
for ( i , ( slot , _t ) ) in slice . iter ( ) . rev ( ) . enumerate ( ) {
2021-04-12 08:52:24 -07:00
if ( rv . is_none ( ) | | * slot > current_max ) & & ancestors . contains_key ( slot ) {
2021-04-05 09:35:14 -07:00
rv = Some ( i ) ;
current_max = * slot ;
}
}
2019-04-15 17:15:50 -07:00
}
}
2020-09-28 16:04:46 -07:00
2021-04-05 09:35:14 -07:00
let max_root = max_root . unwrap_or ( Slot ::MAX ) ;
let mut tracker = None ;
2019-04-15 17:15:50 -07:00
2021-04-05 09:35:14 -07:00
for ( i , ( slot , _t ) ) in slice . iter ( ) . rev ( ) . enumerate ( ) {
2021-04-12 08:52:24 -07:00
if ( rv . is_none ( ) | | * slot > current_max ) & & * slot < = max_root {
2021-04-05 09:35:14 -07:00
let lock = match tracker {
Some ( inner ) = > inner ,
None = > self . roots_tracker . read ( ) . unwrap ( ) ,
} ;
2022-04-02 10:00:52 -07:00
if lock . alive_roots . contains ( slot ) {
2021-04-05 09:35:14 -07:00
rv = Some ( i ) ;
current_max = * slot ;
}
tracker = Some ( lock ) ;
}
}
rv . map ( | index | slice . len ( ) - 1 - index )
2020-09-28 16:04:46 -07:00
}
2021-12-21 15:31:48 -08:00
pub fn hold_range_in_memory < R > ( & self , range : & R , start_holding : bool , thread_pool : & ThreadPool )
2021-09-17 15:19:29 -07:00
where
2021-12-21 15:31:48 -08:00
R : RangeBounds < Pubkey > + Debug + Sync ,
2021-09-17 15:19:29 -07:00
{
let iter = self . iter ( Some ( range ) , true ) ;
2021-12-21 15:31:48 -08:00
iter . hold_range_in_memory ( range , start_holding , thread_pool ) ;
2021-09-17 15:19:29 -07:00
}
2021-09-18 20:08:58 -07:00
2022-03-23 09:53:37 -07:00
pub fn set_startup ( & self , value : Startup ) {
2021-10-15 08:40:36 -07:00
self . storage . set_startup ( value ) ;
2021-09-18 20:08:58 -07:00
}
2022-03-20 17:56:20 -07:00
pub fn get_startup_remaining_items_to_flush_estimate ( & self ) -> usize {
self . storage . get_startup_remaining_items_to_flush_estimate ( )
}
2021-10-19 13:54:06 -07:00
/// For each pubkey, find the latest account that appears in `roots` and <= `max_root`
/// call `callback`
pub ( crate ) fn scan < F > ( & self , pubkeys : & [ Pubkey ] , max_root : Option < Slot > , mut callback : F )
where
// return true if accounts index entry should be put in in_mem cache
// params:
// exists: false if not in index at all
// slot list found at slot at most max_root or empty slot list
// index in slot list where best slot was found or None if nothing found by root criteria
// pubkey looked up
// refcount of entry in index
F : FnMut ( bool , & SlotList < T > , Option < usize > , & Pubkey , RefCount ) -> bool ,
{
let empty_slot_list = vec! [ ] ;
let mut lock = None ;
let mut last_bin = self . bins ( ) ; // too big, won't match
pubkeys . iter ( ) . for_each ( | pubkey | {
let bin = self . bin_calculator . bin_from_pubkey ( pubkey ) ;
if bin ! = last_bin {
// cannot re-use lock since next pubkey is in a different bin than previous one
lock = Some ( self . account_maps [ bin ] . read ( ) . unwrap ( ) ) ;
last_bin = bin ;
}
lock . as_ref ( ) . unwrap ( ) . get_internal ( pubkey , | entry | {
let cache = match entry {
Some ( locked_entry ) = > {
let slot_list = & locked_entry . slot_list . read ( ) . unwrap ( ) ;
let found_index = self . latest_slot ( None , slot_list , max_root ) ;
callback (
true ,
slot_list ,
found_index ,
pubkey ,
locked_entry . ref_count ( ) ,
)
}
None = > callback ( false , & empty_slot_list , None , pubkey , RefCount ::MAX ) ,
} ;
( cache , ( ) )
} ) ;
} ) ;
}
2019-07-10 22:06:32 -07:00
/// Get an account
/// The latest account that appears in `ancestors` or `roots` is returned.
2020-06-08 17:38:14 -07:00
pub ( crate ) fn get (
2019-07-20 17:58:39 -07:00
& self ,
pubkey : & Pubkey ,
2020-06-08 17:38:14 -07:00
ancestors : Option < & Ancestors > ,
2020-09-28 16:04:46 -07:00
max_root : Option < Slot > ,
2021-12-13 19:16:17 -08:00
) -> AccountIndexGetResult < T > {
2021-08-04 07:18:05 -07:00
let read_lock = self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ]
. read ( )
. unwrap ( ) ;
2021-04-23 07:33:14 -07:00
let account = read_lock
. get ( pubkey )
. map ( ReadAccountMapEntry ::from_account_map_entry ) ;
match account {
Some ( locked_entry ) = > {
drop ( read_lock ) ;
let slot_list = locked_entry . slot_list ( ) ;
let found_index = self . latest_slot ( ancestors , slot_list , max_root ) ;
match found_index {
Some ( found_index ) = > AccountIndexGetResult ::Found ( locked_entry , found_index ) ,
2021-12-13 19:16:17 -08:00
None = > AccountIndexGetResult ::NotFound ,
2021-04-23 07:33:14 -07:00
}
}
2021-12-13 19:16:17 -08:00
None = > AccountIndexGetResult ::NotFound ,
2021-04-23 07:33:14 -07:00
}
2019-07-10 22:06:32 -07:00
}
2020-10-03 15:18:58 -07:00
// Get the maximum root <= `max_allowed_root` from the given `slice`
2021-04-30 13:34:38 -07:00
fn get_newest_root_in_slot_list (
2022-04-02 10:00:52 -07:00
alive_roots : & RollingBitField ,
2020-10-03 15:18:58 -07:00
slice : SlotSlice < T > ,
max_allowed_root : Option < Slot > ,
) -> Slot {
2019-06-13 17:35:16 -07:00
let mut max_root = 0 ;
2020-03-25 21:08:56 -07:00
for ( f , _ ) in slice . iter ( ) {
2020-10-03 15:18:58 -07:00
if let Some ( max_allowed_root ) = max_allowed_root {
if * f > max_allowed_root {
continue ;
}
}
2022-04-02 10:00:52 -07:00
if * f > max_root & & alive_roots . contains ( f ) {
2019-06-13 17:35:16 -07:00
max_root = * f ;
}
}
max_root
}
2022-02-16 16:23:25 -08:00
fn update_spl_token_secondary_indexes < G : GenericTokenAccount > (
& self ,
token_id : & Pubkey ,
pubkey : & Pubkey ,
account_owner : & Pubkey ,
account_data : & [ u8 ] ,
account_indexes : & AccountSecondaryIndexes ,
) {
if * account_owner = = * token_id {
if account_indexes . contains ( & AccountIndex ::SplTokenOwner ) {
if let Some ( owner_key ) = G ::unpack_account_owner ( account_data ) {
if account_indexes . include_key ( owner_key ) {
self . spl_token_owner_index . insert ( owner_key , pubkey ) ;
}
}
}
if account_indexes . contains ( & AccountIndex ::SplTokenMint ) {
if let Some ( mint_key ) = G ::unpack_account_mint ( account_data ) {
if account_indexes . include_key ( mint_key ) {
self . spl_token_mint_index . insert ( mint_key , pubkey ) ;
}
}
}
}
}
2022-04-15 11:30:03 -07:00
/// log any secondary index counts, if non-zero
pub ( crate ) fn log_secondary_indexes ( & self ) {
if ! self . program_id_index . index . is_empty ( ) {
info! ( " secondary index: {:?} " , AccountIndex ::ProgramId ) ;
self . program_id_index . log_contents ( ) ;
}
if ! self . spl_token_mint_index . index . is_empty ( ) {
info! ( " secondary index: {:?} " , AccountIndex ::SplTokenMint ) ;
self . spl_token_mint_index . log_contents ( ) ;
}
if ! self . spl_token_owner_index . index . is_empty ( ) {
info! ( " secondary index: {:?} " , AccountIndex ::SplTokenOwner ) ;
self . spl_token_owner_index . log_contents ( ) ;
}
}
2021-05-17 09:58:33 -07:00
pub ( crate ) fn update_secondary_indexes (
2020-12-31 18:06:03 -08:00
& self ,
pubkey : & Pubkey ,
2022-02-23 15:01:23 -08:00
account : & impl ReadableAccount ,
2021-05-10 07:22:48 -07:00
account_indexes : & AccountSecondaryIndexes ,
2020-12-31 18:06:03 -08:00
) {
2021-01-23 08:05:05 -08:00
if account_indexes . is_empty ( ) {
return ;
}
2022-02-23 15:01:23 -08:00
let account_owner = account . owner ( ) ;
let account_data = account . data ( ) ;
2021-05-11 15:06:22 -07:00
if account_indexes . contains ( & AccountIndex ::ProgramId )
& & account_indexes . include_key ( account_owner )
{
2021-05-12 15:29:30 -07:00
self . program_id_index . insert ( account_owner , pubkey ) ;
2020-12-31 18:06:03 -08:00
}
// Note because of the below check below on the account data length, when an
2021-03-09 13:06:07 -08:00
// account hits zero lamports and is reset to AccountSharedData::Default, then we skip
2020-12-31 18:06:03 -08:00
// the below updates to the secondary indexes.
//
// Skipping means not updating secondary index to mark the account as missing.
// This doesn't introduce false positives during a scan because the caller to scan
// provides the ancestors to check. So even if a zero-lamport account is not yet
// removed from the secondary index, the scan function will:
// 1) consult the primary index via `get(&pubkey, Some(ancestors), max_root)`
// and find the zero-lamport version
2021-03-09 13:06:07 -08:00
// 2) When the fetch from storage occurs, it will return AccountSharedData::Default
2020-12-31 18:06:03 -08:00
// (as persisted tombstone for snapshots). This will then ultimately be
// filtered out by post-scan filters, like in `get_filtered_spl_token_accounts_by_owner()`.
2022-02-16 16:23:25 -08:00
self . update_spl_token_secondary_indexes ::< inline_spl_token ::Account > (
& inline_spl_token ::id ( ) ,
pubkey ,
account_owner ,
account_data ,
account_indexes ,
) ;
self . update_spl_token_secondary_indexes ::< inline_spl_token_2022 ::Account > (
& inline_spl_token_2022 ::id ( ) ,
pubkey ,
account_owner ,
account_data ,
account_indexes ,
) ;
2020-12-31 18:06:03 -08:00
}
2021-06-28 13:03:57 -07:00
fn get_account_maps_write_lock ( & self , pubkey : & Pubkey ) -> AccountMapsWriteLock < T > {
2021-08-04 07:18:05 -07:00
self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ]
. write ( )
. unwrap ( )
2021-05-14 13:27:10 -07:00
}
2021-06-28 13:03:57 -07:00
pub ( crate ) fn get_account_maps_read_lock ( & self , pubkey : & Pubkey ) -> AccountMapsReadLock < T > {
2021-08-04 07:18:05 -07:00
self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ]
. read ( )
. unwrap ( )
}
pub fn bins ( & self ) -> usize {
self . account_maps . len ( )
2021-05-21 11:59:32 -07:00
}
2021-05-20 08:29:13 -07:00
// Same functionally to upsert, but:
// 1. operates on a batch of items
// 2. holds the write lock for the duration of adding the items
2021-05-17 09:58:33 -07:00
// Can save time when inserting lots of new keys.
// But, does NOT update secondary index
2021-05-20 08:29:13 -07:00
// This is designed to be called at startup time.
#[ allow(clippy::needless_collect) ]
2021-07-07 13:35:35 -07:00
pub ( crate ) fn insert_new_if_missing_into_primary_index (
& self ,
2021-01-23 08:05:05 -08:00
slot : Slot ,
2021-06-25 12:31:55 -07:00
item_len : usize ,
2021-07-07 13:35:35 -07:00
items : impl Iterator < Item = ( Pubkey , T ) > ,
2021-06-25 06:36:55 -07:00
) -> ( Vec < Pubkey > , u64 ) {
2021-07-07 13:36:40 -07:00
// big enough so not likely to re-allocate, small enough to not over-allocate by too much
// this assumes the largest bin contains twice the expected amount of the average size per bin
2021-08-04 07:18:05 -07:00
let bins = self . bins ( ) ;
let expected_items_per_bin = item_len * 2 / bins ;
2021-09-23 12:59:37 -07:00
// offset bin 0 in the 'binned' array by a random amount.
// This results in calls to insert_new_entry_if_missing_with_lock from different threads starting at different bins.
let random_offset = thread_rng ( ) . gen_range ( 0 , bins ) ;
2021-11-22 13:52:45 -08:00
let use_disk = self . storage . storage . disk . is_some ( ) ;
2021-08-04 07:18:05 -07:00
let mut binned = ( 0 .. bins )
2021-05-20 08:29:13 -07:00
. into_iter ( )
2021-09-23 12:59:37 -07:00
. map ( | mut pubkey_bin | {
// opposite of (pubkey_bin + random_offset) % bins
pubkey_bin = if pubkey_bin < random_offset {
pubkey_bin + bins - random_offset
} else {
pubkey_bin - random_offset
} ;
( pubkey_bin , Vec ::with_capacity ( expected_items_per_bin ) )
} )
2021-06-28 13:03:57 -07:00
. collect ::< Vec < _ > > ( ) ;
2021-09-10 16:46:08 -07:00
let mut dirty_pubkeys = items
. filter_map ( | ( pubkey , account_info ) | {
2021-09-23 12:59:37 -07:00
let pubkey_bin = self . bin_calculator . bin_from_pubkey ( & pubkey ) ;
let binned_index = ( pubkey_bin + random_offset ) % bins ;
2021-09-10 16:46:08 -07:00
// this value is equivalent to what update() below would have created if we inserted a new item
let is_zero_lamport = account_info . is_zero_lamport ( ) ;
let result = if is_zero_lamport { Some ( pubkey ) } else { None } ;
2021-11-22 13:52:45 -08:00
let info = PreAllocatedAccountMapEntry ::new (
slot ,
account_info ,
& self . storage . storage ,
use_disk ,
) ;
2021-09-23 12:59:37 -07:00
binned [ binned_index ] . 1. push ( ( pubkey , info ) ) ;
2021-09-10 16:46:08 -07:00
result
} )
. collect ::< Vec < _ > > ( ) ;
2021-06-28 13:03:57 -07:00
binned . retain ( | x | ! x . 1. is_empty ( ) ) ;
let insertion_time = AtomicU64 ::new ( 0 ) ;
2021-09-10 16:46:08 -07:00
binned . into_iter ( ) . for_each ( | ( pubkey_bin , items ) | {
2021-09-15 10:36:08 -07:00
let w_account_maps = self . account_maps [ pubkey_bin ] . write ( ) . unwrap ( ) ;
2021-09-10 16:46:08 -07:00
let mut insert_time = Measure ::start ( " insert_into_primary_index " ) ;
items . into_iter ( ) . for_each ( | ( pubkey , new_item ) | {
2021-11-19 15:17:07 -08:00
if let InsertNewEntryResults ::ExistedNewEntryNonZeroLamports =
w_account_maps . insert_new_entry_if_missing_with_lock ( pubkey , new_item )
{
// zero lamports were already added to dirty_pubkeys above
dirty_pubkeys . push ( pubkey ) ;
2021-09-10 16:46:08 -07:00
}
} ) ;
insert_time . stop ( ) ;
insertion_time . fetch_add ( insert_time . as_us ( ) , Ordering ::Relaxed ) ;
} ) ;
2021-06-24 12:52:11 -07:00
2021-08-04 16:33:47 -07:00
( dirty_pubkeys , insertion_time . load ( Ordering ::Relaxed ) )
2021-01-23 08:05:05 -08:00
}
2022-02-23 15:33:06 -08:00
/// Updates the given pubkey at the given slot with the new account information.
/// on return, the index's previous account info may be returned in 'reclaims' depending on 'previous_slot_entry_was_cached'
2020-10-21 17:05:27 -07:00
pub fn upsert (
2019-07-20 17:58:39 -07:00
& self ,
2022-02-25 10:58:08 -08:00
new_slot : Slot ,
2022-03-03 06:40:48 -08:00
old_slot : Slot ,
2019-07-20 17:58:39 -07:00
pubkey : & Pubkey ,
2022-02-23 15:01:23 -08:00
account : & impl ReadableAccount ,
2021-05-10 07:22:48 -07:00
account_indexes : & AccountSecondaryIndexes ,
2019-07-20 17:58:39 -07:00
account_info : T ,
2020-03-25 21:08:56 -07:00
reclaims : & mut SlotList < T > ,
2021-08-09 06:58:59 -07:00
previous_slot_entry_was_cached : bool ,
2021-07-27 06:46:27 -07:00
) {
2021-11-30 09:36:46 -08:00
// vast majority of updates are to item already in accounts index, so store as raw to avoid unnecessary allocations
let store_raw = true ;
2021-07-27 06:46:27 -07:00
// We don't atomically update both primary index and secondary index together.
// This certainly creates a small time window with inconsistent state across the two indexes.
// However, this is acceptable because:
//
// - A strict consistent view at any given moment of time is not necessary, because the only
// use case for the secondary index is `scan`, and `scans` are only supported/require consistency
// on frozen banks, and this inconsistency is only possible on working banks.
//
// - The secondary index is never consulted as primary source of truth for gets/stores.
// So, what the accounts_index sees alone is sufficient as a source of truth for other non-scan
// account operations.
2022-02-25 10:58:08 -08:00
let new_item = PreAllocatedAccountMapEntry ::new (
new_slot ,
account_info ,
& self . storage . storage ,
store_raw ,
) ;
2021-08-05 06:45:08 -07:00
let map = & self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ] ;
2021-09-23 17:19:27 -07:00
{
let r_account_maps = map . read ( ) . unwrap ( ) ;
2022-02-25 10:58:08 -08:00
r_account_maps . upsert (
pubkey ,
new_item ,
2022-03-03 06:40:48 -08:00
Some ( old_slot ) ,
2022-02-25 10:58:08 -08:00
reclaims ,
previous_slot_entry_was_cached ,
) ;
2021-07-27 06:46:27 -07:00
}
2022-02-23 15:01:23 -08:00
self . update_secondary_indexes ( pubkey , account , account_indexes ) ;
2019-04-15 17:15:50 -07:00
}
2019-05-30 21:31:35 -07:00
2020-03-12 22:14:37 -07:00
pub fn unref_from_storage ( & self , pubkey : & Pubkey ) {
2021-10-14 06:36:53 -07:00
let map = & self . account_maps [ self . bin_calculator . bin_from_pubkey ( pubkey ) ] ;
map . read ( ) . unwrap ( ) . unref ( pubkey )
2020-03-12 22:14:37 -07:00
}
pub fn ref_count_from_storage ( & self , pubkey : & Pubkey ) -> RefCount {
2020-10-21 17:05:27 -07:00
if let Some ( locked_entry ) = self . get_account_read_entry ( pubkey ) {
2021-08-09 06:59:56 -07:00
locked_entry . ref_count ( )
2020-03-12 22:14:37 -07:00
} else {
0
}
}
2021-05-12 15:29:30 -07:00
fn purge_secondary_indexes_by_inner_key < ' a > (
2021-01-17 20:31:03 -08:00
& ' a self ,
2020-12-31 18:06:03 -08:00
inner_key : & Pubkey ,
2021-05-10 07:22:48 -07:00
account_indexes : & AccountSecondaryIndexes ,
2021-05-12 15:29:30 -07:00
) {
2020-12-31 18:06:03 -08:00
if account_indexes . contains ( & AccountIndex ::ProgramId ) {
2021-05-12 15:29:30 -07:00
self . program_id_index . remove_by_inner_key ( inner_key ) ;
2020-12-31 18:06:03 -08:00
}
if account_indexes . contains ( & AccountIndex ::SplTokenOwner ) {
2021-05-12 15:29:30 -07:00
self . spl_token_owner_index . remove_by_inner_key ( inner_key ) ;
2020-12-31 18:06:03 -08:00
}
if account_indexes . contains ( & AccountIndex ::SplTokenMint ) {
2021-05-12 15:29:30 -07:00
self . spl_token_mint_index . remove_by_inner_key ( inner_key ) ;
2020-12-31 18:06:03 -08:00
}
}
2020-09-28 16:04:46 -07:00
fn purge_older_root_entries (
& self ,
2021-04-30 13:34:38 -07:00
slot_list : & mut SlotList < T > ,
2020-09-28 16:04:46 -07:00
reclaims : & mut SlotList < T > ,
max_clean_root : Option < Slot > ,
) {
2021-03-04 23:16:53 -08:00
let roots_tracker = & self . roots_tracker . read ( ) . unwrap ( ) ;
2022-04-02 10:00:52 -07:00
let newest_root_in_slot_list = Self ::get_newest_root_in_slot_list (
& roots_tracker . alive_roots ,
slot_list ,
max_clean_root ,
) ;
let max_clean_root =
max_clean_root . unwrap_or_else ( | | roots_tracker . alive_roots . max_inclusive ( ) ) ;
2020-03-02 21:57:25 -08:00
2021-04-30 13:34:38 -07:00
slot_list . retain ( | ( slot , value ) | {
let should_purge =
Self ::can_purge_older_entries ( max_clean_root , newest_root_in_slot_list , * slot )
& & ! value . is_cached ( ) ;
2020-12-31 18:06:03 -08:00
if should_purge {
2021-09-01 06:13:08 -07:00
reclaims . push ( ( * slot , * value ) ) ;
2020-12-31 18:06:03 -08:00
}
2021-04-30 13:34:38 -07:00
! should_purge
2020-12-31 18:06:03 -08:00
} ) ;
2020-03-02 21:57:25 -08:00
}
2020-09-28 16:04:46 -07:00
pub fn clean_rooted_entries (
& self ,
pubkey : & Pubkey ,
reclaims : & mut SlotList < T > ,
max_clean_root : Option < Slot > ,
) {
2021-04-30 13:34:38 -07:00
let mut is_slot_list_empty = false ;
2021-09-27 14:24:19 -07:00
self . slot_list_mut ( pubkey , | slot_list | {
self . purge_older_root_entries ( slot_list , reclaims , max_clean_root ) ;
is_slot_list_empty = slot_list . is_empty ( ) ;
} ) ;
2021-04-30 13:34:38 -07:00
// If the slot list is empty, remove the pubkey from `account_maps`. Make sure to grab the
// lock and double check the slot list is still empty, because another writer could have
// locked and inserted the pubkey inbetween when `is_slot_list_empty=true` and the call to
// remove() below.
if is_slot_list_empty {
2021-09-15 10:36:08 -07:00
let w_maps = self . get_account_maps_write_lock ( pubkey ) ;
2021-09-12 12:05:44 -07:00
w_maps . remove_if_slot_list_empty ( * pubkey ) ;
2021-04-30 13:34:38 -07:00
}
2020-03-02 21:57:25 -08:00
}
2021-04-30 13:34:38 -07:00
/// When can an entry be purged?
///
/// If we get a slot update where slot != newest_root_in_slot_list for an account where slot <
/// max_clean_root, then we know it's safe to delete because:
///
/// a) If slot < newest_root_in_slot_list, then we know the update is outdated by a later rooted
/// update, namely the one in newest_root_in_slot_list
///
/// b) If slot > newest_root_in_slot_list, then because slot < max_clean_root and we know there are
/// no roots in the slot list between newest_root_in_slot_list and max_clean_root, (otherwise there
/// would be a bigger newest_root_in_slot_list, which is a contradiction), then we know slot must be
/// an unrooted slot less than max_clean_root and thus safe to clean as well.
fn can_purge_older_entries (
max_clean_root : Slot ,
newest_root_in_slot_list : Slot ,
slot : Slot ,
) -> bool {
slot < max_clean_root & & slot ! = newest_root_in_slot_list
2019-04-15 17:15:50 -07:00
}
2019-06-10 18:15:39 -07:00
2021-05-24 13:51:17 -07:00
/// Given a list of slots, return a new list of only the slots that are rooted
pub fn get_rooted_from_list < ' a > ( & self , slots : impl Iterator < Item = & ' a Slot > ) -> Vec < Slot > {
let roots_tracker = self . roots_tracker . read ( ) . unwrap ( ) ;
slots
. filter_map ( | s | {
2022-04-02 10:00:52 -07:00
if roots_tracker . alive_roots . contains ( s ) {
2021-05-24 13:51:17 -07:00
Some ( * s )
} else {
None
}
} )
. collect ( )
}
2022-04-02 10:00:52 -07:00
pub fn is_alive_root ( & self , slot : Slot ) -> bool {
self . roots_tracker
. read ( )
. unwrap ( )
. alive_roots
. contains ( & slot )
2019-04-15 17:15:50 -07:00
}
2019-06-10 18:15:39 -07:00
2021-01-11 17:00:23 -08:00
pub fn add_root ( & self , slot : Slot , caching_enabled : bool ) {
2020-10-21 17:05:27 -07:00
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
2022-02-08 07:31:32 -08:00
// `AccountsDb::flush_accounts_cache()` relies on roots being added in order
2022-04-02 10:00:52 -07:00
assert! ( slot > = w_roots_tracker . alive_roots . max_inclusive ( ) ) ;
2022-03-30 06:52:45 -07:00
// 'slot' is a root, so it is both 'root' and 'original'
2022-04-02 10:00:52 -07:00
w_roots_tracker . alive_roots . insert ( slot ) ;
2022-04-04 07:12:12 -07:00
w_roots_tracker . historical_roots . insert ( slot ) ;
2021-01-11 17:00:23 -08:00
// we delay cleaning until flushing!
if ! caching_enabled {
w_roots_tracker . uncleaned_roots . insert ( slot ) ;
}
}
pub fn add_uncleaned_roots < I > ( & self , roots : I )
where
I : IntoIterator < Item = Slot > ,
{
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
w_roots_tracker . uncleaned_roots . extend ( roots ) ;
2020-11-16 17:23:11 -08:00
}
2022-02-07 11:26:53 -08:00
pub fn max_root_inclusive ( & self ) -> Slot {
2022-04-02 10:00:52 -07:00
self . roots_tracker
. read ( )
. unwrap ( )
. alive_roots
. max_inclusive ( )
2019-04-15 17:15:50 -07:00
}
2020-11-16 17:23:11 -08:00
2022-04-04 07:12:12 -07:00
/// return the lowest original root >= slot, including historical_roots and ancestors
2022-03-30 06:52:45 -07:00
pub fn get_next_original_root (
& self ,
slot : Slot ,
ancestors : Option < & Ancestors > ,
) -> Option < Slot > {
{
let roots_tracker = self . roots_tracker . read ( ) . unwrap ( ) ;
2022-04-04 07:12:12 -07:00
for root in slot .. roots_tracker . historical_roots . max_exclusive ( ) {
if roots_tracker . historical_roots . contains ( & root ) {
2022-03-30 06:52:45 -07:00
return Some ( root ) ;
}
}
}
// ancestors are higher than roots, so look for roots first
if let Some ( ancestors ) = ancestors {
let min = std ::cmp ::max ( slot , ancestors . min_slot ( ) ) ;
for root in min ..= ancestors . max_slot ( ) {
if ancestors . contains_key ( & root ) {
return Some ( root ) ;
}
}
}
None
}
2022-04-04 07:12:12 -07:00
/// roots are inserted into 'historical_roots' and 'roots' as a new root is made.
2022-03-30 06:52:45 -07:00
/// roots are removed form 'roots' as all entries in the append vec become outdated.
2022-04-04 07:12:12 -07:00
/// This function exists to clean older entries from 'historical_roots'.
/// all roots < 'oldest_slot_to_keep' are removed from 'historical_roots'.
2022-04-02 10:01:13 -07:00
pub fn remove_old_historical_roots ( & self , oldest_slot_to_keep : Slot , keep : & HashSet < Slot > ) {
2022-04-23 06:28:49 -07:00
let mut roots = self
. roots_tracker
. read ( )
. unwrap ( )
2022-04-04 07:12:12 -07:00
. historical_roots
2022-03-30 06:52:45 -07:00
. get_all_less_than ( oldest_slot_to_keep ) ;
roots . retain ( | root | ! keep . contains ( root ) ) ;
if ! roots . is_empty ( ) {
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
roots . into_iter ( ) . for_each ( | root | {
2022-04-04 07:12:12 -07:00
w_roots_tracker . historical_roots . remove ( & root ) ;
2022-03-30 06:52:45 -07:00
} ) ;
}
}
2019-10-23 22:01:22 -07:00
/// Remove the slot when the storage for the slot is freed
/// Accounts no longer reference this slot.
2022-01-31 09:40:19 -08:00
/// return true if slot was a root
2021-10-06 18:04:26 -07:00
pub fn clean_dead_slot ( & self , slot : Slot , stats : & mut AccountsIndexRootsStats ) -> bool {
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
let removed_from_unclean_roots = w_roots_tracker . uncleaned_roots . remove ( & slot ) ;
let removed_from_previous_uncleaned_roots =
w_roots_tracker . previous_uncleaned_roots . remove ( & slot ) ;
2022-04-02 10:00:52 -07:00
if ! w_roots_tracker . alive_roots . remove ( & slot ) {
2021-10-06 18:04:26 -07:00
if removed_from_unclean_roots {
error! ( " clean_dead_slot-removed_from_unclean_roots: {} " , slot ) ;
inc_new_counter_error! ( " clean_dead_slot-removed_from_unclean_roots " , 1 , 1 ) ;
2021-05-05 13:17:45 -07:00
}
2021-10-06 18:04:26 -07:00
if removed_from_previous_uncleaned_roots {
error! (
" clean_dead_slot-removed_from_previous_uncleaned_roots: {} " ,
slot
) ;
inc_new_counter_error! (
" clean_dead_slot-removed_from_previous_uncleaned_roots " ,
1 ,
1
) ;
}
false
} else {
2022-05-10 11:56:30 -07:00
stats . roots_len = Some ( w_roots_tracker . alive_roots . len ( ) ) ;
stats . uncleaned_roots_len = Some ( w_roots_tracker . uncleaned_roots . len ( ) ) ;
stats . previous_uncleaned_roots_len =
Some ( w_roots_tracker . previous_uncleaned_roots . len ( ) ) ;
stats . roots_range = Some ( w_roots_tracker . alive_roots . range_width ( ) ) ;
stats . historical_roots_len = Some ( w_roots_tracker . historical_roots . len ( ) ) ;
2021-10-06 18:04:26 -07:00
true
}
2020-06-11 22:51:43 -07:00
}
2022-04-02 10:00:52 -07:00
pub fn min_alive_root ( & self ) -> Option < Slot > {
self . roots_tracker . read ( ) . unwrap ( ) . min_alive_root ( )
2021-06-14 06:53:07 -07:00
}
2020-10-21 17:05:27 -07:00
pub fn reset_uncleaned_roots ( & self , max_clean_root : Option < Slot > ) -> HashSet < Slot > {
2020-09-28 16:04:46 -07:00
let mut cleaned_roots = HashSet ::new ( ) ;
2020-10-21 17:05:27 -07:00
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
w_roots_tracker . uncleaned_roots . retain ( | root | {
2020-09-28 16:04:46 -07:00
let is_cleaned = max_clean_root
. map ( | max_clean_root | * root < = max_clean_root )
. unwrap_or ( true ) ;
if is_cleaned {
cleaned_roots . insert ( * root ) ;
}
// Only keep the slots that have yet to be cleaned
! is_cleaned
} ) ;
2020-10-21 17:05:27 -07:00
std ::mem ::replace ( & mut w_roots_tracker . previous_uncleaned_roots , cleaned_roots )
}
2021-01-23 04:02:44 -08:00
#[ cfg(test) ]
pub fn clear_uncleaned_roots ( & self , max_clean_root : Option < Slot > ) -> HashSet < Slot > {
let mut cleaned_roots = HashSet ::new ( ) ;
let mut w_roots_tracker = self . roots_tracker . write ( ) . unwrap ( ) ;
w_roots_tracker . uncleaned_roots . retain ( | root | {
let is_cleaned = max_clean_root
. map ( | max_clean_root | * root < = max_clean_root )
. unwrap_or ( true ) ;
if is_cleaned {
cleaned_roots . insert ( * root ) ;
}
// Only keep the slots that have yet to be cleaned
! is_cleaned
} ) ;
cleaned_roots
}
2020-10-21 17:05:27 -07:00
pub fn is_uncleaned_root ( & self , slot : Slot ) -> bool {
self . roots_tracker
. read ( )
. unwrap ( )
. uncleaned_roots
. contains ( & slot )
}
2022-04-02 10:00:52 -07:00
pub fn num_alive_roots ( & self ) -> usize {
self . roots_tracker . read ( ) . unwrap ( ) . alive_roots . len ( )
2020-12-21 21:33:37 -08:00
}
2022-04-02 10:00:52 -07:00
pub fn all_alive_roots ( & self ) -> Vec < Slot > {
2021-04-12 10:11:33 -07:00
let tracker = self . roots_tracker . read ( ) . unwrap ( ) ;
2022-04-02 10:00:52 -07:00
tracker . alive_roots . get_all ( )
2020-10-21 17:05:27 -07:00
}
#[ cfg(test) ]
pub fn clear_roots ( & self ) {
2022-04-02 10:00:52 -07:00
self . roots_tracker . write ( ) . unwrap ( ) . alive_roots . clear ( )
2020-10-21 17:05:27 -07:00
}
2021-10-15 11:18:00 -07:00
pub fn clone_uncleaned_roots ( & self ) -> HashSet < Slot > {
self . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . clone ( )
}
2020-10-21 17:05:27 -07:00
pub fn uncleaned_roots_len ( & self ) -> usize {
self . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( )
2019-04-15 17:15:50 -07:00
}
2020-12-31 18:06:03 -08:00
#[ cfg(test) ]
// filter any rooted entries and return them along with a bool that indicates
// if this account has no more entries. Note this does not update the secondary
// indexes!
pub fn purge_roots ( & self , pubkey : & Pubkey ) -> ( SlotList < T > , bool ) {
2021-09-27 14:24:19 -07:00
self . slot_list_mut ( pubkey , | slot_list | {
2020-12-31 18:06:03 -08:00
let reclaims = self . get_rooted_entries ( slot_list , None ) ;
2022-04-02 10:00:52 -07:00
slot_list . retain ( | ( slot , _ ) | ! self . is_alive_root ( * slot ) ) ;
2020-12-31 18:06:03 -08:00
( reclaims , slot_list . is_empty ( ) )
} )
2021-09-27 14:24:19 -07:00
. unwrap ( )
2020-12-31 18:06:03 -08:00
}
2019-04-15 17:15:50 -07:00
}
#[ cfg(test) ]
2020-12-31 18:06:03 -08:00
pub mod tests {
2021-12-03 09:00:31 -08:00
use {
super ::* ,
2022-02-16 16:23:25 -08:00
crate ::inline_spl_token ::* ,
solana_sdk ::{
2022-02-23 15:01:23 -08:00
account ::{ AccountSharedData , WritableAccount } ,
2022-02-16 16:23:25 -08:00
pubkey ::PUBKEY_BYTES ,
signature ::{ Keypair , Signer } ,
} ,
2021-12-03 09:00:31 -08:00
std ::ops ::RangeInclusive ,
} ;
2019-04-15 17:15:50 -07:00
2020-12-31 18:06:03 -08:00
pub enum SecondaryIndexTypes < ' a > {
RwLock ( & ' a SecondaryIndex < RwLockSecondaryIndexEntry > ) ,
DashMap ( & ' a SecondaryIndex < DashMapSecondaryIndexEntry > ) ,
}
2021-05-10 07:22:48 -07:00
pub fn spl_token_mint_index_enabled ( ) -> AccountSecondaryIndexes {
2020-12-31 18:06:03 -08:00
let mut account_indexes = HashSet ::new ( ) ;
account_indexes . insert ( AccountIndex ::SplTokenMint ) ;
2021-05-11 15:06:22 -07:00
AccountSecondaryIndexes {
indexes : account_indexes ,
keys : None ,
}
2020-12-31 18:06:03 -08:00
}
2021-05-10 07:22:48 -07:00
pub fn spl_token_owner_index_enabled ( ) -> AccountSecondaryIndexes {
2020-12-31 18:06:03 -08:00
let mut account_indexes = HashSet ::new ( ) ;
account_indexes . insert ( AccountIndex ::SplTokenOwner ) ;
2021-05-11 15:06:22 -07:00
AccountSecondaryIndexes {
indexes : account_indexes ,
keys : None ,
}
2020-12-31 18:06:03 -08:00
}
2021-12-13 19:16:17 -08:00
impl < T : IndexValue > AccountIndexGetResult < T > {
2021-04-23 07:33:14 -07:00
pub fn unwrap ( self ) -> ( ReadAccountMapEntry < T > , usize ) {
match self {
AccountIndexGetResult ::Found ( lock , size ) = > ( lock , size ) ,
_ = > {
panic! ( " trying to unwrap AccountIndexGetResult with non-Success result " ) ;
}
}
}
pub fn is_none ( & self ) -> bool {
! self . is_some ( )
}
pub fn is_some ( & self ) -> bool {
matches! ( self , AccountIndexGetResult ::Found ( _lock , _size ) )
}
pub fn map < V , F : FnOnce ( ( ReadAccountMapEntry < T > , usize ) ) -> V > ( self , f : F ) -> Option < V > {
match self {
AccountIndexGetResult ::Found ( lock , size ) = > Some ( f ( ( lock , size ) ) ) ,
_ = > None ,
}
}
}
2021-05-10 07:22:48 -07:00
fn create_dashmap_secondary_index_state ( ) -> ( usize , usize , AccountSecondaryIndexes ) {
2020-12-31 18:06:03 -08:00
{
// Check that we're actually testing the correct variant
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-12-31 18:06:03 -08:00
let _type_check = SecondaryIndexTypes ::DashMap ( & index . spl_token_mint_index ) ;
}
( 0 , PUBKEY_BYTES , spl_token_mint_index_enabled ( ) )
}
2021-05-10 07:22:48 -07:00
fn create_rwlock_secondary_index_state ( ) -> ( usize , usize , AccountSecondaryIndexes ) {
2020-12-31 18:06:03 -08:00
{
// Check that we're actually testing the correct variant
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-12-31 18:06:03 -08:00
let _type_check = SecondaryIndexTypes ::RwLock ( & index . spl_token_owner_index ) ;
}
(
SPL_TOKEN_ACCOUNT_OWNER_OFFSET ,
SPL_TOKEN_ACCOUNT_OWNER_OFFSET + PUBKEY_BYTES ,
spl_token_owner_index_enabled ( ) ,
)
}
2021-09-23 06:11:32 -07:00
impl < T : IndexValue > Clone for PreAllocatedAccountMapEntry < T > {
fn clone ( & self ) -> Self {
// clone the AccountMapEntryInner into a new Arc
2021-11-22 13:52:45 -08:00
match self {
PreAllocatedAccountMapEntry ::Entry ( entry ) = > {
let ( slot , account_info ) = entry . slot_list . read ( ) . unwrap ( ) [ 0 ] ;
let meta = AccountMapEntryMeta {
dirty : AtomicBool ::new ( entry . dirty ( ) ) ,
age : AtomicU8 ::new ( entry . age ( ) ) ,
} ;
PreAllocatedAccountMapEntry ::Entry ( Arc ::new ( AccountMapEntryInner ::new (
vec! [ ( slot , account_info ) ] ,
entry . ref_count ( ) ,
meta ,
) ) )
}
PreAllocatedAccountMapEntry ::Raw ( raw ) = > PreAllocatedAccountMapEntry ::Raw ( * raw ) ,
}
2021-09-23 06:11:32 -07:00
}
}
2021-12-15 07:09:56 -08:00
impl < T : IndexValue > AccountsIndex < T > {
/// provides the ability to refactor this function on the api without bloody changes
pub fn get_for_tests (
& self ,
pubkey : & Pubkey ,
ancestors : Option < & Ancestors > ,
max_root : Option < Slot > ,
) -> AccountIndexGetResult < T > {
self . get ( pubkey , ancestors , max_root )
}
}
2022-03-30 06:52:45 -07:00
#[ test ]
fn test_get_next_original_root ( ) {
let ancestors = None ;
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , None ) ;
}
// roots are now [1]. 0 and 1 both return 1
index . add_root ( 1 , true ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 2 , ancestors ) , None ) ; // no roots after 1, so asking for root >= 2 is None
// roots are now [1, 3]. 0 and 1 both return 1. 2 and 3 both return 3
index . add_root ( 3 , true ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
for slot in 2 .. 4 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 3 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 4 , ancestors ) , None ) ; // no roots after 3, so asking for root >= 4 is None
}
#[ test ]
fn test_get_next_original_root_ancestors ( ) {
let orig_ancestors = Ancestors ::default ( ) ;
let ancestors = Some ( & orig_ancestors ) ;
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , None ) ;
}
// ancestors are now [1]. 0 and 1 both return 1
let orig_ancestors = Ancestors ::from ( vec! [ 1 ] ) ;
let ancestors = Some ( & orig_ancestors ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 2 , ancestors ) , None ) ; // no roots after 1, so asking for root >= 2 is None
// ancestors are now [1, 3]. 0 and 1 both return 1. 2 and 3 both return 3
let orig_ancestors = Ancestors ::from ( vec! [ 1 , 3 ] ) ;
let ancestors = Some ( & orig_ancestors ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
for slot in 2 .. 4 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 3 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 4 , ancestors ) , None ) ; // no roots after 3, so asking for root >= 4 is None
}
#[ test ]
fn test_get_next_original_root_roots_and_ancestors ( ) {
let orig_ancestors = Ancestors ::default ( ) ;
let ancestors = Some ( & orig_ancestors ) ;
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , None ) ;
}
// roots are now [1]. 0 and 1 both return 1
index . add_root ( 1 , true ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 2 , ancestors ) , None ) ; // no roots after 1, so asking for root >= 2 is None
// roots are now [1] and ancestors are now [3]. 0 and 1 both return 1. 2 and 3 both return 3
let orig_ancestors = Ancestors ::from ( vec! [ 3 ] ) ;
let ancestors = Some ( & orig_ancestors ) ;
for slot in 0 .. 2 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 1 ) ) ;
}
for slot in 2 .. 4 {
assert_eq! ( index . get_next_original_root ( slot , ancestors ) , Some ( 3 ) ) ;
}
assert_eq! ( index . get_next_original_root ( 4 , ancestors ) , None ) ; // no roots after 3, so asking for root >= 4 is None
}
#[ test ]
2022-04-02 10:01:13 -07:00
fn test_remove_old_historical_roots ( ) {
2022-03-30 06:52:45 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
index . add_root ( 1 , true ) ;
index . add_root ( 2 , true ) ;
assert_eq! (
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( ) ,
2022-03-30 06:52:45 -07:00
vec! [ 1 , 2 ]
) ;
let empty_hash_set = HashSet ::default ( ) ;
2022-04-02 10:01:13 -07:00
index . remove_old_historical_roots ( 2 , & empty_hash_set ) ;
2022-03-30 06:52:45 -07:00
assert_eq! (
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( ) ,
2022-03-30 06:52:45 -07:00
vec! [ 2 ]
) ;
2022-04-02 10:01:13 -07:00
index . remove_old_historical_roots ( 3 , & empty_hash_set ) ;
2022-03-30 06:52:45 -07:00
assert! (
index
. roots_tracker
. read ( )
. unwrap ( )
2022-04-04 07:12:12 -07:00
. historical_roots
2022-03-30 06:52:45 -07:00
. is_empty ( ) ,
" {:?} " ,
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( )
2022-03-30 06:52:45 -07:00
) ;
// now use 'keep'
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
index . add_root ( 1 , true ) ;
index . add_root ( 2 , true ) ;
let hash_set_1 = vec! [ 1 ] . into_iter ( ) . collect ( ) ;
assert_eq! (
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( ) ,
2022-03-30 06:52:45 -07:00
vec! [ 1 , 2 ]
) ;
2022-04-02 10:01:13 -07:00
index . remove_old_historical_roots ( 2 , & hash_set_1 ) ;
2022-03-30 06:52:45 -07:00
assert_eq! (
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( ) ,
2022-03-30 06:52:45 -07:00
vec! [ 1 , 2 ]
) ;
2022-04-02 10:01:13 -07:00
index . remove_old_historical_roots ( 3 , & hash_set_1 ) ;
2022-03-30 06:52:45 -07:00
assert_eq! (
2022-04-04 07:12:12 -07:00
index
. roots_tracker
. read ( )
. unwrap ( )
. historical_roots
. get_all ( ) ,
2022-03-30 06:52:45 -07:00
vec! [ 1 ]
) ;
}
2021-08-26 16:12:43 -07:00
const COLLECT_ALL_UNSORTED_FALSE : bool = false ;
2019-04-15 17:15:50 -07:00
#[ test ]
fn test_get_empty ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-04-12 08:51:57 -07:00
let ancestors = Ancestors ::default ( ) ;
2021-12-15 07:09:56 -08:00
let key = & key . pubkey ( ) ;
assert! ( index . get_for_tests ( key , Some ( & ancestors ) , None ) . is_none ( ) ) ;
assert! ( index . get_for_tests ( key , None , None ) . is_none ( ) ) ;
2019-07-10 22:06:32 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2019-07-10 22:06:32 -07:00
assert_eq! ( num , 0 ) ;
2019-04-15 17:15:50 -07:00
}
2021-05-11 15:06:22 -07:00
#[ test ]
fn test_secondary_index_include_exclude ( ) {
let pk1 = Pubkey ::new_unique ( ) ;
let pk2 = Pubkey ::new_unique ( ) ;
let mut index = AccountSecondaryIndexes ::default ( ) ;
assert! ( ! index . contains ( & AccountIndex ::ProgramId ) ) ;
index . indexes . insert ( AccountIndex ::ProgramId ) ;
assert! ( index . contains ( & AccountIndex ::ProgramId ) ) ;
assert! ( index . include_key ( & pk1 ) ) ;
assert! ( index . include_key ( & pk2 ) ) ;
let exclude = false ;
index . keys = Some ( AccountSecondaryIndexesIncludeExclude {
keys : [ pk1 ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude ,
} ) ;
assert! ( index . include_key ( & pk1 ) ) ;
assert! ( ! index . include_key ( & pk2 ) ) ;
let exclude = true ;
index . keys = Some ( AccountSecondaryIndexesIncludeExclude {
keys : [ pk1 ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude ,
} ) ;
assert! ( ! index . include_key ( & pk1 ) ) ;
assert! ( index . include_key ( & pk2 ) ) ;
let exclude = true ;
index . keys = Some ( AccountSecondaryIndexesIncludeExclude {
keys : [ pk1 , pk2 ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude ,
} ) ;
assert! ( ! index . include_key ( & pk1 ) ) ;
assert! ( ! index . include_key ( & pk2 ) ) ;
let exclude = false ;
index . keys = Some ( AccountSecondaryIndexesIncludeExclude {
keys : [ pk1 , pk2 ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude ,
} ) ;
assert! ( index . include_key ( & pk1 ) ) ;
assert! ( index . include_key ( & pk2 ) ) ;
}
2021-08-09 06:58:59 -07:00
const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE : bool = false ;
2019-04-15 17:15:50 -07:00
#[ test ]
fn test_insert_no_ancestors ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2021-04-12 08:51:57 -07:00
let ancestors = Ancestors ::default ( ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. is_none ( ) ) ;
assert! ( index . get_for_tests ( & key . pubkey ( ) , None , None ) . is_none ( ) ) ;
2019-07-10 22:06:32 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2019-07-10 22:06:32 -07:00
assert_eq! ( num , 0 ) ;
2019-04-15 17:15:50 -07:00
}
2021-05-17 09:58:33 -07:00
type AccountInfoTest = f64 ;
2021-09-14 15:51:07 -07:00
impl IndexValue for AccountInfoTest { }
2021-05-17 09:58:33 -07:00
impl IsCached for AccountInfoTest {
fn is_cached ( & self ) -> bool {
true
}
}
impl ZeroLamport for AccountInfoTest {
fn is_zero_lamport ( & self ) -> bool {
true
}
}
#[ test ]
fn test_insert_new_with_lock_no_ancestors ( ) {
let key = Keypair ::new ( ) ;
2021-05-18 16:08:37 -07:00
let pubkey = & key . pubkey ( ) ;
2021-05-17 09:58:33 -07:00
let slot = 0 ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-05-17 09:58:33 -07:00
let account_info = true ;
2021-07-07 13:35:35 -07:00
let items = vec! [ ( * pubkey , account_info ) ] ;
2021-06-25 12:31:55 -07:00
index . insert_new_if_missing_into_primary_index ( slot , items . len ( ) , items . into_iter ( ) ) ;
2021-05-17 09:58:33 -07:00
let mut ancestors = Ancestors ::default ( ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( pubkey , Some ( & ancestors ) , None )
. is_none ( ) ) ;
assert! ( index . get_for_tests ( pubkey , None , None ) . is_none ( ) ) ;
2021-05-17 09:58:33 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 0 ) ;
ancestors . insert ( slot , 0 ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( pubkey , Some ( & ancestors ) , None )
. is_some ( ) ) ;
2021-06-18 06:34:46 -07:00
assert_eq! ( index . ref_count_from_storage ( pubkey ) , 1 ) ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 1 ) ;
// not zero lamports
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< AccountInfoTest > ::default_for_tests ( ) ;
2021-05-17 09:58:33 -07:00
let account_info : AccountInfoTest = 0 as AccountInfoTest ;
2021-07-07 13:35:35 -07:00
let items = vec! [ ( * pubkey , account_info ) ] ;
2021-06-25 12:31:55 -07:00
index . insert_new_if_missing_into_primary_index ( slot , items . len ( ) , items . into_iter ( ) ) ;
2021-05-17 09:58:33 -07:00
let mut ancestors = Ancestors ::default ( ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( pubkey , Some ( & ancestors ) , None )
. is_none ( ) ) ;
assert! ( index . get_for_tests ( pubkey , None , None ) . is_none ( ) ) ;
2021-05-17 09:58:33 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 0 ) ;
ancestors . insert ( slot , 0 ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( pubkey , Some ( & ancestors ) , None )
. is_some ( ) ) ;
2021-06-18 06:34:46 -07:00
assert_eq! ( index . ref_count_from_storage ( pubkey ) , 0 ) ; // cached, so 0
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 1 ) ;
}
2021-11-30 09:36:46 -08:00
fn get_pre_allocated < T : IndexValue > (
slot : Slot ,
account_info : T ,
storage : & Arc < BucketMapHolder < T > > ,
store_raw : bool ,
to_raw_first : bool ,
) -> PreAllocatedAccountMapEntry < T > {
let entry = PreAllocatedAccountMapEntry ::new ( slot , account_info , storage , store_raw ) ;
if to_raw_first {
// convert to raw
let ( slot2 , account_info2 ) = entry . into ( ) ;
// recreate using extracted raw
PreAllocatedAccountMapEntry ::new ( slot2 , account_info2 , storage , store_raw )
} else {
entry
}
}
2021-05-19 14:21:24 -07:00
#[ test ]
fn test_new_entry ( ) {
2021-11-30 09:36:46 -08:00
for store_raw in [ false , true ] {
for to_raw_first in [ false , true ] {
let slot = 0 ;
// account_info type that IS cached
let account_info = AccountInfoTest ::default ( ) ;
let index = AccountsIndex ::default_for_tests ( ) ;
let new_entry = get_pre_allocated (
slot ,
account_info ,
& index . storage . storage ,
store_raw ,
to_raw_first ,
)
2021-11-22 13:52:45 -08:00
. into_account_map_entry ( & index . storage . storage ) ;
2021-12-02 10:09:37 -08:00
assert_eq! ( new_entry . ref_count ( ) , 0 ) ;
2021-11-30 09:36:46 -08:00
assert_eq! ( new_entry . slot_list . read ( ) . unwrap ( ) . capacity ( ) , 1 ) ;
assert_eq! (
new_entry . slot_list . read ( ) . unwrap ( ) . to_vec ( ) ,
vec! [ ( slot , account_info ) ]
) ;
2021-05-19 14:21:24 -07:00
2021-11-30 09:36:46 -08:00
// account_info type that is NOT cached
let account_info = true ;
let index = AccountsIndex ::default_for_tests ( ) ;
2021-05-19 14:21:24 -07:00
2021-11-30 09:36:46 -08:00
let new_entry = get_pre_allocated (
slot ,
account_info ,
& index . storage . storage ,
store_raw ,
to_raw_first ,
)
2021-11-22 13:52:45 -08:00
. into_account_map_entry ( & index . storage . storage ) ;
2021-12-02 10:09:37 -08:00
assert_eq! ( new_entry . ref_count ( ) , 1 ) ;
2021-11-30 09:36:46 -08:00
assert_eq! ( new_entry . slot_list . read ( ) . unwrap ( ) . capacity ( ) , 1 ) ;
assert_eq! (
new_entry . slot_list . read ( ) . unwrap ( ) . to_vec ( ) ,
vec! [ ( slot , account_info ) ]
) ;
}
}
2021-05-19 14:21:24 -07:00
}
2021-05-20 08:29:13 -07:00
#[ test ]
fn test_batch_insert ( ) {
let slot0 = 0 ;
let key0 = Keypair ::new ( ) . pubkey ( ) ;
let key1 = Keypair ::new ( ) . pubkey ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-05-20 08:29:13 -07:00
let account_infos = [ true , false ] ;
2021-07-07 13:35:35 -07:00
let items = vec! [ ( key0 , account_infos [ 0 ] ) , ( key1 , account_infos [ 1 ] ) ] ;
2021-06-25 12:31:55 -07:00
index . insert_new_if_missing_into_primary_index ( slot0 , items . len ( ) , items . into_iter ( ) ) ;
2021-05-20 08:29:13 -07:00
for ( i , key ) in [ key0 , key1 ] . iter ( ) . enumerate ( ) {
let entry = index . get_account_read_entry ( key ) . unwrap ( ) ;
2021-08-09 06:59:56 -07:00
assert_eq! ( entry . ref_count ( ) , 1 ) ;
2021-05-20 08:29:13 -07:00
assert_eq! ( entry . slot_list ( ) . to_vec ( ) , vec! [ ( slot0 , account_infos [ i ] ) , ] ) ;
}
}
2021-09-14 15:51:07 -07:00
fn test_new_entry_code_paths_helper < T : IndexValue > (
2021-05-19 14:21:24 -07:00
account_infos : [ T ; 2 ] ,
is_cached : bool ,
upsert : bool ,
) {
let slot0 = 0 ;
let slot1 = 1 ;
let key = Keypair ::new ( ) . pubkey ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< T > ::default_for_tests ( ) ;
2021-05-19 14:21:24 -07:00
let mut gc = Vec ::new ( ) ;
if upsert {
// insert first entry for pubkey. This will use new_entry_after_update and not call update.
index . upsert (
2022-02-25 10:58:08 -08:00
slot0 ,
2021-05-19 14:21:24 -07:00
slot0 ,
& key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-19 14:21:24 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2021-09-01 06:13:08 -07:00
account_infos [ 0 ] ,
2021-05-19 14:21:24 -07:00
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-05-19 14:21:24 -07:00
) ;
} else {
2021-09-01 06:13:08 -07:00
let items = vec! [ ( key , account_infos [ 0 ] ) ] ;
2021-06-25 12:31:55 -07:00
index . insert_new_if_missing_into_primary_index ( slot0 , items . len ( ) , items . into_iter ( ) ) ;
2021-05-19 14:21:24 -07:00
}
assert! ( gc . is_empty ( ) ) ;
// verify the added entry matches expected
{
let entry = index . get_account_read_entry ( & key ) . unwrap ( ) ;
2021-08-09 06:59:56 -07:00
assert_eq! ( entry . ref_count ( ) , if is_cached { 0 } else { 1 } ) ;
2021-09-01 06:13:08 -07:00
let expected = vec! [ ( slot0 , account_infos [ 0 ] ) ] ;
2021-05-19 14:21:24 -07:00
assert_eq! ( entry . slot_list ( ) . to_vec ( ) , expected ) ;
2021-11-22 13:52:45 -08:00
let new_entry : AccountMapEntry < _ > = PreAllocatedAccountMapEntry ::new (
slot0 ,
account_infos [ 0 ] ,
& index . storage . storage ,
false ,
)
. into_account_map_entry ( & index . storage . storage ) ;
2021-05-19 14:21:24 -07:00
assert_eq! (
entry . slot_list ( ) . to_vec ( ) ,
new_entry . slot_list . read ( ) . unwrap ( ) . to_vec ( ) ,
) ;
}
// insert second entry for pubkey. This will use update and NOT use new_entry_after_update.
if upsert {
index . upsert (
2022-02-25 10:58:08 -08:00
slot1 ,
2021-05-19 14:21:24 -07:00
slot1 ,
& key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-19 14:21:24 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2021-09-01 06:13:08 -07:00
account_infos [ 1 ] ,
2021-05-19 14:21:24 -07:00
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-05-19 14:21:24 -07:00
) ;
} else {
2021-09-01 06:13:08 -07:00
let items = vec! [ ( key , account_infos [ 1 ] ) ] ;
2021-06-25 12:31:55 -07:00
index . insert_new_if_missing_into_primary_index ( slot1 , items . len ( ) , items . into_iter ( ) ) ;
2021-05-19 14:21:24 -07:00
}
assert! ( gc . is_empty ( ) ) ;
2021-05-21 11:59:32 -07:00
for lock in & [ false , true ] {
let read_lock = if * lock {
2021-06-28 13:03:57 -07:00
Some ( index . get_account_maps_read_lock ( & key ) )
2021-05-21 11:59:32 -07:00
} else {
None
} ;
let entry = if * lock {
index
. get_account_read_entry_with_lock ( & key , read_lock . as_ref ( ) . unwrap ( ) )
. unwrap ( )
} else {
index . get_account_read_entry ( & key ) . unwrap ( )
} ;
2021-08-09 06:59:56 -07:00
assert_eq! ( entry . ref_count ( ) , if is_cached { 0 } else { 2 } ) ;
2021-05-19 14:21:24 -07:00
assert_eq! (
entry . slot_list ( ) . to_vec ( ) ,
2021-09-01 06:13:08 -07:00
vec! [ ( slot0 , account_infos [ 0 ] ) , ( slot1 , account_infos [ 1 ] ) ]
2021-05-19 14:21:24 -07:00
) ;
2021-11-22 13:52:45 -08:00
let new_entry = PreAllocatedAccountMapEntry ::new (
slot1 ,
account_infos [ 1 ] ,
& index . storage . storage ,
false ,
) ;
2021-09-23 06:11:32 -07:00
assert_eq! ( entry . slot_list ( ) [ 1 ] , new_entry . into ( ) ) ;
2021-05-19 14:21:24 -07:00
}
}
#[ test ]
fn test_new_entry_and_update_code_paths ( ) {
for is_upsert in & [ false , true ] {
// account_info type that IS cached
test_new_entry_code_paths_helper ( [ 1.0 , 2.0 ] , true , * is_upsert ) ;
// account_info type that is NOT cached
test_new_entry_code_paths_helper ( [ true , false ] , false , * is_upsert ) ;
}
}
2021-05-17 09:58:33 -07:00
#[ test ]
fn test_insert_with_lock_no_ancestors ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-05-17 09:58:33 -07:00
let slot = 0 ;
2021-05-19 14:21:24 -07:00
let account_info = true ;
2021-05-17 09:58:33 -07:00
2021-09-23 06:11:32 -07:00
let new_entry =
2021-11-22 13:52:45 -08:00
PreAllocatedAccountMapEntry ::new ( slot , account_info , & index . storage . storage , false ) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 0 , account_maps_stats_len ( & index ) ) ;
2021-09-23 06:11:32 -07:00
assert_eq! ( ( slot , account_info ) , new_entry . clone ( ) . into ( ) ) ;
2021-08-05 06:45:08 -07:00
2021-11-30 09:35:21 -08:00
assert_eq! ( 0 , account_maps_stats_len ( & index ) ) ;
2021-09-15 10:36:08 -07:00
let w_account_maps = index . get_account_maps_write_lock ( & key . pubkey ( ) ) ;
2021-09-12 19:54:09 -07:00
w_account_maps . upsert (
2021-08-05 06:45:08 -07:00
& key . pubkey ( ) ,
2021-05-17 09:58:33 -07:00
new_entry ,
2022-02-25 10:58:08 -08:00
None ,
2021-08-05 06:45:08 -07:00
& mut SlotList ::default ( ) ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-05-17 09:58:33 -07:00
) ;
2021-09-12 19:54:09 -07:00
drop ( w_account_maps ) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 1 , account_maps_stats_len ( & index ) ) ;
2021-05-17 09:58:33 -07:00
let mut ancestors = Ancestors ::default ( ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. is_none ( ) ) ;
assert! ( index . get_for_tests ( & key . pubkey ( ) , None , None ) . is_none ( ) ) ;
2021-05-17 09:58:33 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 0 ) ;
ancestors . insert ( slot , 0 ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. is_some ( ) ) ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2021-05-17 09:58:33 -07:00
assert_eq! ( num , 1 ) ;
}
2019-04-15 17:15:50 -07:00
#[ test ]
fn test_insert_wrong_ancestors ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
let ancestors = vec! [ ( 1 , 1 ) ] . into_iter ( ) . collect ( ) ;
2021-12-15 07:09:56 -08:00
assert! ( index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. is_none ( ) ) ;
2019-07-10 22:06:32 -07:00
let mut num = 0 ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| _pubkey , _index | num + = 1 ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2019-07-10 22:06:32 -07:00
assert_eq! ( num , 0 ) ;
2019-04-15 17:15:50 -07:00
}
#[ test ]
fn test_insert_with_ancestors ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
let ancestors = vec! [ ( 0 , 0 ) ] . into_iter ( ) . collect ( ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 0 , true ) ) ;
2019-07-10 22:06:32 -07:00
let mut num = 0 ;
let mut found_key = false ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| pubkey , _index | {
if pubkey = = & key . pubkey ( ) {
found_key = true
} ;
num + = 1
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2019-07-10 22:06:32 -07:00
assert_eq! ( num , 1 ) ;
assert! ( found_key ) ;
2019-04-15 17:15:50 -07:00
}
2020-10-21 17:05:27 -07:00
fn setup_accounts_index_keys ( num_pubkeys : usize ) -> ( AccountsIndex < bool > , Vec < Pubkey > ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-10-21 17:05:27 -07:00
let root_slot = 0 ;
let mut pubkeys : Vec < Pubkey > = std ::iter ::repeat_with ( | | {
2020-10-19 12:23:14 -07:00
let new_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
root_slot ,
2020-12-31 18:06:03 -08:00
root_slot ,
& new_pubkey ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2020-10-21 17:05:27 -07:00
new_pubkey
} )
. take ( num_pubkeys . saturating_sub ( 1 ) )
. collect ( ) ;
if num_pubkeys ! = 0 {
pubkeys . push ( Pubkey ::default ( ) ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
root_slot ,
2020-12-31 18:06:03 -08:00
root_slot ,
& Pubkey ::default ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2020-10-21 17:05:27 -07:00
}
2021-01-11 17:00:23 -08:00
index . add_root ( root_slot , false ) ;
2020-10-21 17:05:27 -07:00
( index , pubkeys )
}
fn run_test_range (
index : & AccountsIndex < bool > ,
pubkeys : & [ Pubkey ] ,
start_bound : Bound < usize > ,
end_bound : Bound < usize > ,
) {
// Exclusive `index_start`
let ( pubkey_start , index_start ) = match start_bound {
Unbounded = > ( Unbounded , 0 ) ,
Included ( i ) = > ( Included ( pubkeys [ i ] ) , i ) ,
Excluded ( i ) = > ( Excluded ( pubkeys [ i ] ) , i + 1 ) ,
} ;
// Exclusive `index_end`
let ( pubkey_end , index_end ) = match end_bound {
Unbounded = > ( Unbounded , pubkeys . len ( ) ) ,
Included ( i ) = > ( Included ( pubkeys [ i ] ) , i + 1 ) ,
Excluded ( i ) = > ( Excluded ( pubkeys [ i ] ) , i ) ,
} ;
let pubkey_range = ( pubkey_start , pubkey_end ) ;
2021-04-12 08:51:57 -07:00
let ancestors = Ancestors ::default ( ) ;
2020-10-21 17:05:27 -07:00
let mut scanned_keys = HashSet ::new ( ) ;
2021-08-26 16:12:43 -07:00
index . range_scan_accounts (
" " ,
& ancestors ,
pubkey_range ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
| pubkey , _index | {
scanned_keys . insert ( * pubkey ) ;
} ,
) ;
2020-10-21 17:05:27 -07:00
let mut expected_len = 0 ;
for key in & pubkeys [ index_start .. index_end ] {
expected_len + = 1 ;
assert! ( scanned_keys . contains ( key ) ) ;
}
assert_eq! ( scanned_keys . len ( ) , expected_len ) ;
}
fn run_test_range_indexes (
index : & AccountsIndex < bool > ,
pubkeys : & [ Pubkey ] ,
start : Option < usize > ,
end : Option < usize > ,
) {
let start_options = start
. map ( | i | vec! [ Included ( i ) , Excluded ( i ) ] )
. unwrap_or_else ( | | vec! [ Unbounded ] ) ;
let end_options = end
. map ( | i | vec! [ Included ( i ) , Excluded ( i ) ] )
. unwrap_or_else ( | | vec! [ Unbounded ] ) ;
for start in & start_options {
for end in & end_options {
run_test_range ( index , pubkeys , * start , * end ) ;
}
}
}
#[ test ]
fn test_range_scan_accounts ( ) {
let ( index , mut pubkeys ) = setup_accounts_index_keys ( 3 * ITER_BATCH_SIZE ) ;
pubkeys . sort ( ) ;
run_test_range_indexes ( & index , & pubkeys , None , None ) ;
run_test_range_indexes ( & index , & pubkeys , Some ( ITER_BATCH_SIZE ) , None ) ;
run_test_range_indexes ( & index , & pubkeys , None , Some ( 2 * ITER_BATCH_SIZE as usize ) ) ;
run_test_range_indexes (
& index ,
& pubkeys ,
Some ( ITER_BATCH_SIZE as usize ) ,
Some ( 2 * ITER_BATCH_SIZE as usize ) ,
) ;
run_test_range_indexes (
& index ,
& pubkeys ,
Some ( ITER_BATCH_SIZE as usize ) ,
Some ( 2 * ITER_BATCH_SIZE as usize - 1 ) ,
) ;
run_test_range_indexes (
& index ,
& pubkeys ,
2020-12-13 17:26:34 -08:00
Some ( ITER_BATCH_SIZE - 1_ usize ) ,
2020-10-21 17:05:27 -07:00
Some ( 2 * ITER_BATCH_SIZE as usize + 1 ) ,
) ;
}
fn run_test_scan_accounts ( num_pubkeys : usize ) {
let ( index , _ ) = setup_accounts_index_keys ( num_pubkeys ) ;
2021-04-12 08:51:57 -07:00
let ancestors = Ancestors ::default ( ) ;
2020-10-21 17:05:27 -07:00
let mut scanned_keys = HashSet ::new ( ) ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& ancestors ,
| pubkey , _index | {
scanned_keys . insert ( * pubkey ) ;
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( scanned_keys . len ( ) , num_pubkeys ) ;
}
#[ test ]
fn test_scan_accounts ( ) {
run_test_scan_accounts ( 0 ) ;
run_test_scan_accounts ( 1 ) ;
run_test_scan_accounts ( ITER_BATCH_SIZE * 10 ) ;
run_test_scan_accounts ( ITER_BATCH_SIZE * 10 - 1 ) ;
run_test_scan_accounts ( ITER_BATCH_SIZE * 10 + 1 ) ;
}
#[ test ]
fn test_accounts_iter_finished ( ) {
let ( index , _ ) = setup_accounts_index_keys ( 0 ) ;
2021-09-03 16:00:49 -07:00
let mut iter = index . iter ( None ::< & Range < Pubkey > > , COLLECT_ALL_UNSORTED_FALSE ) ;
2020-10-21 17:05:27 -07:00
assert! ( iter . next ( ) . is_none ( ) ) ;
let mut gc = vec! [ ] ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& solana_sdk ::pubkey ::new_rand ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2020-10-21 17:05:27 -07:00
assert! ( iter . next ( ) . is_none ( ) ) ;
}
2019-04-15 17:15:50 -07:00
#[ test ]
2022-04-02 10:00:52 -07:00
fn test_is_alive_root ( ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2022-04-02 10:00:52 -07:00
assert! ( ! index . is_alive_root ( 0 ) ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
2022-04-02 10:00:52 -07:00
assert! ( index . is_alive_root ( 0 ) ) ;
2019-04-15 17:15:50 -07:00
}
#[ test ]
fn test_insert_with_root ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index . get_for_tests ( & key . pubkey ( ) , None , None ) . unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 0 , true ) ) ;
2019-04-15 17:15:50 -07:00
}
2019-04-28 10:27:37 -07:00
#[ test ]
2020-03-02 21:57:25 -08:00
fn test_clean_first ( ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
index . add_root ( 1 , false ) ;
2021-10-06 18:04:26 -07:00
index . clean_dead_slot ( 0 , & mut AccountsIndexRootsStats ::default ( ) ) ;
2022-04-02 10:00:52 -07:00
assert! ( index . is_alive_root ( 1 ) ) ;
assert! ( ! index . is_alive_root ( 0 ) ) ;
2019-04-15 17:15:50 -07:00
}
#[ test ]
2020-03-02 21:57:25 -08:00
fn test_clean_last ( ) {
2019-10-23 22:01:22 -07:00
//this behavior might be undefined, clean up should only occur on older slots
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
index . add_root ( 1 , false ) ;
2021-10-06 18:04:26 -07:00
index . clean_dead_slot ( 1 , & mut AccountsIndexRootsStats ::default ( ) ) ;
2022-04-02 10:00:52 -07:00
assert! ( ! index . is_alive_root ( 1 ) ) ;
assert! ( index . is_alive_root ( 0 ) ) ;
2019-04-15 17:15:50 -07:00
}
2020-03-02 21:57:25 -08:00
#[ test ]
fn test_clean_and_unclean_slot ( ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 0 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
index . add_root ( 1 , false ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 2 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
2020-06-11 22:51:43 -07:00
2020-10-21 17:05:27 -07:00
assert_eq! (
0 ,
index
. roots_tracker
. read ( )
. unwrap ( )
. previous_uncleaned_roots
. len ( )
) ;
2020-09-28 16:04:46 -07:00
index . reset_uncleaned_roots ( None ) ;
2022-04-02 10:00:52 -07:00
assert_eq! ( 2 , index . roots_tracker . read ( ) . unwrap ( ) . alive_roots . len ( ) ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 0 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
assert_eq! (
2 ,
index
. roots_tracker
. read ( )
. unwrap ( )
. previous_uncleaned_roots
. len ( )
) ;
2020-06-11 22:51:43 -07:00
2021-01-11 17:00:23 -08:00
index . add_root ( 2 , false ) ;
index . add_root ( 3 , false ) ;
2022-04-02 10:00:52 -07:00
assert_eq! ( 4 , index . roots_tracker . read ( ) . unwrap ( ) . alive_roots . len ( ) ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 2 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
assert_eq! (
2 ,
index
. roots_tracker
. read ( )
. unwrap ( )
. previous_uncleaned_roots
. len ( )
) ;
2020-06-11 22:51:43 -07:00
2021-10-06 18:04:26 -07:00
index . clean_dead_slot ( 1 , & mut AccountsIndexRootsStats ::default ( ) ) ;
2022-04-02 10:00:52 -07:00
assert_eq! ( 3 , index . roots_tracker . read ( ) . unwrap ( ) . alive_roots . len ( ) ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 2 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
assert_eq! (
1 ,
index
. roots_tracker
. read ( )
. unwrap ( )
. previous_uncleaned_roots
. len ( )
) ;
2020-06-11 22:51:43 -07:00
2021-10-06 18:04:26 -07:00
index . clean_dead_slot ( 2 , & mut AccountsIndexRootsStats ::default ( ) ) ;
2022-04-02 10:00:52 -07:00
assert_eq! ( 2 , index . roots_tracker . read ( ) . unwrap ( ) . alive_roots . len ( ) ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( 1 , index . roots_tracker . read ( ) . unwrap ( ) . uncleaned_roots . len ( ) ) ;
assert_eq! (
1 ,
index
. roots_tracker
. read ( )
. unwrap ( )
. previous_uncleaned_roots
. len ( )
) ;
2020-03-02 21:57:25 -08:00
}
2019-04-15 17:15:50 -07:00
#[ test ]
fn test_update_last_wins ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-04-15 17:15:50 -07:00
let ancestors = vec! [ ( 0 , 0 ) ] . into_iter ( ) . collect ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 0 , true ) ) ;
2019-07-20 17:58:39 -07:00
drop ( list ) ;
2019-04-15 17:15:50 -07:00
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
false ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert_eq! ( gc , vec! [ ( 0 , true ) ] ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 0 , false ) ) ;
2019-04-15 17:15:50 -07:00
}
#[ test ]
2019-10-23 22:01:22 -07:00
fn test_update_new_slot ( ) {
2019-07-20 17:58:39 -07:00
solana_logger ::setup ( ) ;
2019-04-15 17:15:50 -07:00
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-04-15 17:15:50 -07:00
let ancestors = vec! [ ( 0 , 0 ) ] . into_iter ( ) . collect ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
1 ,
2020-12-31 18:06:03 -08:00
1 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
false ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 0 , true ) ) ;
2019-04-15 17:15:50 -07:00
let ancestors = vec! [ ( 1 , 0 ) ] . into_iter ( ) . collect ( ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index
. get_for_tests ( & key . pubkey ( ) , Some ( & ancestors ) , None )
. unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 1 , false ) ) ;
2019-04-15 17:15:50 -07:00
}
#[ test ]
2019-10-23 22:01:22 -07:00
fn test_update_gc_purged_slot ( ) {
2019-04-15 17:15:50 -07:00
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2019-06-10 18:15:39 -07:00
let mut gc = Vec ::new ( ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2019-04-15 17:15:50 -07:00
assert! ( gc . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
1 ,
2020-12-31 18:06:03 -08:00
1 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
false ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
index . upsert (
2022-02-25 10:58:08 -08:00
2 ,
2020-12-31 18:06:03 -08:00
2 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
index . upsert (
2022-02-25 10:58:08 -08:00
3 ,
2020-12-31 18:06:03 -08:00
3 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 0 , false ) ;
index . add_root ( 1 , false ) ;
index . add_root ( 3 , false ) ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
4 ,
2020-12-31 18:06:03 -08:00
4 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
true ,
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2020-09-28 16:04:46 -07:00
// Updating index should not purge older roots, only purges
// previous updates within the same slot
assert_eq! ( gc , vec! [ ] ) ;
2021-12-15 07:09:56 -08:00
let ( list , idx ) = index . get_for_tests ( & key . pubkey ( ) , None , None ) . unwrap ( ) ;
2020-10-21 17:05:27 -07:00
assert_eq! ( list . slot_list ( ) [ idx ] , ( 3 , true ) ) ;
2019-07-10 22:06:32 -07:00
let mut num = 0 ;
let mut found_key = false ;
2021-08-26 16:12:43 -07:00
index . unchecked_scan_accounts (
" " ,
& Ancestors ::default ( ) ,
| pubkey , _index | {
if pubkey = = & key . pubkey ( ) {
found_key = true ;
assert_eq! ( _index , ( & true , 3 ) ) ;
} ;
num + = 1
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
2021-08-26 16:12:43 -07:00
) ;
2019-07-10 22:06:32 -07:00
assert_eq! ( num , 1 ) ;
assert! ( found_key ) ;
2019-04-15 17:15:50 -07:00
}
2019-12-11 11:11:31 -08:00
2021-11-30 09:35:21 -08:00
fn account_maps_stats_len < T : IndexValue > ( index : & AccountsIndex < T > ) -> usize {
index . storage . storage . stats . total_count ( )
2021-07-27 06:46:27 -07:00
}
2019-12-11 11:11:31 -08:00
#[ test ]
fn test_purge ( ) {
let key = Keypair ::new ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< u64 > ::default_for_tests ( ) ;
2019-12-11 11:11:31 -08:00
let mut gc = Vec ::new ( ) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 0 , account_maps_stats_len ( & index ) ) ;
2021-07-27 06:46:27 -07:00
index . upsert (
2022-02-25 10:58:08 -08:00
1 ,
2020-12-31 18:06:03 -08:00
1 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
12 ,
2021-07-27 06:46:27 -07:00
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-07-27 06:46:27 -07:00
) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 1 , account_maps_stats_len ( & index ) ) ;
2020-12-31 18:06:03 -08:00
2021-07-27 06:46:27 -07:00
index . upsert (
2022-02-25 10:58:08 -08:00
1 ,
2020-12-31 18:06:03 -08:00
1 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
10 ,
2021-07-27 06:46:27 -07:00
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-07-27 06:46:27 -07:00
) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 1 , account_maps_stats_len ( & index ) ) ;
2020-12-31 18:06:03 -08:00
let purges = index . purge_roots ( & key . pubkey ( ) ) ;
2019-12-11 11:11:31 -08:00
assert_eq! ( purges , ( vec! [ ] , false ) ) ;
2021-01-11 17:00:23 -08:00
index . add_root ( 1 , false ) ;
2019-12-11 11:11:31 -08:00
2020-12-31 18:06:03 -08:00
let purges = index . purge_roots ( & key . pubkey ( ) ) ;
2019-12-11 11:11:31 -08:00
assert_eq! ( purges , ( vec! [ ( 1 , 10 ) ] , true ) ) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 1 , account_maps_stats_len ( & index ) ) ;
2021-07-27 06:46:27 -07:00
index . upsert (
2022-02-25 10:58:08 -08:00
1 ,
2020-12-31 18:06:03 -08:00
1 ,
& key . pubkey ( ) ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::default ( ) ,
2021-05-10 07:22:48 -07:00
& AccountSecondaryIndexes ::default ( ) ,
2020-12-31 18:06:03 -08:00
9 ,
2021-07-27 06:46:27 -07:00
& mut gc ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2021-07-27 06:46:27 -07:00
) ;
2021-11-30 09:35:21 -08:00
assert_eq! ( 1 , account_maps_stats_len ( & index ) ) ;
2019-12-11 11:11:31 -08:00
}
2020-09-28 16:04:46 -07:00
#[ test ]
fn test_latest_slot ( ) {
let slot_slice = vec! [ ( 0 , true ) , ( 5 , true ) , ( 3 , true ) , ( 7 , true ) ] ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-09-28 16:04:46 -07:00
// No ancestors, no root, should return None
assert! ( index . latest_slot ( None , & slot_slice , None ) . is_none ( ) ) ;
// Given a root, should return the root
2021-01-11 17:00:23 -08:00
index . add_root ( 5 , false ) ;
2020-09-28 16:04:46 -07:00
assert_eq! ( index . latest_slot ( None , & slot_slice , None ) . unwrap ( ) , 1 ) ;
2020-11-16 17:23:11 -08:00
// Given a max_root == root, should still return the root
2020-09-28 16:04:46 -07:00
assert_eq! ( index . latest_slot ( None , & slot_slice , Some ( 5 ) ) . unwrap ( ) , 1 ) ;
2020-11-16 17:23:11 -08:00
// Given a max_root < root, should filter out the root
2020-09-28 16:04:46 -07:00
assert! ( index . latest_slot ( None , & slot_slice , Some ( 4 ) ) . is_none ( ) ) ;
2020-11-16 17:23:11 -08:00
// Given a max_root, should filter out roots < max_root, but specified
// ancestors should not be affected
2021-04-12 08:51:57 -07:00
let ancestors = vec! [ ( 3 , 1 ) , ( 7 , 1 ) ] . into_iter ( ) . collect ( ) ;
2020-09-28 16:04:46 -07:00
assert_eq! (
index
. latest_slot ( Some ( & ancestors ) , & slot_slice , Some ( 4 ) )
. unwrap ( ) ,
2020-11-16 17:23:11 -08:00
3
2020-09-28 16:04:46 -07:00
) ;
assert_eq! (
index
. latest_slot ( Some ( & ancestors ) , & slot_slice , Some ( 7 ) )
. unwrap ( ) ,
3
) ;
2020-11-16 17:23:11 -08:00
// Given no max_root, should just return the greatest ancestor or root
2020-09-28 16:04:46 -07:00
assert_eq! (
index
. latest_slot ( Some ( & ancestors ) , & slot_slice , None )
. unwrap ( ) ,
3
) ;
}
2020-10-03 15:18:58 -07:00
2020-12-31 18:06:03 -08:00
fn run_test_purge_exact_secondary_index <
SecondaryIndexEntryType : SecondaryIndexEntry + Default + Sync + Send ,
> (
index : & AccountsIndex < bool > ,
secondary_index : & SecondaryIndex < SecondaryIndexEntryType > ,
key_start : usize ,
key_end : usize ,
2021-05-12 15:29:30 -07:00
secondary_indexes : & AccountSecondaryIndexes ,
2020-12-31 18:06:03 -08:00
) {
// No roots, should be no reclaims
let slots = vec! [ 1 , 2 , 5 , 9 ] ;
let index_key = Pubkey ::new_unique ( ) ;
let account_key = Pubkey ::new_unique ( ) ;
2022-02-16 16:23:25 -08:00
let mut account_data = vec! [ 0 ; inline_spl_token ::Account ::get_packed_len ( ) ] ;
2021-04-18 10:27:36 -07:00
account_data [ key_start .. key_end ] . clone_from_slice ( & ( index_key . to_bytes ( ) ) ) ;
2020-12-31 18:06:03 -08:00
// Insert slots into secondary index
for slot in & slots {
index . upsert (
2022-02-25 10:58:08 -08:00
* slot ,
2020-12-31 18:06:03 -08:00
* slot ,
& account_key ,
// Make sure these accounts are added to secondary index
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create (
0 ,
account_data . to_vec ( ) ,
inline_spl_token ::id ( ) ,
false ,
0 ,
) ,
2021-05-12 15:29:30 -07:00
secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
}
// Only one top level index entry exists
assert_eq! ( secondary_index . index . get ( & index_key ) . unwrap ( ) . len ( ) , 1 ) ;
// In the reverse index, one account maps across multiple slots
// to the same top level key
assert_eq! (
secondary_index
. reverse_index
. get ( & account_key )
. unwrap ( )
. value ( )
. read ( )
. unwrap ( )
. len ( ) ,
2021-05-12 15:29:30 -07:00
1
2020-12-31 18:06:03 -08:00
) ;
2021-01-11 17:00:23 -08:00
index . purge_exact (
& account_key ,
2021-01-17 20:31:03 -08:00
& slots . into_iter ( ) . collect ::< HashSet < Slot > > ( ) ,
2021-01-11 17:00:23 -08:00
& mut vec! [ ] ,
) ;
2020-12-31 18:06:03 -08:00
2021-05-12 15:29:30 -07:00
index . handle_dead_keys ( & [ & account_key ] , secondary_indexes ) ;
2020-12-31 18:06:03 -08:00
assert! ( secondary_index . index . is_empty ( ) ) ;
assert! ( secondary_index . reverse_index . is_empty ( ) ) ;
}
#[ test ]
fn test_purge_exact_dashmap_secondary_index ( ) {
2021-05-12 15:29:30 -07:00
let ( key_start , key_end , secondary_indexes ) = create_dashmap_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-12-31 18:06:03 -08:00
run_test_purge_exact_secondary_index (
& index ,
& index . spl_token_mint_index ,
key_start ,
key_end ,
2021-05-12 15:29:30 -07:00
& secondary_indexes ,
2020-12-31 18:06:03 -08:00
) ;
}
#[ test ]
fn test_purge_exact_rwlock_secondary_index ( ) {
2021-05-12 15:29:30 -07:00
let ( key_start , key_end , secondary_indexes ) = create_rwlock_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-12-31 18:06:03 -08:00
run_test_purge_exact_secondary_index (
& index ,
& index . spl_token_owner_index ,
key_start ,
key_end ,
2021-05-12 15:29:30 -07:00
& secondary_indexes ,
2020-12-31 18:06:03 -08:00
) ;
}
2020-10-03 15:18:58 -07:00
#[ test ]
fn test_purge_older_root_entries ( ) {
// No roots, should be no reclaims
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2020-10-03 15:18:58 -07:00
let mut slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
let mut reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , None ) ;
2020-10-03 15:18:58 -07:00
assert! ( reclaims . is_empty ( ) ) ;
assert_eq! ( slot_list , vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ) ;
// Add a later root, earlier slots should be reclaimed
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
2021-01-11 17:00:23 -08:00
index . add_root ( 1 , false ) ;
2020-10-03 15:18:58 -07:00
// Note 2 is not a root
2021-01-11 17:00:23 -08:00
index . add_root ( 5 , false ) ;
2020-10-03 15:18:58 -07:00
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , None ) ;
2020-10-03 15:18:58 -07:00
assert_eq! ( reclaims , vec! [ ( 1 , true ) , ( 2 , true ) ] ) ;
assert_eq! ( slot_list , vec! [ ( 5 , true ) , ( 9 , true ) ] ) ;
// Add a later root that is not in the list, should not affect the outcome
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
2021-01-11 17:00:23 -08:00
index . add_root ( 6 , false ) ;
2020-10-03 15:18:58 -07:00
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , None ) ;
2020-10-03 15:18:58 -07:00
assert_eq! ( reclaims , vec! [ ( 1 , true ) , ( 2 , true ) ] ) ;
assert_eq! ( slot_list , vec! [ ( 5 , true ) , ( 9 , true ) ] ) ;
// Pass a max root >= than any root in the slot list, should not affect
// outcome
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , Some ( 6 ) ) ;
2020-10-03 15:18:58 -07:00
assert_eq! ( reclaims , vec! [ ( 1 , true ) , ( 2 , true ) ] ) ;
assert_eq! ( slot_list , vec! [ ( 5 , true ) , ( 9 , true ) ] ) ;
// Pass a max root, earlier slots should be reclaimed
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , Some ( 5 ) ) ;
2020-10-03 15:18:58 -07:00
assert_eq! ( reclaims , vec! [ ( 1 , true ) , ( 2 , true ) ] ) ;
assert_eq! ( slot_list , vec! [ ( 5 , true ) , ( 9 , true ) ] ) ;
// Pass a max root 2. This means the latest root < 2 is 1 because 2 is not a root
// so nothing will be purged
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , Some ( 2 ) ) ;
2020-10-03 15:18:58 -07:00
assert! ( reclaims . is_empty ( ) ) ;
assert_eq! ( slot_list , vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ) ;
// Pass a max root 1. This means the latest root < 3 is 1 because 2 is not a root
// so nothing will be purged
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , Some ( 1 ) ) ;
2020-10-03 15:18:58 -07:00
assert! ( reclaims . is_empty ( ) ) ;
assert_eq! ( slot_list , vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ) ;
// Pass a max root that doesn't exist in the list but is greater than
// some of the roots in the list, shouldn't return those smaller roots
slot_list = vec! [ ( 1 , true ) , ( 2 , true ) , ( 5 , true ) , ( 9 , true ) ] ;
reclaims = vec! [ ] ;
2021-05-12 15:29:30 -07:00
index . purge_older_root_entries ( & mut slot_list , & mut reclaims , Some ( 7 ) ) ;
2020-10-03 15:18:58 -07:00
assert_eq! ( reclaims , vec! [ ( 1 , true ) , ( 2 , true ) ] ) ;
assert_eq! ( slot_list , vec! [ ( 5 , true ) , ( 9 , true ) ] ) ;
}
2020-12-31 18:06:03 -08:00
2021-05-12 15:29:30 -07:00
fn check_secondary_index_mapping_correct < SecondaryIndexEntryType > (
2020-12-31 18:06:03 -08:00
secondary_index : & SecondaryIndex < SecondaryIndexEntryType > ,
2021-05-12 15:29:30 -07:00
secondary_index_keys : & [ Pubkey ] ,
2020-12-31 18:06:03 -08:00
account_key : & Pubkey ,
) where
SecondaryIndexEntryType : SecondaryIndexEntry + Default + Sync + Send ,
{
// Check secondary index has unique mapping from secondary index key
// to the account key and slot
2021-05-12 15:29:30 -07:00
for secondary_index_key in secondary_index_keys {
assert_eq! ( secondary_index . index . len ( ) , secondary_index_keys . len ( ) ) ;
let account_key_map = secondary_index . get ( secondary_index_key ) ;
assert_eq! ( account_key_map . len ( ) , 1 ) ;
assert_eq! ( account_key_map , vec! [ * account_key ] ) ;
}
// Check reverse index contains all of the `secondary_index_keys`
let secondary_index_key_map = secondary_index . reverse_index . get ( account_key ) . unwrap ( ) ;
assert_eq! (
& * secondary_index_key_map . value ( ) . read ( ) . unwrap ( ) ,
secondary_index_keys
) ;
2020-12-31 18:06:03 -08:00
}
2022-02-16 16:23:25 -08:00
fn run_test_spl_token_secondary_indexes <
2020-12-31 18:06:03 -08:00
SecondaryIndexEntryType : SecondaryIndexEntry + Default + Sync + Send ,
> (
2022-02-16 16:23:25 -08:00
token_id : & Pubkey ,
2020-12-31 18:06:03 -08:00
index : & AccountsIndex < bool > ,
secondary_index : & SecondaryIndex < SecondaryIndexEntryType > ,
key_start : usize ,
key_end : usize ,
2021-05-12 15:29:30 -07:00
secondary_indexes : & AccountSecondaryIndexes ,
2020-12-31 18:06:03 -08:00
) {
2021-05-12 15:29:30 -07:00
let mut secondary_indexes = secondary_indexes . clone ( ) ;
2020-12-31 18:06:03 -08:00
let account_key = Pubkey ::new_unique ( ) ;
let index_key = Pubkey ::new_unique ( ) ;
2022-02-16 16:23:25 -08:00
let mut account_data = vec! [ 0 ; inline_spl_token ::Account ::get_packed_len ( ) ] ;
2021-04-18 10:27:36 -07:00
account_data [ key_start .. key_end ] . clone_from_slice ( & ( index_key . to_bytes ( ) ) ) ;
2020-12-31 18:06:03 -08:00
// Wrong program id
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data . to_vec ( ) , Pubkey ::default ( ) , false , 0 ) ,
2021-05-12 15:29:30 -07:00
& secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2021-05-10 06:54:30 -07:00
assert! ( secondary_index . index . is_empty ( ) ) ;
assert! ( secondary_index . reverse_index . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
// Wrong account data size
index . upsert (
2022-02-25 10:58:08 -08:00
0 ,
2020-12-31 18:06:03 -08:00
0 ,
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data [ 1 .. ] . to_vec ( ) , * token_id , false , 0 ) ,
2021-05-12 15:29:30 -07:00
& secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2021-05-10 06:54:30 -07:00
assert! ( secondary_index . index . is_empty ( ) ) ;
assert! ( secondary_index . reverse_index . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
2021-05-12 15:29:30 -07:00
secondary_indexes . keys = None ;
2021-05-11 15:06:22 -07:00
2020-12-31 18:06:03 -08:00
// Just right. Inserting the same index multiple times should be ok
for _ in 0 .. 2 {
index . update_secondary_indexes (
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data . to_vec ( ) , * token_id , false , 0 ) ,
2021-05-12 15:29:30 -07:00
& secondary_indexes ,
2020-12-31 18:06:03 -08:00
) ;
2021-05-12 15:29:30 -07:00
check_secondary_index_mapping_correct ( secondary_index , & [ index_key ] , & account_key ) ;
2020-12-31 18:06:03 -08:00
}
2021-05-10 06:54:30 -07:00
// included
assert! ( ! secondary_index . index . is_empty ( ) ) ;
assert! ( ! secondary_index . reverse_index . is_empty ( ) ) ;
2021-05-12 15:29:30 -07:00
secondary_indexes . keys = Some ( AccountSecondaryIndexesIncludeExclude {
2021-05-11 15:06:22 -07:00
keys : [ index_key ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude : false ,
} ) ;
secondary_index . index . clear ( ) ;
secondary_index . reverse_index . clear ( ) ;
2022-02-23 15:01:23 -08:00
index . update_secondary_indexes (
& account_key ,
& AccountSharedData ::create ( 0 , account_data . to_vec ( ) , * token_id , false , 0 ) ,
& secondary_indexes ,
) ;
2021-05-11 15:06:22 -07:00
assert! ( ! secondary_index . index . is_empty ( ) ) ;
assert! ( ! secondary_index . reverse_index . is_empty ( ) ) ;
2021-05-12 15:29:30 -07:00
check_secondary_index_mapping_correct ( secondary_index , & [ index_key ] , & account_key ) ;
2021-05-11 15:06:22 -07:00
// not-excluded
2021-05-12 15:29:30 -07:00
secondary_indexes . keys = Some ( AccountSecondaryIndexesIncludeExclude {
2021-05-11 15:06:22 -07:00
keys : [ ] . iter ( ) . cloned ( ) . collect ::< HashSet < _ > > ( ) ,
exclude : true ,
} ) ;
secondary_index . index . clear ( ) ;
secondary_index . reverse_index . clear ( ) ;
2022-02-23 15:01:23 -08:00
index . update_secondary_indexes (
& account_key ,
& AccountSharedData ::create ( 0 , account_data . to_vec ( ) , * token_id , false , 0 ) ,
& secondary_indexes ,
) ;
2021-05-11 15:06:22 -07:00
assert! ( ! secondary_index . index . is_empty ( ) ) ;
assert! ( ! secondary_index . reverse_index . is_empty ( ) ) ;
2021-05-12 15:29:30 -07:00
check_secondary_index_mapping_correct ( secondary_index , & [ index_key ] , & account_key ) ;
2021-05-11 15:06:22 -07:00
2021-05-12 15:29:30 -07:00
secondary_indexes . keys = None ;
2021-05-11 15:06:22 -07:00
2021-09-27 14:24:19 -07:00
index . slot_list_mut ( & account_key , | slot_list | slot_list . clear ( ) ) ;
2020-12-31 18:06:03 -08:00
// Everything should be deleted
2021-05-12 15:29:30 -07:00
index . handle_dead_keys ( & [ & account_key ] , & secondary_indexes ) ;
2021-05-10 06:54:30 -07:00
assert! ( secondary_index . index . is_empty ( ) ) ;
assert! ( secondary_index . reverse_index . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
}
#[ test ]
fn test_dashmap_secondary_index ( ) {
2021-05-12 15:29:30 -07:00
let ( key_start , key_end , secondary_indexes ) = create_dashmap_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2022-02-16 16:23:25 -08:00
for token_id in [ inline_spl_token ::id ( ) , inline_spl_token_2022 ::id ( ) ] {
run_test_spl_token_secondary_indexes (
& token_id ,
& index ,
& index . spl_token_mint_index ,
key_start ,
key_end ,
& secondary_indexes ,
) ;
}
2020-12-31 18:06:03 -08:00
}
#[ test ]
fn test_rwlock_secondary_index ( ) {
2021-05-12 15:29:30 -07:00
let ( key_start , key_end , secondary_indexes ) = create_rwlock_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2022-02-16 16:23:25 -08:00
for token_id in [ inline_spl_token ::id ( ) , inline_spl_token_2022 ::id ( ) ] {
run_test_spl_token_secondary_indexes (
& token_id ,
& index ,
& index . spl_token_owner_index ,
key_start ,
key_end ,
& secondary_indexes ,
) ;
}
2020-12-31 18:06:03 -08:00
}
fn run_test_secondary_indexes_same_slot_and_forks <
SecondaryIndexEntryType : SecondaryIndexEntry + Default + Sync + Send ,
> (
2022-02-16 16:23:25 -08:00
token_id : & Pubkey ,
2020-12-31 18:06:03 -08:00
index : & AccountsIndex < bool > ,
secondary_index : & SecondaryIndex < SecondaryIndexEntryType > ,
index_key_start : usize ,
index_key_end : usize ,
2021-05-12 15:29:30 -07:00
secondary_indexes : & AccountSecondaryIndexes ,
2020-12-31 18:06:03 -08:00
) {
let account_key = Pubkey ::new_unique ( ) ;
let secondary_key1 = Pubkey ::new_unique ( ) ;
let secondary_key2 = Pubkey ::new_unique ( ) ;
let slot = 1 ;
2022-02-16 16:23:25 -08:00
let mut account_data1 = vec! [ 0 ; inline_spl_token ::Account ::get_packed_len ( ) ] ;
2020-12-31 18:06:03 -08:00
account_data1 [ index_key_start .. index_key_end ]
2021-04-18 10:27:36 -07:00
. clone_from_slice ( & ( secondary_key1 . to_bytes ( ) ) ) ;
2022-02-16 16:23:25 -08:00
let mut account_data2 = vec! [ 0 ; inline_spl_token ::Account ::get_packed_len ( ) ] ;
2020-12-31 18:06:03 -08:00
account_data2 [ index_key_start .. index_key_end ]
2021-04-18 10:27:36 -07:00
. clone_from_slice ( & ( secondary_key2 . to_bytes ( ) ) ) ;
2020-12-31 18:06:03 -08:00
// First write one mint index
index . upsert (
2022-02-25 10:58:08 -08:00
slot ,
2020-12-31 18:06:03 -08:00
slot ,
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data1 . to_vec ( ) , * token_id , false , 0 ) ,
2021-05-12 15:29:30 -07:00
secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2021-05-12 15:29:30 -07:00
// Now write a different mint index for the same account
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
slot ,
2020-12-31 18:06:03 -08:00
slot ,
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data2 . to_vec ( ) , * token_id , false , 0 ) ,
2021-05-12 15:29:30 -07:00
secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
2021-05-12 15:29:30 -07:00
// Both pubkeys will now be present in the index
check_secondary_index_mapping_correct (
2021-06-18 06:34:46 -07:00
secondary_index ,
2021-05-12 15:29:30 -07:00
& [ secondary_key1 , secondary_key2 ] ,
& account_key ,
) ;
2020-12-31 18:06:03 -08:00
2021-05-12 15:29:30 -07:00
// If a later slot also introduces secondary_key1, then it should still exist in the index
let later_slot = slot + 1 ;
2020-12-31 18:06:03 -08:00
index . upsert (
2022-02-25 10:58:08 -08:00
later_slot ,
2021-05-12 15:29:30 -07:00
later_slot ,
2020-12-31 18:06:03 -08:00
& account_key ,
2022-02-23 15:01:23 -08:00
& AccountSharedData ::create ( 0 , account_data1 . to_vec ( ) , * token_id , false , 0 ) ,
2021-05-12 15:29:30 -07:00
secondary_indexes ,
2020-12-31 18:06:03 -08:00
true ,
& mut vec! [ ] ,
2021-08-09 06:58:59 -07:00
UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE ,
2020-12-31 18:06:03 -08:00
) ;
assert_eq! ( secondary_index . get ( & secondary_key1 ) , vec! [ account_key ] ) ;
2021-05-12 15:29:30 -07:00
// If we set a root at `later_slot`, and clean, then even though the account with secondary_key1
// was outdated by the update in the later slot, the primary account key is still alive,
// so both secondary keys will still be kept alive.
index . add_root ( later_slot , false ) ;
2021-09-27 14:24:19 -07:00
index . slot_list_mut ( & account_key , | slot_list | {
index . purge_older_root_entries ( slot_list , & mut vec! [ ] , None )
} ) ;
2020-12-31 18:06:03 -08:00
2021-05-12 15:29:30 -07:00
check_secondary_index_mapping_correct (
secondary_index ,
& [ secondary_key1 , secondary_key2 ] ,
& account_key ,
) ;
// Removing the remaining entry for this pubkey in the index should mark the
// pubkey as dead and finally remove all the secondary indexes
let mut reclaims = vec! [ ] ;
index . purge_exact ( & account_key , & later_slot , & mut reclaims ) ;
index . handle_dead_keys ( & [ & account_key ] , secondary_indexes ) ;
assert! ( secondary_index . index . is_empty ( ) ) ;
assert! ( secondary_index . reverse_index . is_empty ( ) ) ;
2020-12-31 18:06:03 -08:00
}
#[ test ]
fn test_dashmap_secondary_index_same_slot_and_forks ( ) {
let ( key_start , key_end , account_index ) = create_dashmap_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2022-02-16 16:23:25 -08:00
for token_id in [ inline_spl_token ::id ( ) , inline_spl_token_2022 ::id ( ) ] {
run_test_secondary_indexes_same_slot_and_forks (
& token_id ,
& index ,
& index . spl_token_mint_index ,
key_start ,
key_end ,
& account_index ,
) ;
}
2020-12-31 18:06:03 -08:00
}
#[ test ]
fn test_rwlock_secondary_index_same_slot_and_forks ( ) {
let ( key_start , key_end , account_index ) = create_rwlock_secondary_index_state ( ) ;
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2022-02-16 16:23:25 -08:00
for token_id in [ inline_spl_token ::id ( ) , inline_spl_token_2022 ::id ( ) ] {
run_test_secondary_indexes_same_slot_and_forks (
& token_id ,
& index ,
& index . spl_token_owner_index ,
key_start ,
key_end ,
& account_index ,
) ;
}
2020-12-31 18:06:03 -08:00
}
2021-01-24 09:50:19 -08:00
2021-09-14 15:51:07 -07:00
impl IndexValue for bool { }
impl IndexValue for u64 { }
2021-08-06 06:39:34 -07:00
impl IsCached for bool {
fn is_cached ( & self ) -> bool {
false
}
}
impl IsCached for u64 {
fn is_cached ( & self ) -> bool {
false
}
}
2021-01-24 09:50:19 -08:00
impl ZeroLamport for bool {
fn is_zero_lamport ( & self ) -> bool {
false
}
}
impl ZeroLamport for u64 {
fn is_zero_lamport ( & self ) -> bool {
false
}
}
2021-07-15 08:26:50 -07:00
#[ test ]
2021-07-27 11:40:45 -07:00
fn test_bin_start_and_range ( ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
None ::< & RangeInclusive < Pubkey > > ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-27 11:40:45 -07:00
assert_eq! ( ( 0 , usize ::MAX ) , iter . bin_start_and_range ( ) ) ;
let key_0 = Pubkey ::new ( & [ 0 ; 32 ] ) ;
let key_ff = Pubkey ::new ( & [ 0xff ; 32 ] ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & RangeInclusive ::new ( key_0 , key_ff ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
let bins = index . bins ( ) ;
assert_eq! ( ( 0 , bins ) , iter . bin_start_and_range ( ) ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & RangeInclusive ::new ( key_ff , key_0 ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
assert_eq! ( ( bins - 1 , 0 ) , iter . bin_start_and_range ( ) ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Included ( key_0 ) , Unbounded ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-27 11:40:45 -07:00
assert_eq! ( ( 0 , usize ::MAX ) , iter . bin_start_and_range ( ) ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Included ( key_ff ) , Unbounded ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
assert_eq! ( ( bins - 1 , usize ::MAX ) , iter . bin_start_and_range ( ) ) ;
2021-07-27 11:40:45 -07:00
assert_eq! (
( 0 .. 2 )
. into_iter ( )
. skip ( 1 )
. take ( usize ::MAX )
. collect ::< Vec < _ > > ( ) ,
vec! [ 1 ]
) ;
}
#[ test ]
fn test_start_end_bin ( ) {
2021-08-05 09:38:53 -07:00
let index = AccountsIndex ::< bool > ::default_for_tests ( ) ;
2021-09-02 14:32:42 -07:00
assert_eq! ( index . bins ( ) , BINS_FOR_TESTING ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
None ::< & RangeInclusive < Pubkey > > ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-15 08:26:50 -07:00
assert_eq! ( iter . start_bin ( ) , 0 ) ; // no range, so 0
2021-07-27 11:40:45 -07:00
assert_eq! ( iter . end_bin_inclusive ( ) , usize ::MAX ) ; // no range, so max
2021-07-15 08:26:50 -07:00
let key = Pubkey ::new ( & [ 0 ; 32 ] ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & RangeInclusive ::new ( key , key ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-15 08:26:50 -07:00
assert_eq! ( iter . start_bin ( ) , 0 ) ; // start at pubkey 0, so 0
2021-07-27 11:40:45 -07:00
assert_eq! ( iter . end_bin_inclusive ( ) , 0 ) ; // end at pubkey 0, so 0
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Included ( key ) , Excluded ( key ) ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-15 08:26:50 -07:00
assert_eq! ( iter . start_bin ( ) , 0 ) ; // start at pubkey 0, so 0
2021-07-27 11:40:45 -07:00
assert_eq! ( iter . end_bin_inclusive ( ) , 0 ) ; // end at pubkey 0, so 0
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Excluded ( key ) , Excluded ( key ) ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-07-15 08:26:50 -07:00
assert_eq! ( iter . start_bin ( ) , 0 ) ; // start at pubkey 0, so 0
2021-07-27 11:40:45 -07:00
assert_eq! ( iter . end_bin_inclusive ( ) , 0 ) ; // end at pubkey 0, so 0
2021-07-15 08:26:50 -07:00
let key = Pubkey ::new ( & [ 0xff ; 32 ] ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & RangeInclusive ::new ( key , key ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
let bins = index . bins ( ) ;
assert_eq! ( iter . start_bin ( ) , bins - 1 ) ; // start at highest possible pubkey, so bins - 1
assert_eq! ( iter . end_bin_inclusive ( ) , bins - 1 ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Included ( key ) , Excluded ( key ) ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
assert_eq! ( iter . start_bin ( ) , bins - 1 ) ; // start at highest possible pubkey, so bins - 1
assert_eq! ( iter . end_bin_inclusive ( ) , bins - 1 ) ;
2021-08-26 16:12:43 -07:00
let iter = AccountsIndexIterator ::new (
& index ,
2021-09-03 16:00:49 -07:00
Some ( & ( Excluded ( key ) , Excluded ( key ) ) ) ,
2021-08-26 16:12:43 -07:00
COLLECT_ALL_UNSORTED_FALSE ,
) ;
2021-08-04 07:18:05 -07:00
assert_eq! ( iter . start_bin ( ) , bins - 1 ) ; // start at highest possible pubkey, so bins - 1
assert_eq! ( iter . end_bin_inclusive ( ) , bins - 1 ) ;
2021-07-15 08:26:50 -07:00
}
2021-08-05 09:15:26 -07:00
#[ test ]
#[ should_panic(expected = " bins.is_power_of_two() " ) ]
2021-09-17 11:12:06 -07:00
#[ allow(clippy::field_reassign_with_default) ]
2021-08-05 09:15:26 -07:00
fn test_illegal_bins ( ) {
2021-09-17 11:12:06 -07:00
let mut config = AccountsIndexConfig ::default ( ) ;
config . bins = Some ( 3 ) ;
AccountsIndex ::< bool > ::new ( Some ( config ) ) ;
2021-08-05 09:15:26 -07:00
}
2021-12-08 12:09:34 -08:00
#[ test ]
fn test_scan_config ( ) {
for collect_all_unsorted in [ false , true ] {
let config = ScanConfig ::new ( collect_all_unsorted ) ;
assert_eq! ( config . collect_all_unsorted , collect_all_unsorted ) ;
assert! ( config . abort . is_none ( ) ) ; // not allocated
assert! ( ! config . is_aborted ( ) ) ;
config . abort ( ) ; // has no effect
assert! ( ! config . is_aborted ( ) ) ;
}
let config = ScanConfig ::default ( ) ;
assert! ( ! config . collect_all_unsorted ) ;
assert! ( config . abort . is_none ( ) ) ;
let config = config . recreate_with_abort ( ) ;
assert! ( config . abort . is_some ( ) ) ;
assert! ( ! config . is_aborted ( ) ) ;
config . abort ( ) ;
assert! ( config . is_aborted ( ) ) ;
let config = config . recreate_with_abort ( ) ;
assert! ( config . is_aborted ( ) ) ;
}
2019-04-15 17:15:50 -07:00
}