1pub(crate) mod in_mem_accounts_index;
2use {
3 crate::{
4 accounts_index_storage::{AccountsIndexStorage, Startup},
5 accounts_partition::RentPayingAccountsByPartition,
6 ancestors::Ancestors,
7 bucket_map_holder::{Age, AtomicAge, BucketMapHolder},
8 contains::Contains,
9 pubkey_bins::PubkeyBinCalculator24,
10 rolling_bit_field::RollingBitField,
11 secondary_index::*,
12 },
13 in_mem_accounts_index::{InMemAccountsIndex, InsertNewEntryResults, StartupStats},
14 log::*,
15 rand::{thread_rng, Rng},
16 rayon::{
17 iter::{IntoParallelIterator, ParallelIterator},
18 ThreadPool,
19 },
20 solana_measure::measure::Measure,
21 solana_nohash_hasher::IntSet,
22 solana_sdk::{
23 account::ReadableAccount,
24 clock::{BankId, Slot},
25 pubkey::Pubkey,
26 },
27 std::{
28 collections::{btree_map::BTreeMap, HashSet},
29 fmt::Debug,
30 num::NonZeroUsize,
31 ops::{
32 Bound,
33 Bound::{Excluded, Included, Unbounded},
34 Range, RangeBounds,
35 },
36 path::PathBuf,
37 sync::{
38 atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
39 Arc, Mutex, OnceLock, RwLock,
40 },
41 },
42 thiserror::Error,
43};
44
45pub const ITER_BATCH_SIZE: usize = 1000;
46pub const BINS_DEFAULT: usize = 8192;
47pub const BINS_FOR_TESTING: usize = 2; pub const BINS_FOR_BENCHMARKS: usize = 8192;
49pub const FLUSH_THREADS_TESTING: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) };
51pub const ACCOUNTS_INDEX_CONFIG_FOR_TESTING: AccountsIndexConfig = AccountsIndexConfig {
52 bins: Some(BINS_FOR_TESTING),
53 num_flush_threads: Some(FLUSH_THREADS_TESTING),
54 drives: None,
55 index_limit_mb: IndexLimitMb::Unlimited,
56 ages_to_stay_in_cache: None,
57 scan_results_limit_bytes: None,
58 started_from_validator: false,
59};
60pub const ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS: AccountsIndexConfig = AccountsIndexConfig {
61 bins: Some(BINS_FOR_BENCHMARKS),
62 num_flush_threads: Some(FLUSH_THREADS_TESTING),
63 drives: None,
64 index_limit_mb: IndexLimitMb::Unlimited,
65 ages_to_stay_in_cache: None,
66 scan_results_limit_bytes: None,
67 started_from_validator: false,
68};
69pub type ScanResult<T> = Result<T, ScanError>;
70pub type SlotList<T> = Vec<(Slot, T)>;
71pub type SlotSlice<'s, T> = &'s [(Slot, T)];
72pub type RefCount = u64;
73pub type AccountMap<T, U> = Arc<InMemAccountsIndex<T, U>>;
74
75#[derive(Default, Debug, PartialEq, Eq)]
76pub(crate) struct GenerateIndexResult<T: IndexValue> {
77 pub count: usize,
79 pub duplicates: Option<Vec<(Pubkey, (Slot, T))>>,
81}
82
83#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
84pub enum ScanFilter {
86 #[default]
88 All,
89
90 OnlyAbnormal,
93
94 OnlyAbnormalWithVerify,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub enum UpsertReclaim {
102 PreviousSlotEntryWasCached,
104 PopulateReclaims,
107 IgnoreReclaims,
109}
110
111#[derive(Debug)]
112pub struct ScanConfig {
113 pub abort: Option<Arc<AtomicBool>>,
115
116 pub collect_all_unsorted: bool,
119}
120
121impl Default for ScanConfig {
122 fn default() -> Self {
123 Self {
124 abort: None,
125 collect_all_unsorted: true,
126 }
127 }
128}
129
130impl ScanConfig {
131 pub fn new(collect_all_unsorted: bool) -> Self {
132 Self {
133 collect_all_unsorted,
134 ..Default::default()
135 }
136 }
137
138 pub fn abort(&self) {
140 if let Some(abort) = self.abort.as_ref() {
141 abort.store(true, Ordering::Relaxed)
142 }
143 }
144
145 pub fn recreate_with_abort(&self) -> Self {
147 ScanConfig {
148 abort: Some(self.abort.clone().unwrap_or_default()),
149 collect_all_unsorted: self.collect_all_unsorted,
150 }
151 }
152
153 pub fn is_aborted(&self) -> bool {
155 if let Some(abort) = self.abort.as_ref() {
156 abort.load(Ordering::Relaxed)
157 } else {
158 false
159 }
160 }
161}
162
163pub(crate) type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>;
164
165pub trait IsCached {
166 fn is_cached(&self) -> bool;
167}
168
169pub trait IndexValue: 'static + IsCached + ZeroLamport + DiskIndexValue {}
170
171pub trait DiskIndexValue:
172 'static + Clone + Debug + PartialEq + Copy + Default + Sync + Send
173{
174}
175
176#[derive(Error, Debug, PartialEq, Eq)]
177pub enum ScanError {
178 #[error("Node detected it replayed bad version of slot {slot:?} with id {bank_id:?}, thus the scan on said slot was aborted")]
179 SlotRemoved { slot: Slot, bank_id: BankId },
180 #[error("scan aborted: {0}")]
181 Aborted(String),
182}
183
184enum ScanTypes<R: RangeBounds<Pubkey>> {
185 Unindexed(Option<R>),
186 Indexed(IndexKey),
187}
188
189#[derive(Debug, Clone, Copy)]
190pub enum IndexKey {
191 ProgramId(Pubkey),
192 SplTokenMint(Pubkey),
193 SplTokenOwner(Pubkey),
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Hash)]
197pub enum AccountIndex {
198 ProgramId,
199 SplTokenMint,
200 SplTokenOwner,
201}
202
203#[derive(Debug, PartialEq, Eq, Clone)]
204pub struct AccountSecondaryIndexesIncludeExclude {
205 pub exclude: bool,
206 pub keys: HashSet<Pubkey>,
207}
208
209#[derive(Debug, Copy, Clone, Default)]
211pub enum IndexLimitMb {
212 #[default]
215 Unlimited,
216 InMemOnly,
218}
219
220#[derive(Debug, Default, Clone)]
221pub struct AccountsIndexConfig {
222 pub bins: Option<usize>,
223 pub num_flush_threads: Option<NonZeroUsize>,
224 pub drives: Option<Vec<PathBuf>>,
225 pub index_limit_mb: IndexLimitMb,
226 pub ages_to_stay_in_cache: Option<Age>,
227 pub scan_results_limit_bytes: Option<usize>,
228 pub started_from_validator: bool,
230}
231
232pub fn default_num_flush_threads() -> NonZeroUsize {
233 NonZeroUsize::new(std::cmp::max(2, num_cpus::get() / 4)).expect("non-zero system threads")
234}
235
236#[derive(Debug, Default, Clone)]
237pub struct AccountSecondaryIndexes {
238 pub keys: Option<AccountSecondaryIndexesIncludeExclude>,
239 pub indexes: HashSet<AccountIndex>,
240}
241
242impl AccountSecondaryIndexes {
243 pub fn is_empty(&self) -> bool {
244 self.indexes.is_empty()
245 }
246 pub fn contains(&self, index: &AccountIndex) -> bool {
247 self.indexes.contains(index)
248 }
249 pub fn include_key(&self, key: &Pubkey) -> bool {
250 match &self.keys {
251 Some(options) => options.exclude ^ options.keys.contains(key),
252 None => true, }
254 }
255}
256
257#[derive(Debug, Default)]
258pub struct AccountMapEntryMeta {
261 pub dirty: AtomicBool,
263 pub age: AtomicAge,
265}
266
267impl AccountMapEntryMeta {
268 pub fn new_dirty<T: IndexValue, U: DiskIndexValue + From<T> + Into<T>>(
269 storage: &Arc<BucketMapHolder<T, U>>,
270 is_cached: bool,
271 ) -> Self {
272 AccountMapEntryMeta {
273 dirty: AtomicBool::new(true),
274 age: AtomicAge::new(storage.future_age_to_flush(is_cached)),
275 }
276 }
277 pub fn new_clean<T: IndexValue, U: DiskIndexValue + From<T> + Into<T>>(
278 storage: &Arc<BucketMapHolder<T, U>>,
279 ) -> Self {
280 AccountMapEntryMeta {
281 dirty: AtomicBool::new(false),
282 age: AtomicAge::new(storage.future_age_to_flush(false)),
283 }
284 }
285}
286
287#[derive(Debug, Default)]
288pub struct AccountMapEntryInner<T> {
291 ref_count: AtomicU64,
294 pub slot_list: RwLock<SlotList<T>>,
298 pub meta: AccountMapEntryMeta,
300}
301
302impl<T: IndexValue> AccountMapEntryInner<T> {
303 pub fn new(slot_list: SlotList<T>, ref_count: RefCount, meta: AccountMapEntryMeta) -> Self {
304 Self {
305 slot_list: RwLock::new(slot_list),
306 ref_count: AtomicU64::new(ref_count),
307 meta,
308 }
309 }
310 pub fn ref_count(&self) -> RefCount {
311 self.ref_count.load(Ordering::Acquire)
312 }
313
314 pub fn addref(&self) {
315 self.ref_count.fetch_add(1, Ordering::Release);
316 self.set_dirty(true);
317 }
318
319 pub fn unref(&self) -> RefCount {
323 let previous = self.ref_count.fetch_sub(1, Ordering::Release);
324 self.set_dirty(true);
325 if previous == 0 {
326 inc_new_counter_info!("accounts_index-deref_from_0", 1);
327 }
328 previous
329 }
330
331 pub fn dirty(&self) -> bool {
332 self.meta.dirty.load(Ordering::Acquire)
333 }
334
335 pub fn set_dirty(&self, value: bool) {
336 self.meta.dirty.store(value, Ordering::Release)
337 }
338
339 pub fn clear_dirty(&self) -> bool {
341 self.meta
342 .dirty
343 .compare_exchange(true, false, Ordering::AcqRel, Ordering::Relaxed)
344 .is_ok()
345 }
346
347 pub fn age(&self) -> Age {
348 self.meta.age.load(Ordering::Acquire)
349 }
350
351 pub fn set_age(&self, value: Age) {
352 self.meta.age.store(value, Ordering::Release)
353 }
354
355 pub fn try_exchange_age(&self, next_age: Age, expected_age: Age) {
357 let _ = self.meta.age.compare_exchange(
358 expected_age,
359 next_age,
360 Ordering::AcqRel,
361 Ordering::Relaxed,
362 );
363 }
364}
365
366pub enum PreAllocatedAccountMapEntry<T: IndexValue> {
368 Entry(AccountMapEntry<T>),
369 Raw((Slot, T)),
370}
371
372impl<T: IndexValue> ZeroLamport for PreAllocatedAccountMapEntry<T> {
373 fn is_zero_lamport(&self) -> bool {
374 match self {
375 PreAllocatedAccountMapEntry::Entry(entry) => {
376 entry.slot_list.read().unwrap()[0].1.is_zero_lamport()
377 }
378 PreAllocatedAccountMapEntry::Raw(raw) => raw.1.is_zero_lamport(),
379 }
380 }
381}
382
383impl<T: IndexValue> From<PreAllocatedAccountMapEntry<T>> for (Slot, T) {
384 fn from(source: PreAllocatedAccountMapEntry<T>) -> (Slot, T) {
385 match source {
386 PreAllocatedAccountMapEntry::Entry(entry) => entry.slot_list.read().unwrap()[0],
387 PreAllocatedAccountMapEntry::Raw(raw) => raw,
388 }
389 }
390}
391
392impl<T: IndexValue> PreAllocatedAccountMapEntry<T> {
393 pub fn new<U: DiskIndexValue + From<T> + Into<T>>(
399 slot: Slot,
400 account_info: T,
401 storage: &Arc<BucketMapHolder<T, U>>,
402 store_raw: bool,
403 ) -> PreAllocatedAccountMapEntry<T> {
404 if store_raw {
405 Self::Raw((slot, account_info))
406 } else {
407 Self::Entry(Self::allocate(slot, account_info, storage))
408 }
409 }
410
411 fn allocate<U: DiskIndexValue + From<T> + Into<T>>(
412 slot: Slot,
413 account_info: T,
414 storage: &Arc<BucketMapHolder<T, U>>,
415 ) -> AccountMapEntry<T> {
416 let is_cached = account_info.is_cached();
417 let ref_count = u64::from(!is_cached);
418 let meta = AccountMapEntryMeta::new_dirty(storage, is_cached);
419 Arc::new(AccountMapEntryInner::new(
420 vec![(slot, account_info)],
421 ref_count,
422 meta,
423 ))
424 }
425
426 pub fn into_account_map_entry<U: DiskIndexValue + From<T> + Into<T>>(
427 self,
428 storage: &Arc<BucketMapHolder<T, U>>,
429 ) -> AccountMapEntry<T> {
430 match self {
431 Self::Entry(entry) => entry,
432 Self::Raw((slot, account_info)) => Self::allocate(slot, account_info, storage),
433 }
434 }
435}
436
437#[derive(Debug)]
438pub struct RootsTracker {
439 pub alive_roots: RollingBitField,
444 uncleaned_roots: IntSet<Slot>,
445}
446
447impl Default for RootsTracker {
448 fn default() -> Self {
449 RootsTracker::new(4194304)
453 }
454}
455
456impl RootsTracker {
457 pub fn new(max_width: u64) -> Self {
458 Self {
459 alive_roots: RollingBitField::new(max_width),
460 uncleaned_roots: IntSet::default(),
461 }
462 }
463
464 pub fn min_alive_root(&self) -> Option<Slot> {
465 self.alive_roots.min()
466 }
467}
468
469#[derive(Debug, Default)]
470pub struct AccountsIndexRootsStats {
471 pub roots_len: Option<usize>,
472 pub uncleaned_roots_len: Option<usize>,
473 pub roots_range: Option<u64>,
474 pub rooted_cleaned_count: usize,
475 pub unrooted_cleaned_count: usize,
476 pub clean_unref_from_storage_us: u64,
477 pub clean_dead_slot_us: u64,
478}
479
480pub struct AccountsIndexIterator<'a, T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> {
481 account_maps: &'a LockMapTypeSlice<T, U>,
482 bin_calculator: &'a PubkeyBinCalculator24,
483 start_bound: Bound<Pubkey>,
484 end_bound: Bound<Pubkey>,
485 is_finished: bool,
486 collect_all_unsorted: bool,
487}
488
489impl<'a, T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> AccountsIndexIterator<'a, T, U> {
490 fn range<R>(
491 map: &AccountMaps<T, U>,
492 range: R,
493 collect_all_unsorted: bool,
494 ) -> Vec<(Pubkey, AccountMapEntry<T>)>
495 where
496 R: RangeBounds<Pubkey> + std::fmt::Debug,
497 {
498 let mut result = map.items(&range);
499 if !collect_all_unsorted {
500 result.sort_unstable_by(|a, b| a.0.cmp(&b.0));
501 }
502 result
503 }
504
505 fn clone_bound(bound: Bound<&Pubkey>) -> Bound<Pubkey> {
506 match bound {
507 Unbounded => Unbounded,
508 Included(k) => Included(*k),
509 Excluded(k) => Excluded(*k),
510 }
511 }
512
513 fn bin_from_bound(&self, bound: &Bound<Pubkey>, unbounded_bin: usize) -> usize {
514 match bound {
515 Bound::Included(bound) | Bound::Excluded(bound) => {
516 self.bin_calculator.bin_from_pubkey(bound)
517 }
518 Bound::Unbounded => unbounded_bin,
519 }
520 }
521
522 fn start_bin(&self) -> usize {
523 self.bin_from_bound(&self.start_bound, 0)
525 }
526
527 fn end_bin_inclusive(&self) -> usize {
528 self.bin_from_bound(&self.end_bound, usize::MAX)
530 }
531
532 fn bin_start_and_range(&self) -> (usize, usize) {
533 let start_bin = self.start_bin();
534 let end_bin_inclusive = self.end_bin_inclusive();
536 let bin_range = if start_bin > end_bin_inclusive {
537 0 } else if end_bin_inclusive == usize::MAX {
539 usize::MAX
540 } else {
541 end_bin_inclusive.saturating_add(1) - start_bin
544 };
545 (start_bin, bin_range)
546 }
547
548 pub fn new<R>(
549 index: &'a AccountsIndex<T, U>,
550 range: Option<&R>,
551 collect_all_unsorted: bool,
552 ) -> Self
553 where
554 R: RangeBounds<Pubkey>,
555 {
556 Self {
557 start_bound: range
558 .as_ref()
559 .map(|r| Self::clone_bound(r.start_bound()))
560 .unwrap_or(Unbounded),
561 end_bound: range
562 .as_ref()
563 .map(|r| Self::clone_bound(r.end_bound()))
564 .unwrap_or(Unbounded),
565 account_maps: &index.account_maps,
566 is_finished: false,
567 bin_calculator: &index.bin_calculator,
568 collect_all_unsorted,
569 }
570 }
571
572 pub fn hold_range_in_memory<R>(&self, range: &R, start_holding: bool, thread_pool: &ThreadPool)
573 where
574 R: RangeBounds<Pubkey> + Debug + Sync,
575 {
576 let (start_bin, bin_range) = self.bin_start_and_range();
578 thread_pool.install(|| {
581 (0..bin_range).into_par_iter().for_each(|idx| {
582 let map = &self.account_maps[idx + start_bin];
583 map.hold_range_in_memory(range, start_holding);
584 });
585 });
586 }
587}
588
589impl<'a, T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> Iterator
590 for AccountsIndexIterator<'a, T, U>
591{
592 type Item = Vec<(Pubkey, AccountMapEntry<T>)>;
593 fn next(&mut self) -> Option<Self::Item> {
594 if self.is_finished {
595 return None;
596 }
597 let (start_bin, bin_range) = self.bin_start_and_range();
598 let mut chunk = Vec::with_capacity(ITER_BATCH_SIZE);
599 'outer: for i in self.account_maps.iter().skip(start_bin).take(bin_range) {
600 for (pubkey, account_map_entry) in Self::range(
601 &i,
602 (self.start_bound, self.end_bound),
603 self.collect_all_unsorted,
604 ) {
605 if chunk.len() >= ITER_BATCH_SIZE && !self.collect_all_unsorted {
606 break 'outer;
607 }
608 let item = (pubkey, account_map_entry);
609 chunk.push(item);
610 }
611 }
612
613 if chunk.is_empty() {
614 self.is_finished = true;
615 return None;
616 } else if self.collect_all_unsorted {
617 self.is_finished = true;
618 }
619
620 self.start_bound = Excluded(chunk.last().unwrap().0);
621 Some(chunk)
622 }
623}
624
625pub trait ZeroLamport {
626 fn is_zero_lamport(&self) -> bool;
627}
628
629type MapType<T, U> = AccountMap<T, U>;
630type LockMapType<T, U> = Vec<MapType<T, U>>;
631type LockMapTypeSlice<T, U> = [MapType<T, U>];
632type AccountMaps<'a, T, U> = &'a MapType<T, U>;
633
634#[derive(Debug, Default)]
635pub struct ScanSlotTracker {
636 is_removed: bool,
637}
638
639impl ScanSlotTracker {
640 pub fn is_removed(&self) -> bool {
641 self.is_removed
642 }
643
644 pub fn mark_removed(&mut self) {
645 self.is_removed = true;
646 }
647}
648
649#[derive(Copy, Clone)]
650pub enum AccountsIndexScanResult {
651 OnlyKeepInMemoryIfDirty,
653 KeepInMemory,
655 Unref,
657 UnrefAssert0,
659 UnrefLog0,
661}
662
663#[derive(Debug)]
664pub struct AccountsIndex<T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> {
667 pub account_maps: LockMapType<T, U>,
668 pub bin_calculator: PubkeyBinCalculator24,
669 program_id_index: SecondaryIndex<RwLockSecondaryIndexEntry>,
670 spl_token_mint_index: SecondaryIndex<RwLockSecondaryIndexEntry>,
671 spl_token_owner_index: SecondaryIndex<RwLockSecondaryIndexEntry>,
672 pub roots_tracker: RwLock<RootsTracker>,
673 ongoing_scan_roots: RwLock<BTreeMap<Slot, u64>>,
674 pub removed_bank_ids: Mutex<HashSet<BankId>>,
685
686 storage: AccountsIndexStorage<T, U>,
687
688 pub scan_results_limit_bytes: Option<usize>,
690
691 pub purge_older_root_entries_one_slot_list: AtomicUsize,
692
693 pub roots_added: AtomicUsize,
695 pub roots_removed: AtomicUsize,
697 pub active_scans: AtomicUsize,
699 pub max_distance_to_min_scan_slot: AtomicU64,
701 pub unref_zero_count: AtomicU64,
703
704 pub rent_paying_accounts_by_partition: OnceLock<RentPayingAccountsByPartition>,
706}
707
708impl<T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> AccountsIndex<T, U> {
709 pub fn default_for_tests() -> Self {
710 Self::new(Some(ACCOUNTS_INDEX_CONFIG_FOR_TESTING), Arc::default())
711 }
712
713 pub fn new(config: Option<AccountsIndexConfig>, exit: Arc<AtomicBool>) -> Self {
714 let scan_results_limit_bytes = config
715 .as_ref()
716 .and_then(|config| config.scan_results_limit_bytes);
717 let (account_maps, bin_calculator, storage) = Self::allocate_accounts_index(config, exit);
718 Self {
719 purge_older_root_entries_one_slot_list: AtomicUsize::default(),
720 account_maps,
721 bin_calculator,
722 program_id_index: SecondaryIndex::<RwLockSecondaryIndexEntry>::new(
723 "program_id_index_stats",
724 ),
725 spl_token_mint_index: SecondaryIndex::<RwLockSecondaryIndexEntry>::new(
726 "spl_token_mint_index_stats",
727 ),
728 spl_token_owner_index: SecondaryIndex::<RwLockSecondaryIndexEntry>::new(
729 "spl_token_owner_index_stats",
730 ),
731 roots_tracker: RwLock::<RootsTracker>::default(),
732 ongoing_scan_roots: RwLock::<BTreeMap<Slot, u64>>::default(),
733 removed_bank_ids: Mutex::<HashSet<BankId>>::default(),
734 storage,
735 scan_results_limit_bytes,
736 roots_added: AtomicUsize::default(),
737 roots_removed: AtomicUsize::default(),
738 active_scans: AtomicUsize::default(),
739 max_distance_to_min_scan_slot: AtomicU64::default(),
740 unref_zero_count: AtomicU64::default(),
741 rent_paying_accounts_by_partition: OnceLock::default(),
742 }
743 }
744
745 fn allocate_accounts_index(
746 config: Option<AccountsIndexConfig>,
747 exit: Arc<AtomicBool>,
748 ) -> (
749 LockMapType<T, U>,
750 PubkeyBinCalculator24,
751 AccountsIndexStorage<T, U>,
752 ) {
753 let bins = config
754 .as_ref()
755 .and_then(|config| config.bins)
756 .unwrap_or(BINS_DEFAULT);
757 let bin_calculator = PubkeyBinCalculator24::new(bins);
759 let storage = AccountsIndexStorage::new(bins, &config, exit);
760 let account_maps = (0..bins)
761 .map(|bin| Arc::clone(&storage.in_mem[bin]))
762 .collect::<Vec<_>>();
763 (account_maps, bin_calculator, storage)
764 }
765
766 fn iter<R>(&self, range: Option<&R>, collect_all_unsorted: bool) -> AccountsIndexIterator<T, U>
767 where
768 R: RangeBounds<Pubkey>,
769 {
770 AccountsIndexIterator::new(self, range, collect_all_unsorted)
771 }
772
773 pub fn is_disk_index_enabled(&self) -> bool {
775 self.storage.storage.is_disk_index_enabled()
776 }
777
778 fn min_ongoing_scan_root_from_btree(ongoing_scan_roots: &BTreeMap<Slot, u64>) -> Option<Slot> {
779 ongoing_scan_roots.keys().next().cloned()
780 }
781
782 fn do_checked_scan_accounts<F, R>(
783 &self,
784 metric_name: &'static str,
785 ancestors: &Ancestors,
786 scan_bank_id: BankId,
787 func: F,
788 scan_type: ScanTypes<R>,
789 config: &ScanConfig,
790 ) -> Result<(), ScanError>
791 where
792 F: FnMut(&Pubkey, (&T, Slot)),
793 R: RangeBounds<Pubkey> + std::fmt::Debug,
794 {
795 {
796 let locked_removed_bank_ids = self.removed_bank_ids.lock().unwrap();
797 if locked_removed_bank_ids.contains(&scan_bank_id) {
798 return Err(ScanError::SlotRemoved {
799 slot: ancestors.max_slot(),
800 bank_id: scan_bank_id,
801 });
802 }
803 }
804
805 self.active_scans.fetch_add(1, Ordering::Relaxed);
806 let max_root = {
807 let mut w_ongoing_scan_roots = self
808 .ongoing_scan_roots
813 .write()
814 .unwrap();
815 let max_root_inclusive = self.max_root_inclusive();
820 if let Some(min_ongoing_scan_root) =
821 Self::min_ongoing_scan_root_from_btree(&w_ongoing_scan_roots)
822 {
823 if min_ongoing_scan_root < max_root_inclusive {
824 let current = max_root_inclusive - min_ongoing_scan_root;
825 self.max_distance_to_min_scan_slot
826 .fetch_max(current, Ordering::Relaxed);
827 }
828 }
829 *w_ongoing_scan_roots.entry(max_root_inclusive).or_default() += 1;
830
831 max_root_inclusive
832 };
833
834 let empty = Ancestors::default();
885 let ancestors = if ancestors.contains_key(&max_root) {
886 ancestors
887 } else {
888 &empty
909 };
910
911 match scan_type {
950 ScanTypes::Unindexed(range) => {
951 self.do_scan_accounts(metric_name, ancestors, func, range, Some(max_root), config);
953 }
954 ScanTypes::Indexed(IndexKey::ProgramId(program_id)) => {
955 self.do_scan_secondary_index(
956 ancestors,
957 func,
958 &self.program_id_index,
959 &program_id,
960 Some(max_root),
961 config,
962 );
963 }
964 ScanTypes::Indexed(IndexKey::SplTokenMint(mint_key)) => {
965 self.do_scan_secondary_index(
966 ancestors,
967 func,
968 &self.spl_token_mint_index,
969 &mint_key,
970 Some(max_root),
971 config,
972 );
973 }
974 ScanTypes::Indexed(IndexKey::SplTokenOwner(owner_key)) => {
975 self.do_scan_secondary_index(
976 ancestors,
977 func,
978 &self.spl_token_owner_index,
979 &owner_key,
980 Some(max_root),
981 config,
982 );
983 }
984 }
985
986 {
987 self.active_scans.fetch_sub(1, Ordering::Relaxed);
988 let mut ongoing_scan_roots = self.ongoing_scan_roots.write().unwrap();
989 let count = ongoing_scan_roots.get_mut(&max_root).unwrap();
990 *count -= 1;
991 if *count == 0 {
992 ongoing_scan_roots.remove(&max_root);
993 }
994 }
995
996 let was_scan_corrupted = self
999 .removed_bank_ids
1000 .lock()
1001 .unwrap()
1002 .contains(&scan_bank_id);
1003
1004 if was_scan_corrupted {
1005 Err(ScanError::SlotRemoved {
1006 slot: ancestors.max_slot(),
1007 bank_id: scan_bank_id,
1008 })
1009 } else {
1010 Ok(())
1011 }
1012 }
1013
1014 fn do_unchecked_scan_accounts<F, R>(
1015 &self,
1016 metric_name: &'static str,
1017 ancestors: &Ancestors,
1018 func: F,
1019 range: Option<R>,
1020 config: &ScanConfig,
1021 ) where
1022 F: FnMut(&Pubkey, (&T, Slot)),
1023 R: RangeBounds<Pubkey> + std::fmt::Debug,
1024 {
1025 self.do_scan_accounts(metric_name, ancestors, func, range, None, config);
1026 }
1027
1028 fn do_scan_accounts<F, R>(
1032 &self,
1033 metric_name: &'static str,
1034 ancestors: &Ancestors,
1035 mut func: F,
1036 range: Option<R>,
1037 max_root: Option<Slot>,
1038 config: &ScanConfig,
1039 ) where
1040 F: FnMut(&Pubkey, (&T, Slot)),
1041 R: RangeBounds<Pubkey> + std::fmt::Debug,
1042 {
1043 let mut total_elapsed_timer = Measure::start("total");
1046 let mut num_keys_iterated = 0;
1047 let mut latest_slot_elapsed = 0;
1048 let mut load_account_elapsed = 0;
1049 let mut read_lock_elapsed = 0;
1050 let mut iterator_elapsed = 0;
1051 let mut iterator_timer = Measure::start("iterator_elapsed");
1052 for pubkey_list in self.iter(range.as_ref(), config.collect_all_unsorted) {
1053 iterator_timer.stop();
1054 iterator_elapsed += iterator_timer.as_us();
1055 for (pubkey, list) in pubkey_list {
1056 num_keys_iterated += 1;
1057 let mut read_lock_timer = Measure::start("read_lock");
1058 let list_r = &list.slot_list.read().unwrap();
1059 read_lock_timer.stop();
1060 read_lock_elapsed += read_lock_timer.as_us();
1061 let mut latest_slot_timer = Measure::start("latest_slot");
1062 if let Some(index) = self.latest_slot(Some(ancestors), list_r, max_root) {
1063 latest_slot_timer.stop();
1064 latest_slot_elapsed += latest_slot_timer.as_us();
1065 let mut load_account_timer = Measure::start("load_account");
1066 func(&pubkey, (&list_r[index].1, list_r[index].0));
1067 load_account_timer.stop();
1068 load_account_elapsed += load_account_timer.as_us();
1069 }
1070 if config.is_aborted() {
1071 return;
1072 }
1073 }
1074 iterator_timer = Measure::start("iterator_elapsed");
1075 }
1076
1077 total_elapsed_timer.stop();
1078 if !metric_name.is_empty() {
1079 datapoint_info!(
1080 metric_name,
1081 ("total_elapsed", total_elapsed_timer.as_us(), i64),
1082 ("latest_slot_elapsed", latest_slot_elapsed, i64),
1083 ("read_lock_elapsed", read_lock_elapsed, i64),
1084 ("load_account_elapsed", load_account_elapsed, i64),
1085 ("iterator_elapsed", iterator_elapsed, i64),
1086 ("num_keys_iterated", num_keys_iterated, i64),
1087 )
1088 }
1089 }
1090
1091 fn do_scan_secondary_index<
1092 F,
1093 SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
1094 >(
1095 &self,
1096 ancestors: &Ancestors,
1097 mut func: F,
1098 index: &SecondaryIndex<SecondaryIndexEntryType>,
1099 index_key: &Pubkey,
1100 max_root: Option<Slot>,
1101 config: &ScanConfig,
1102 ) where
1103 F: FnMut(&Pubkey, (&T, Slot)),
1104 {
1105 for pubkey in index.get(index_key) {
1106 if config.is_aborted() {
1107 break;
1108 }
1109 if let Some(entry) = self.get_cloned(&pubkey) {
1110 self.get_account_info_with_and_then(
1111 &entry,
1112 Some(ancestors),
1113 max_root,
1114 |(slot, account_info)| func(&pubkey, (&account_info, slot)),
1115 );
1116 };
1117 }
1118 }
1119
1120 pub fn get_and_then<R>(
1124 &self,
1125 pubkey: &Pubkey,
1126 callback: impl FnOnce(Option<&AccountMapEntryInner<T>>) -> (bool, R),
1127 ) -> R {
1128 self.get_bin(pubkey).get_internal_inner(pubkey, callback)
1129 }
1130
1131 pub(crate) fn get_with_and_then<R>(
1134 &self,
1135 pubkey: &Pubkey,
1136 ancestors: Option<&Ancestors>,
1137 max_root: Option<Slot>,
1138 should_add_to_in_mem_cache: bool,
1139 callback: impl FnOnce((Slot, T)) -> R,
1140 ) -> Option<R> {
1141 self.get_and_then(pubkey, |entry| {
1142 let callback_result = entry.and_then(|entry| {
1143 self.get_account_info_with_and_then(entry, ancestors, max_root, callback)
1144 });
1145 (should_add_to_in_mem_cache, callback_result)
1146 })
1147 }
1148
1149 pub(crate) fn get_account_info_with_and_then<R>(
1152 &self,
1153 entry: &AccountMapEntryInner<T>,
1154 ancestors: Option<&Ancestors>,
1155 max_root: Option<Slot>,
1156 callback: impl FnOnce((Slot, T)) -> R,
1157 ) -> Option<R> {
1158 let slot_list = entry.slot_list.read().unwrap();
1159 self.latest_slot(ancestors, &slot_list, max_root)
1160 .map(|found_index| callback(slot_list[found_index]))
1161 }
1162
1163 pub fn get_cloned(&self, pubkey: &Pubkey) -> Option<AccountMapEntry<T>> {
1167 self.get_bin(pubkey)
1168 .get_internal_cloned(pubkey, |entry| entry)
1169 }
1170
1171 pub fn contains(&self, pubkey: &Pubkey) -> bool {
1173 self.get_and_then(pubkey, |entry| (false, entry.is_some()))
1174 }
1175
1176 #[cfg(test)]
1178 pub(crate) fn contains_with(
1179 &self,
1180 pubkey: &Pubkey,
1181 ancestors: Option<&Ancestors>,
1182 max_root: Option<Slot>,
1183 ) -> bool {
1184 self.get_with_and_then(pubkey, ancestors, max_root, false, |_| ())
1185 .is_some()
1186 }
1187
1188 fn slot_list_mut<RT>(
1189 &self,
1190 pubkey: &Pubkey,
1191 user_fn: impl FnOnce(&mut SlotList<T>) -> RT,
1192 ) -> Option<RT> {
1193 let read_lock = self.get_bin(pubkey);
1194 read_lock.slot_list_mut(pubkey, user_fn)
1195 }
1196
1197 #[must_use]
1200 pub fn handle_dead_keys(
1201 &self,
1202 dead_keys: &[&Pubkey],
1203 account_indexes: &AccountSecondaryIndexes,
1204 ) -> HashSet<Pubkey> {
1205 let mut pubkeys_removed_from_accounts_index = HashSet::default();
1206 if !dead_keys.is_empty() {
1207 for key in dead_keys.iter() {
1208 let w_index = self.get_bin(key);
1209 if w_index.remove_if_slot_list_empty(**key) {
1210 pubkeys_removed_from_accounts_index.insert(**key);
1211 self.purge_secondary_indexes_by_inner_key(key, account_indexes);
1215 }
1216 }
1217 }
1218 pubkeys_removed_from_accounts_index
1219 }
1220
1221 pub(crate) fn scan_accounts<F>(
1223 &self,
1224 ancestors: &Ancestors,
1225 scan_bank_id: BankId,
1226 func: F,
1227 config: &ScanConfig,
1228 ) -> Result<(), ScanError>
1229 where
1230 F: FnMut(&Pubkey, (&T, Slot)),
1231 {
1232 self.do_checked_scan_accounts(
1234 "",
1235 ancestors,
1236 scan_bank_id,
1237 func,
1238 ScanTypes::Unindexed(None::<Range<Pubkey>>),
1239 config,
1240 )
1241 }
1242
1243 pub(crate) fn unchecked_scan_accounts<F>(
1244 &self,
1245 metric_name: &'static str,
1246 ancestors: &Ancestors,
1247 func: F,
1248 config: &ScanConfig,
1249 ) where
1250 F: FnMut(&Pubkey, (&T, Slot)),
1251 {
1252 self.do_unchecked_scan_accounts(
1253 metric_name,
1254 ancestors,
1255 func,
1256 None::<Range<Pubkey>>,
1257 config,
1258 );
1259 }
1260
1261 pub(crate) fn range_scan_accounts<F, R>(
1264 &self,
1265 metric_name: &'static str,
1266 ancestors: &Ancestors,
1267 range: R,
1268 config: &ScanConfig,
1269 func: F,
1270 ) where
1271 F: FnMut(&Pubkey, (&T, Slot)),
1272 R: RangeBounds<Pubkey> + std::fmt::Debug,
1273 {
1274 self.do_unchecked_scan_accounts(metric_name, ancestors, func, Some(range), config);
1276 }
1277
1278 pub(crate) fn index_scan_accounts<F>(
1280 &self,
1281 ancestors: &Ancestors,
1282 scan_bank_id: BankId,
1283 index_key: IndexKey,
1284 func: F,
1285 config: &ScanConfig,
1286 ) -> Result<(), ScanError>
1287 where
1288 F: FnMut(&Pubkey, (&T, Slot)),
1289 {
1290 self.do_checked_scan_accounts(
1292 "",
1293 ancestors,
1294 scan_bank_id,
1295 func,
1296 ScanTypes::<Range<Pubkey>>::Indexed(index_key),
1297 config,
1298 )
1299 }
1300
1301 pub fn get_rooted_entries(
1302 &self,
1303 slice: SlotSlice<T>,
1304 max_inclusive: Option<Slot>,
1305 ) -> SlotList<T> {
1306 let max_inclusive = max_inclusive.unwrap_or(Slot::MAX);
1307 let lock = &self.roots_tracker.read().unwrap().alive_roots;
1308 slice
1309 .iter()
1310 .filter(|(slot, _)| *slot <= max_inclusive && lock.contains(slot))
1311 .cloned()
1312 .collect()
1313 }
1314
1315 pub(crate) fn purge_exact<'a, C>(
1319 &'a self,
1320 pubkey: &Pubkey,
1321 slots_to_purge: &'a C,
1322 reclaims: &mut SlotList<T>,
1323 ) -> bool
1324 where
1325 C: Contains<'a, Slot>,
1326 {
1327 self.slot_list_mut(pubkey, |slot_list| {
1328 slot_list.retain(|(slot, item)| {
1329 let should_purge = slots_to_purge.contains(slot);
1330 if should_purge {
1331 reclaims.push((*slot, *item));
1332 false
1333 } else {
1334 true
1335 }
1336 });
1337 slot_list.is_empty()
1338 })
1339 .unwrap_or(true)
1340 }
1341
1342 pub fn min_ongoing_scan_root(&self) -> Option<Slot> {
1343 Self::min_ongoing_scan_root_from_btree(&self.ongoing_scan_roots.read().unwrap())
1344 }
1345
1346 pub(crate) fn latest_slot(
1349 &self,
1350 ancestors: Option<&Ancestors>,
1351 slice: SlotSlice<T>,
1352 max_root_inclusive: Option<Slot>,
1353 ) -> Option<usize> {
1354 let mut current_max = 0;
1355 let mut rv = None;
1356 if let Some(ancestors) = ancestors {
1357 if !ancestors.is_empty() {
1358 for (i, (slot, _t)) in slice.iter().rev().enumerate() {
1359 if (rv.is_none() || *slot > current_max) && ancestors.contains_key(slot) {
1360 rv = Some(i);
1361 current_max = *slot;
1362 }
1363 }
1364 }
1365 }
1366
1367 let max_root_inclusive = max_root_inclusive.unwrap_or(Slot::MAX);
1368 let mut tracker = None;
1369
1370 for (i, (slot, _t)) in slice.iter().rev().enumerate() {
1371 if (rv.is_none() || *slot > current_max) && *slot <= max_root_inclusive {
1372 let lock = match tracker {
1373 Some(inner) => inner,
1374 None => self.roots_tracker.read().unwrap(),
1375 };
1376 if lock.alive_roots.contains(slot) {
1377 rv = Some(i);
1378 current_max = *slot;
1379 }
1380 tracker = Some(lock);
1381 }
1382 }
1383
1384 rv.map(|index| slice.len() - 1 - index)
1385 }
1386
1387 pub fn hold_range_in_memory<R>(&self, range: &R, start_holding: bool, thread_pool: &ThreadPool)
1388 where
1389 R: RangeBounds<Pubkey> + Debug + Sync,
1390 {
1391 let iter = self.iter(Some(range), true);
1392 iter.hold_range_in_memory(range, start_holding, thread_pool);
1393 }
1394
1395 pub(crate) fn get_startup_stats(&self) -> &StartupStats {
1397 &self.storage.storage.startup_stats
1398 }
1399
1400 pub fn set_startup(&self, value: Startup) {
1401 self.storage.set_startup(value);
1402 }
1403
1404 pub fn get_startup_remaining_items_to_flush_estimate(&self) -> usize {
1405 self.storage.get_startup_remaining_items_to_flush_estimate()
1406 }
1407
1408 pub(crate) fn scan<'a, F, I>(
1427 &self,
1428 pubkeys: I,
1429 mut callback: F,
1430 avoid_callback_result: Option<AccountsIndexScanResult>,
1431 provide_entry_in_callback: bool,
1432 filter: ScanFilter,
1433 ) where
1434 F: FnMut(
1435 &'a Pubkey,
1436 Option<(&SlotList<T>, RefCount)>,
1437 Option<&AccountMapEntry<T>>,
1438 ) -> AccountsIndexScanResult,
1439 I: Iterator<Item = &'a Pubkey>,
1440 {
1441 let mut lock = None;
1442 let mut last_bin = self.bins(); pubkeys.into_iter().for_each(|pubkey| {
1444 let bin = self.bin_calculator.bin_from_pubkey(pubkey);
1445 if bin != last_bin {
1446 lock = Some(&self.account_maps[bin]);
1448 last_bin = bin;
1449 }
1450
1451 let mut internal_callback = |entry: Option<&AccountMapEntry<T>>| {
1452 let mut cache = false;
1453 match entry {
1454 Some(locked_entry) => {
1455 let result = if let Some(result) = avoid_callback_result.as_ref() {
1456 *result
1457 } else {
1458 let slot_list = &locked_entry.slot_list.read().unwrap();
1459 callback(
1460 pubkey,
1461 Some((slot_list, locked_entry.ref_count())),
1462 provide_entry_in_callback.then_some(locked_entry),
1463 )
1464 };
1465 cache = match result {
1466 AccountsIndexScanResult::Unref => {
1467 if locked_entry.unref() == 0 {
1468 info!("scan: refcount of item already at 0: {pubkey}");
1469 self.unref_zero_count.fetch_add(1, Ordering::Relaxed);
1470 }
1471 true
1472 }
1473 AccountsIndexScanResult::UnrefAssert0 => {
1474 assert_eq!(
1475 locked_entry.unref(),
1476 1,
1477 "ref count expected to be zero, but is {}! {pubkey}, {:?}",
1478 locked_entry.ref_count(),
1479 locked_entry.slot_list.read().unwrap(),
1480 );
1481 true
1482 }
1483 AccountsIndexScanResult::UnrefLog0 => {
1484 let old_ref = locked_entry.unref();
1485 if old_ref != 1 {
1486 info!("Unexpected unref {pubkey} with {old_ref} {:?}, expect old_ref to be 1", locked_entry.slot_list.read().unwrap());
1487 datapoint_warn!(
1488 "accounts_db-unexpected-unref-zero",
1489 ("old_ref", old_ref, i64),
1490 ("pubkey", pubkey.to_string(), String),
1491 );
1492 }
1493 true
1494 }
1495 AccountsIndexScanResult::KeepInMemory => true,
1496 AccountsIndexScanResult::OnlyKeepInMemoryIfDirty => false,
1497 };
1498 }
1499 None => {
1500 avoid_callback_result.unwrap_or_else(|| callback(pubkey, None, None));
1501 }
1502 }
1503 (cache, ())
1504 };
1505
1506 match filter {
1507 ScanFilter::All => {
1508 lock.as_ref()
1512 .unwrap()
1513 .get_internal(pubkey, internal_callback);
1514 }
1515 ScanFilter::OnlyAbnormal | ScanFilter::OnlyAbnormalWithVerify => {
1516 let found = lock
1517 .as_ref()
1518 .unwrap()
1519 .get_only_in_mem(pubkey, false, |entry| {
1520 internal_callback(entry);
1521 entry.is_some()
1522 });
1523 if !found && matches!(filter, ScanFilter::OnlyAbnormalWithVerify) {
1524 lock.as_ref().unwrap().get_internal(pubkey, |entry| {
1525 assert!(entry.is_some(), "{pubkey}, entry: {entry:?}");
1526 let entry = entry.unwrap();
1527 assert_eq!(entry.ref_count(), 1, "{pubkey}");
1528 assert_eq!(entry.slot_list.read().unwrap().len(), 1, "{pubkey}");
1529 (false, ())
1530 });
1531 }
1532 }
1533 }
1534 });
1535 }
1536
1537 fn get_newest_root_in_slot_list(
1539 alive_roots: &RollingBitField,
1540 slice: SlotSlice<T>,
1541 max_allowed_root_inclusive: Option<Slot>,
1542 ) -> Slot {
1543 let mut max_root = 0;
1544 for (slot, _) in slice.iter() {
1545 if let Some(max_allowed_root_inclusive) = max_allowed_root_inclusive {
1546 if *slot > max_allowed_root_inclusive {
1547 continue;
1548 }
1549 }
1550 if *slot > max_root && alive_roots.contains(slot) {
1551 max_root = *slot;
1552 }
1553 }
1554 max_root
1555 }
1556
1557 fn update_spl_token_secondary_indexes<G: solana_inline_spl::token::GenericTokenAccount>(
1558 &self,
1559 token_id: &Pubkey,
1560 pubkey: &Pubkey,
1561 account_owner: &Pubkey,
1562 account_data: &[u8],
1563 account_indexes: &AccountSecondaryIndexes,
1564 ) {
1565 if *account_owner == *token_id {
1566 if account_indexes.contains(&AccountIndex::SplTokenOwner) {
1567 if let Some(owner_key) = G::unpack_account_owner(account_data) {
1568 if account_indexes.include_key(owner_key) {
1569 self.spl_token_owner_index.insert(owner_key, pubkey);
1570 }
1571 }
1572 }
1573
1574 if account_indexes.contains(&AccountIndex::SplTokenMint) {
1575 if let Some(mint_key) = G::unpack_account_mint(account_data) {
1576 if account_indexes.include_key(mint_key) {
1577 self.spl_token_mint_index.insert(mint_key, pubkey);
1578 }
1579 }
1580 }
1581 }
1582 }
1583
1584 pub fn get_index_key_size(&self, index: &AccountIndex, index_key: &Pubkey) -> Option<usize> {
1585 match index {
1586 AccountIndex::ProgramId => self.program_id_index.index.get(index_key).map(|x| x.len()),
1587 AccountIndex::SplTokenOwner => self
1588 .spl_token_owner_index
1589 .index
1590 .get(index_key)
1591 .map(|x| x.len()),
1592 AccountIndex::SplTokenMint => self
1593 .spl_token_mint_index
1594 .index
1595 .get(index_key)
1596 .map(|x| x.len()),
1597 }
1598 }
1599
1600 pub(crate) fn log_secondary_indexes(&self) {
1602 if !self.program_id_index.index.is_empty() {
1603 info!("secondary index: {:?}", AccountIndex::ProgramId);
1604 self.program_id_index.log_contents();
1605 }
1606 if !self.spl_token_mint_index.index.is_empty() {
1607 info!("secondary index: {:?}", AccountIndex::SplTokenMint);
1608 self.spl_token_mint_index.log_contents();
1609 }
1610 if !self.spl_token_owner_index.index.is_empty() {
1611 info!("secondary index: {:?}", AccountIndex::SplTokenOwner);
1612 self.spl_token_owner_index.log_contents();
1613 }
1614 }
1615
1616 pub(crate) fn update_secondary_indexes(
1617 &self,
1618 pubkey: &Pubkey,
1619 account: &impl ReadableAccount,
1620 account_indexes: &AccountSecondaryIndexes,
1621 ) {
1622 if account_indexes.is_empty() {
1623 return;
1624 }
1625
1626 let account_owner = account.owner();
1627 let account_data = account.data();
1628
1629 if account_indexes.contains(&AccountIndex::ProgramId)
1630 && account_indexes.include_key(account_owner)
1631 {
1632 self.program_id_index.insert(account_owner, pubkey);
1633 }
1634 self.update_spl_token_secondary_indexes::<solana_inline_spl::token::Account>(
1649 &solana_inline_spl::token::id(),
1650 pubkey,
1651 account_owner,
1652 account_data,
1653 account_indexes,
1654 );
1655 self.update_spl_token_secondary_indexes::<solana_inline_spl::token_2022::Account>(
1656 &solana_inline_spl::token_2022::id(),
1657 pubkey,
1658 account_owner,
1659 account_data,
1660 account_indexes,
1661 );
1662 }
1663
1664 pub(crate) fn get_bin(&self, pubkey: &Pubkey) -> AccountMaps<T, U> {
1665 &self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)]
1666 }
1667
1668 pub fn bins(&self) -> usize {
1669 self.account_maps.len()
1670 }
1671
1672 fn remove_older_duplicate_pubkeys(
1676 items: &mut Vec<(Pubkey, (Slot, T))>,
1677 ) -> Option<Vec<(Pubkey, (Slot, T))>> {
1678 if items.len() < 2 {
1679 return None;
1680 }
1681 items.sort_by(|a, b| a.0.cmp(&b.0));
1684 let mut duplicates = None::<Vec<(Pubkey, (Slot, T))>>;
1685
1686 let n = items.len();
1689 let mut last_key = items[n - 1].0;
1690 let mut write = n - 1;
1691 let mut curr = write;
1692
1693 while curr > 0 {
1694 let curr_item = items[curr - 1];
1695
1696 if curr_item.0 == last_key {
1697 let mut duplicates_insert = duplicates.unwrap_or_default();
1698 duplicates_insert.push(curr_item);
1699 duplicates = Some(duplicates_insert);
1700 curr -= 1;
1701 } else {
1702 if curr < write {
1703 items[write - 1] = curr_item;
1704 }
1705 curr -= 1;
1706 write -= 1;
1707 last_key = curr_item.0;
1708 }
1709 }
1710
1711 items.drain(..(write - curr));
1712
1713 duplicates
1714 }
1715
1716 pub(crate) fn insert_new_if_missing_into_primary_index(
1724 &self,
1725 slot: Slot,
1726 approx_items_len: usize,
1727 items: impl Iterator<Item = (Pubkey, T)>,
1728 ) -> (Vec<Pubkey>, u64, GenerateIndexResult<T>) {
1729 let bins = self.bins();
1732 let expected_items_per_bin = approx_items_len * 2 / bins;
1733 let use_disk = self.storage.storage.disk.is_some();
1734 let mut binned = (0..bins)
1735 .map(|_| Vec::with_capacity(expected_items_per_bin))
1736 .collect::<Vec<_>>();
1737 let mut count = 0;
1738 let mut dirty_pubkeys = items
1739 .filter_map(|(pubkey, account_info)| {
1740 let pubkey_bin = self.bin_calculator.bin_from_pubkey(&pubkey);
1741 let is_zero_lamport = account_info.is_zero_lamport();
1743 let result = if is_zero_lamport { Some(pubkey) } else { None };
1744
1745 binned[pubkey_bin].push((pubkey, (slot, account_info)));
1746 result
1747 })
1748 .collect::<Vec<_>>();
1749
1750 let insertion_time = AtomicU64::new(0);
1751
1752 let random_offset = thread_rng().gen_range(0..bins);
1756 let mut duplicates = Vec::default();
1757 (0..bins).for_each(|pubkey_bin| {
1758 let pubkey_bin = (pubkey_bin + random_offset) % bins;
1759 let mut items = std::mem::take(&mut binned[pubkey_bin]);
1760 if items.is_empty() {
1761 return;
1762 }
1763
1764 let these_duplicates = Self::remove_older_duplicate_pubkeys(&mut items);
1765 if let Some(mut these_duplicates) = these_duplicates {
1766 duplicates.append(&mut these_duplicates);
1767 }
1768
1769 let r_account_maps = &self.account_maps[pubkey_bin];
1770 let mut insert_time = Measure::start("insert_into_primary_index");
1771 count += items.len();
1773 if use_disk {
1774 r_account_maps.startup_insert_only(items.into_iter());
1775 } else {
1776 items
1779 .into_iter()
1780 .for_each(|(pubkey, (slot, account_info))| {
1781 let new_entry = PreAllocatedAccountMapEntry::new(
1782 slot,
1783 account_info,
1784 &self.storage.storage,
1785 use_disk,
1786 );
1787 match r_account_maps
1788 .insert_new_entry_if_missing_with_lock(pubkey, new_entry)
1789 {
1790 InsertNewEntryResults::DidNotExist => {}
1791 InsertNewEntryResults::ExistedNewEntryZeroLamports => {}
1792 InsertNewEntryResults::ExistedNewEntryNonZeroLamports => {
1793 dirty_pubkeys.push(pubkey);
1794 }
1795 }
1796 });
1797 }
1798 insert_time.stop();
1799 insertion_time.fetch_add(insert_time.as_us(), Ordering::Relaxed);
1800 });
1801
1802 (
1803 dirty_pubkeys,
1804 insertion_time.load(Ordering::Relaxed),
1805 GenerateIndexResult {
1806 count,
1807 duplicates: (!duplicates.is_empty()).then_some(duplicates),
1808 },
1809 )
1810 }
1811
1812 pub(crate) fn populate_and_retrieve_duplicate_keys_from_startup(
1814 &self,
1815 f: impl Fn(Vec<(Slot, Pubkey)>) + Sync + Send,
1816 ) {
1817 (0..self.bins())
1818 .into_par_iter()
1819 .map(|pubkey_bin| {
1820 let r_account_maps = &self.account_maps[pubkey_bin];
1821 r_account_maps.populate_and_retrieve_duplicate_keys_from_startup()
1822 })
1823 .for_each(f);
1824 }
1825
1826 pub fn upsert(
1829 &self,
1830 new_slot: Slot,
1831 old_slot: Slot,
1832 pubkey: &Pubkey,
1833 account: &impl ReadableAccount,
1834 account_indexes: &AccountSecondaryIndexes,
1835 account_info: T,
1836 reclaims: &mut SlotList<T>,
1837 reclaim: UpsertReclaim,
1838 ) {
1839 let store_raw = true;
1841
1842 let new_item = PreAllocatedAccountMapEntry::new(
1854 new_slot,
1855 account_info,
1856 &self.storage.storage,
1857 store_raw,
1858 );
1859 let map = self.get_bin(pubkey);
1860
1861 map.upsert(pubkey, new_item, Some(old_slot), reclaims, reclaim);
1862 self.update_secondary_indexes(pubkey, account, account_indexes);
1863 }
1864
1865 pub fn ref_count_from_storage(&self, pubkey: &Pubkey) -> RefCount {
1866 let map = self.get_bin(pubkey);
1867 map.get_internal_inner(pubkey, |entry| {
1868 (
1869 false,
1870 entry.map(|entry| entry.ref_count()).unwrap_or_default(),
1871 )
1872 })
1873 }
1874
1875 fn purge_secondary_indexes_by_inner_key(
1876 &self,
1877 inner_key: &Pubkey,
1878 account_indexes: &AccountSecondaryIndexes,
1879 ) {
1880 if account_indexes.contains(&AccountIndex::ProgramId) {
1881 self.program_id_index.remove_by_inner_key(inner_key);
1882 }
1883
1884 if account_indexes.contains(&AccountIndex::SplTokenOwner) {
1885 self.spl_token_owner_index.remove_by_inner_key(inner_key);
1886 }
1887
1888 if account_indexes.contains(&AccountIndex::SplTokenMint) {
1889 self.spl_token_mint_index.remove_by_inner_key(inner_key);
1890 }
1891 }
1892
1893 fn purge_older_root_entries(
1894 &self,
1895 slot_list: &mut SlotList<T>,
1896 reclaims: &mut SlotList<T>,
1897 max_clean_root_inclusive: Option<Slot>,
1898 ) {
1899 if slot_list.len() <= 1 {
1900 self.purge_older_root_entries_one_slot_list
1901 .fetch_add(1, Ordering::Relaxed);
1902 }
1903 let newest_root_in_slot_list;
1904 let max_clean_root_inclusive = {
1905 let roots_tracker = &self.roots_tracker.read().unwrap();
1906 newest_root_in_slot_list = Self::get_newest_root_in_slot_list(
1907 &roots_tracker.alive_roots,
1908 slot_list,
1909 max_clean_root_inclusive,
1910 );
1911 max_clean_root_inclusive.unwrap_or_else(|| roots_tracker.alive_roots.max_inclusive())
1912 };
1913
1914 slot_list.retain(|(slot, value)| {
1915 let should_purge = Self::can_purge_older_entries(
1916 max_clean_root_inclusive,
1920 newest_root_in_slot_list,
1921 *slot,
1922 ) && !value.is_cached();
1923 if should_purge {
1924 reclaims.push((*slot, *value));
1925 }
1926 !should_purge
1927 });
1928 }
1929
1930 #[must_use]
1934 pub fn clean_rooted_entries(
1935 &self,
1936 pubkey: &Pubkey,
1937 reclaims: &mut SlotList<T>,
1938 max_clean_root_inclusive: Option<Slot>,
1939 ) -> bool {
1940 let mut is_slot_list_empty = false;
1941 let missing_in_accounts_index = self
1942 .slot_list_mut(pubkey, |slot_list| {
1943 self.purge_older_root_entries(slot_list, reclaims, max_clean_root_inclusive);
1944 is_slot_list_empty = slot_list.is_empty();
1945 })
1946 .is_none();
1947
1948 let mut removed = false;
1949 if is_slot_list_empty {
1954 let w_maps = self.get_bin(pubkey);
1955 removed = w_maps.remove_if_slot_list_empty(*pubkey);
1956 }
1957 removed || missing_in_accounts_index
1958 }
1959
1960 fn can_purge_older_entries(
1973 max_clean_root_exclusive: Slot,
1974 newest_root_in_slot_list: Slot,
1975 slot: Slot,
1976 ) -> bool {
1977 slot < max_clean_root_exclusive && slot != newest_root_in_slot_list
1978 }
1979
1980 pub fn get_rooted_from_list<'a>(&self, slots: impl Iterator<Item = &'a Slot>) -> Vec<Slot> {
1982 let roots_tracker = self.roots_tracker.read().unwrap();
1983 slots
1984 .filter_map(|s| {
1985 if roots_tracker.alive_roots.contains(s) {
1986 Some(*s)
1987 } else {
1988 None
1989 }
1990 })
1991 .collect()
1992 }
1993
1994 pub fn is_alive_root(&self, slot: Slot) -> bool {
1995 self.roots_tracker
1996 .read()
1997 .unwrap()
1998 .alive_roots
1999 .contains(&slot)
2000 }
2001
2002 pub fn add_root(&self, slot: Slot) {
2003 self.roots_added.fetch_add(1, Ordering::Relaxed);
2004 let mut w_roots_tracker = self.roots_tracker.write().unwrap();
2005 assert!(
2007 slot >= w_roots_tracker.alive_roots.max_inclusive(),
2008 "Roots must be added in order: {} < {}",
2009 slot,
2010 w_roots_tracker.alive_roots.max_inclusive()
2011 );
2012 w_roots_tracker.alive_roots.insert(slot);
2014 }
2015
2016 pub fn add_uncleaned_roots<I>(&self, roots: I)
2017 where
2018 I: IntoIterator<Item = Slot>,
2019 {
2020 let mut w_roots_tracker = self.roots_tracker.write().unwrap();
2021 w_roots_tracker.uncleaned_roots.extend(roots);
2022 }
2023
2024 #[cfg(feature = "dev-context-only-utils")]
2026 pub fn remove_uncleaned_root(&self, root: Slot) -> bool {
2027 self.roots_tracker
2028 .write()
2029 .unwrap()
2030 .uncleaned_roots
2031 .remove(&root)
2032 }
2033
2034 pub fn max_root_inclusive(&self) -> Slot {
2035 self.roots_tracker
2036 .read()
2037 .unwrap()
2038 .alive_roots
2039 .max_inclusive()
2040 }
2041
2042 pub fn clean_dead_slot(&self, slot: Slot) -> bool {
2046 let mut w_roots_tracker = self.roots_tracker.write().unwrap();
2047 let removed_from_unclean_roots = w_roots_tracker.uncleaned_roots.remove(&slot);
2048 if !w_roots_tracker.alive_roots.remove(&slot) {
2049 if removed_from_unclean_roots {
2050 error!("clean_dead_slot-removed_from_unclean_roots: {}", slot);
2051 inc_new_counter_error!("clean_dead_slot-removed_from_unclean_roots", 1, 1);
2052 }
2053 false
2054 } else {
2055 drop(w_roots_tracker);
2056 self.roots_removed.fetch_add(1, Ordering::Relaxed);
2057 true
2058 }
2059 }
2060
2061 pub(crate) fn update_roots_stats(&self, stats: &mut AccountsIndexRootsStats) {
2062 let roots_tracker = self.roots_tracker.read().unwrap();
2063 stats.roots_len = Some(roots_tracker.alive_roots.len());
2064 stats.uncleaned_roots_len = Some(roots_tracker.uncleaned_roots.len());
2065 stats.roots_range = Some(roots_tracker.alive_roots.range_width());
2066 }
2067
2068 pub fn min_alive_root(&self) -> Option<Slot> {
2069 self.roots_tracker.read().unwrap().min_alive_root()
2070 }
2071
2072 pub(crate) fn reset_uncleaned_roots(&self, max_clean_root: Option<Slot>) {
2073 let mut w_roots_tracker = self.roots_tracker.write().unwrap();
2074 w_roots_tracker.uncleaned_roots.retain(|root| {
2075 let is_cleaned = max_clean_root
2076 .map(|max_clean_root| *root <= max_clean_root)
2077 .unwrap_or(true);
2078 !is_cleaned
2080 });
2081 }
2082
2083 pub fn num_alive_roots(&self) -> usize {
2084 self.roots_tracker.read().unwrap().alive_roots.len()
2085 }
2086
2087 pub fn all_alive_roots(&self) -> Vec<Slot> {
2088 let tracker = self.roots_tracker.read().unwrap();
2089 tracker.alive_roots.get_all()
2090 }
2091
2092 pub fn clone_uncleaned_roots(&self) -> IntSet<Slot> {
2093 self.roots_tracker.read().unwrap().uncleaned_roots.clone()
2094 }
2095
2096 pub fn uncleaned_roots_len(&self) -> usize {
2097 self.roots_tracker.read().unwrap().uncleaned_roots.len()
2098 }
2099
2100 #[cfg(feature = "dev-context-only-utils")]
2102 pub fn purge_roots(&self, pubkey: &Pubkey) -> (SlotList<T>, bool) {
2106 self.slot_list_mut(pubkey, |slot_list| {
2107 let reclaims = self.get_rooted_entries(slot_list, None);
2108 slot_list.retain(|(slot, _)| !self.is_alive_root(*slot));
2109 (reclaims, slot_list.is_empty())
2110 })
2111 .unwrap()
2112 }
2113}
2114
2115#[cfg(test)]
2116pub mod tests {
2117 use {
2118 super::*,
2119 solana_inline_spl::token::SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
2120 solana_sdk::{
2121 account::{AccountSharedData, WritableAccount},
2122 pubkey::PUBKEY_BYTES,
2123 },
2124 std::ops::RangeInclusive,
2125 };
2126
2127 const SPL_TOKENS: &[Pubkey] = &[
2128 solana_inline_spl::token::id(),
2129 solana_inline_spl::token_2022::id(),
2130 ];
2131
2132 pub enum SecondaryIndexTypes<'a> {
2133 RwLock(&'a SecondaryIndex<RwLockSecondaryIndexEntry>),
2134 DashMap(&'a SecondaryIndex<DashMapSecondaryIndexEntry>),
2135 }
2136
2137 pub fn spl_token_mint_index_enabled() -> AccountSecondaryIndexes {
2138 let mut account_indexes = HashSet::new();
2139 account_indexes.insert(AccountIndex::SplTokenMint);
2140 AccountSecondaryIndexes {
2141 indexes: account_indexes,
2142 keys: None,
2143 }
2144 }
2145
2146 pub fn spl_token_owner_index_enabled() -> AccountSecondaryIndexes {
2147 let mut account_indexes = HashSet::new();
2148 account_indexes.insert(AccountIndex::SplTokenOwner);
2149 AccountSecondaryIndexes {
2150 indexes: account_indexes,
2151 keys: None,
2152 }
2153 }
2154
2155 fn create_spl_token_mint_secondary_index_state() -> (usize, usize, AccountSecondaryIndexes) {
2156 {
2157 let index = AccountsIndex::<bool, bool>::default_for_tests();
2159 let _type_check = SecondaryIndexTypes::RwLock(&index.spl_token_mint_index);
2160 }
2161
2162 (0, PUBKEY_BYTES, spl_token_mint_index_enabled())
2163 }
2164
2165 fn create_spl_token_owner_secondary_index_state() -> (usize, usize, AccountSecondaryIndexes) {
2166 {
2167 let index = AccountsIndex::<bool, bool>::default_for_tests();
2169 let _type_check = SecondaryIndexTypes::RwLock(&index.spl_token_owner_index);
2170 }
2171
2172 (
2173 SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
2174 SPL_TOKEN_ACCOUNT_OWNER_OFFSET + PUBKEY_BYTES,
2175 spl_token_owner_index_enabled(),
2176 )
2177 }
2178
2179 impl<T: IndexValue> Clone for PreAllocatedAccountMapEntry<T> {
2180 fn clone(&self) -> Self {
2181 match self {
2183 PreAllocatedAccountMapEntry::Entry(entry) => {
2184 let (slot, account_info) = entry.slot_list.read().unwrap()[0];
2185 let meta = AccountMapEntryMeta {
2186 dirty: AtomicBool::new(entry.dirty()),
2187 age: AtomicAge::new(entry.age()),
2188 };
2189 PreAllocatedAccountMapEntry::Entry(Arc::new(AccountMapEntryInner::new(
2190 vec![(slot, account_info)],
2191 entry.ref_count(),
2192 meta,
2193 )))
2194 }
2195 PreAllocatedAccountMapEntry::Raw(raw) => PreAllocatedAccountMapEntry::Raw(*raw),
2196 }
2197 }
2198 }
2199
2200 const COLLECT_ALL_UNSORTED_FALSE: bool = false;
2201
2202 #[test]
2203 fn test_get_empty() {
2204 let key = solana_sdk::pubkey::new_rand();
2205 let index = AccountsIndex::<bool, bool>::default_for_tests();
2206 let ancestors = Ancestors::default();
2207 let key = &key;
2208 assert!(!index.contains_with(key, Some(&ancestors), None));
2209 assert!(!index.contains_with(key, None, None));
2210
2211 let mut num = 0;
2212 index.unchecked_scan_accounts(
2213 "",
2214 &ancestors,
2215 |_pubkey, _index| num += 1,
2216 &ScanConfig::default(),
2217 );
2218 assert_eq!(num, 0);
2219 }
2220
2221 #[test]
2222 fn test_remove_older_duplicate_pubkeys() {
2223 let pk1 = Pubkey::new_from_array([0; 32]);
2224 let pk2 = Pubkey::new_from_array([1; 32]);
2225 let slot0 = 0;
2226 let info2 = 55;
2227 let mut items = vec![];
2228 let removed = AccountsIndex::<u64, u64>::remove_older_duplicate_pubkeys(&mut items);
2229 assert!(items.is_empty());
2230 assert!(removed.is_none());
2231 let mut items = vec![(pk1, (slot0, 1u64)), (pk2, (slot0, 2))];
2232 let expected = items.clone();
2233 let removed = AccountsIndex::<u64, u64>::remove_older_duplicate_pubkeys(&mut items);
2234 assert_eq!(items, expected);
2235 assert!(removed.is_none());
2236
2237 for dup in 0..3 {
2238 for other in 0..dup + 2 {
2239 let first_info = 10u64;
2240 let mut items = vec![(pk1, (slot0, first_info))];
2241 let mut expected_dups = items.clone();
2242 for i in 0..dup {
2243 let this_dup = (pk1, (slot0, i + 10u64 + 1));
2244 if i < dup.saturating_sub(1) {
2245 expected_dups.push(this_dup);
2246 }
2247 items.push(this_dup);
2248 }
2249 let mut expected = vec![*items.last().unwrap()];
2250 let other_item = (pk2, (slot0, info2));
2251 if other == dup + 1 {
2252 } else if other == dup {
2254 expected.push(other_item);
2255 items.push(other_item);
2256 } else {
2257 expected.push(other_item);
2258 items.insert(other as usize, other_item);
2259 }
2260 let result = AccountsIndex::<u64, u64>::remove_older_duplicate_pubkeys(&mut items);
2261 assert_eq!(items, expected);
2262 if dup != 0 {
2263 expected_dups.reverse();
2264 assert_eq!(result.unwrap(), expected_dups);
2265 } else {
2266 assert!(result.is_none());
2267 }
2268 }
2269 }
2270 }
2271
2272 #[test]
2273 fn test_secondary_index_include_exclude() {
2274 let pk1 = Pubkey::new_unique();
2275 let pk2 = Pubkey::new_unique();
2276 let mut index = AccountSecondaryIndexes::default();
2277
2278 assert!(!index.contains(&AccountIndex::ProgramId));
2279 index.indexes.insert(AccountIndex::ProgramId);
2280 assert!(index.contains(&AccountIndex::ProgramId));
2281 assert!(index.include_key(&pk1));
2282 assert!(index.include_key(&pk2));
2283
2284 let exclude = false;
2285 index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2286 keys: [pk1].iter().cloned().collect::<HashSet<_>>(),
2287 exclude,
2288 });
2289 assert!(index.include_key(&pk1));
2290 assert!(!index.include_key(&pk2));
2291
2292 let exclude = true;
2293 index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2294 keys: [pk1].iter().cloned().collect::<HashSet<_>>(),
2295 exclude,
2296 });
2297 assert!(!index.include_key(&pk1));
2298 assert!(index.include_key(&pk2));
2299
2300 let exclude = true;
2301 index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2302 keys: [pk1, pk2].iter().cloned().collect::<HashSet<_>>(),
2303 exclude,
2304 });
2305 assert!(!index.include_key(&pk1));
2306 assert!(!index.include_key(&pk2));
2307
2308 let exclude = false;
2309 index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2310 keys: [pk1, pk2].iter().cloned().collect::<HashSet<_>>(),
2311 exclude,
2312 });
2313 assert!(index.include_key(&pk1));
2314 assert!(index.include_key(&pk2));
2315 }
2316
2317 const UPSERT_POPULATE_RECLAIMS: UpsertReclaim = UpsertReclaim::PopulateReclaims;
2318
2319 #[test]
2320 fn test_insert_no_ancestors() {
2321 let key = solana_sdk::pubkey::new_rand();
2322 let index = AccountsIndex::<bool, bool>::default_for_tests();
2323 let mut gc = Vec::new();
2324 index.upsert(
2325 0,
2326 0,
2327 &key,
2328 &AccountSharedData::default(),
2329 &AccountSecondaryIndexes::default(),
2330 true,
2331 &mut gc,
2332 UPSERT_POPULATE_RECLAIMS,
2333 );
2334 assert!(gc.is_empty());
2335
2336 let ancestors = Ancestors::default();
2337 assert!(!index.contains_with(&key, Some(&ancestors), None));
2338 assert!(!index.contains_with(&key, None, None));
2339
2340 let mut num = 0;
2341 index.unchecked_scan_accounts(
2342 "",
2343 &ancestors,
2344 |_pubkey, _index| num += 1,
2345 &ScanConfig::default(),
2346 );
2347 assert_eq!(num, 0);
2348 }
2349
2350 type AccountInfoTest = f64;
2351
2352 impl IndexValue for AccountInfoTest {}
2353 impl DiskIndexValue for AccountInfoTest {}
2354 impl IsCached for AccountInfoTest {
2355 fn is_cached(&self) -> bool {
2356 true
2357 }
2358 }
2359
2360 impl ZeroLamport for AccountInfoTest {
2361 fn is_zero_lamport(&self) -> bool {
2362 true
2363 }
2364 }
2365
2366 #[test]
2367 fn test_insert_duplicates() {
2368 let key = solana_sdk::pubkey::new_rand();
2369 let pubkey = &key;
2370 let slot = 0;
2371 let mut ancestors = Ancestors::default();
2372 ancestors.insert(slot, 0);
2373
2374 let account_info = true;
2375 let index = AccountsIndex::<bool, bool>::default_for_tests();
2376 let account_info2: bool = !account_info;
2377 let items = vec![(*pubkey, account_info), (*pubkey, account_info2)];
2378 index.set_startup(Startup::Startup);
2379 let (_, _, result) =
2380 index.insert_new_if_missing_into_primary_index(slot, items.len(), items.into_iter());
2381 assert_eq!(result.count, 1);
2382 index.set_startup(Startup::Normal);
2383 let index_entry = index.get_cloned(pubkey).unwrap();
2384 let slot_list = index_entry.slot_list.read().unwrap();
2385 assert_eq!(slot_list.len(), 1);
2387 assert_eq!(slot_list[0], (slot, account_info2));
2388 }
2389
2390 #[test]
2391 fn test_insert_new_with_lock_no_ancestors() {
2392 let key = solana_sdk::pubkey::new_rand();
2393 let pubkey = &key;
2394 let slot = 0;
2395
2396 let index = AccountsIndex::<bool, bool>::default_for_tests();
2397 let account_info = true;
2398 let items = vec![(*pubkey, account_info)];
2399 index.set_startup(Startup::Startup);
2400 let expected_len = items.len();
2401 let (_, _, result) =
2402 index.insert_new_if_missing_into_primary_index(slot, items.len(), items.into_iter());
2403 assert_eq!(result.count, expected_len);
2404 index.set_startup(Startup::Normal);
2405
2406 let mut ancestors = Ancestors::default();
2407 assert!(!index.contains_with(pubkey, Some(&ancestors), None));
2408 assert!(!index.contains_with(pubkey, None, None));
2409
2410 let mut num = 0;
2411 index.unchecked_scan_accounts(
2412 "",
2413 &ancestors,
2414 |_pubkey, _index| num += 1,
2415 &ScanConfig::default(),
2416 );
2417 assert_eq!(num, 0);
2418 ancestors.insert(slot, 0);
2419 assert!(index.contains_with(pubkey, Some(&ancestors), None));
2420 assert_eq!(index.ref_count_from_storage(pubkey), 1);
2421 index.unchecked_scan_accounts(
2422 "",
2423 &ancestors,
2424 |_pubkey, _index| num += 1,
2425 &ScanConfig::default(),
2426 );
2427 assert_eq!(num, 1);
2428
2429 let index = AccountsIndex::<bool, bool>::default_for_tests();
2431 let account_info = false;
2432 let items = vec![(*pubkey, account_info)];
2433 index.set_startup(Startup::Startup);
2434 let expected_len = items.len();
2435 let (_, _, result) =
2436 index.insert_new_if_missing_into_primary_index(slot, items.len(), items.into_iter());
2437 assert_eq!(result.count, expected_len);
2438 index.set_startup(Startup::Normal);
2439
2440 let mut ancestors = Ancestors::default();
2441 assert!(!index.contains_with(pubkey, Some(&ancestors), None));
2442 assert!(!index.contains_with(pubkey, None, None));
2443
2444 let mut num = 0;
2445 index.unchecked_scan_accounts(
2446 "",
2447 &ancestors,
2448 |_pubkey, _index| num += 1,
2449 &ScanConfig::default(),
2450 );
2451 assert_eq!(num, 0);
2452 ancestors.insert(slot, 0);
2453 assert!(index.contains_with(pubkey, Some(&ancestors), None));
2454 assert_eq!(index.ref_count_from_storage(pubkey), 1);
2455 index.unchecked_scan_accounts(
2456 "",
2457 &ancestors,
2458 |_pubkey, _index| num += 1,
2459 &ScanConfig::default(),
2460 );
2461 assert_eq!(num, 1);
2462 }
2463
2464 fn get_pre_allocated<T: IndexValue>(
2465 slot: Slot,
2466 account_info: T,
2467 storage: &Arc<BucketMapHolder<T, T>>,
2468 store_raw: bool,
2469 to_raw_first: bool,
2470 ) -> PreAllocatedAccountMapEntry<T> {
2471 let entry = PreAllocatedAccountMapEntry::new(slot, account_info, storage, store_raw);
2472
2473 if to_raw_first {
2474 let (slot2, account_info2) = entry.into();
2476 PreAllocatedAccountMapEntry::new(slot2, account_info2, storage, store_raw)
2478 } else {
2479 entry
2480 }
2481 }
2482
2483 #[test]
2484 fn test_new_entry() {
2485 for store_raw in [false, true] {
2486 for to_raw_first in [false, true] {
2487 let slot = 0;
2488 let account_info = AccountInfoTest::default();
2490 let index = AccountsIndex::default_for_tests();
2491
2492 let new_entry = get_pre_allocated(
2493 slot,
2494 account_info,
2495 &index.storage.storage,
2496 store_raw,
2497 to_raw_first,
2498 )
2499 .into_account_map_entry(&index.storage.storage);
2500 assert_eq!(new_entry.ref_count(), 0);
2501 assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
2502 assert_eq!(
2503 new_entry.slot_list.read().unwrap().to_vec(),
2504 vec![(slot, account_info)]
2505 );
2506
2507 let account_info = true;
2509 let index = AccountsIndex::default_for_tests();
2510
2511 let new_entry = get_pre_allocated(
2512 slot,
2513 account_info,
2514 &index.storage.storage,
2515 store_raw,
2516 to_raw_first,
2517 )
2518 .into_account_map_entry(&index.storage.storage);
2519 assert_eq!(new_entry.ref_count(), 1);
2520 assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
2521 assert_eq!(
2522 new_entry.slot_list.read().unwrap().to_vec(),
2523 vec![(slot, account_info)]
2524 );
2525 }
2526 }
2527 }
2528
2529 #[test]
2530 fn test_batch_insert() {
2531 let slot0 = 0;
2532 let key0 = solana_sdk::pubkey::new_rand();
2533 let key1 = solana_sdk::pubkey::new_rand();
2534
2535 let index = AccountsIndex::<bool, bool>::default_for_tests();
2536 let account_infos = [true, false];
2537
2538 index.set_startup(Startup::Startup);
2539 let items = vec![(key0, account_infos[0]), (key1, account_infos[1])];
2540 let expected_len = items.len();
2541 let (_, _, result) =
2542 index.insert_new_if_missing_into_primary_index(slot0, items.len(), items.into_iter());
2543 assert_eq!(result.count, expected_len);
2544 index.set_startup(Startup::Normal);
2545
2546 for (i, key) in [key0, key1].iter().enumerate() {
2547 let entry = index.get_cloned(key).unwrap();
2548 assert_eq!(entry.ref_count.load(Ordering::Relaxed), 1);
2549 assert_eq!(
2550 entry.slot_list.read().unwrap().as_slice(),
2551 &[(slot0, account_infos[i])],
2552 );
2553 }
2554 }
2555
2556 fn test_new_entry_code_paths_helper<T: IndexValue>(
2557 account_infos: [T; 2],
2558 is_cached: bool,
2559 upsert: bool,
2560 use_disk: bool,
2561 ) {
2562 if is_cached && !upsert {
2563 return;
2567 }
2568
2569 let slot0 = 0;
2570 let slot1 = 1;
2571 let key = solana_sdk::pubkey::new_rand();
2572
2573 let mut config = ACCOUNTS_INDEX_CONFIG_FOR_TESTING;
2574 config.index_limit_mb = if use_disk {
2575 IndexLimitMb::Unlimited
2576 } else {
2577 IndexLimitMb::InMemOnly };
2579 let index = AccountsIndex::<T, T>::new(Some(config), Arc::default());
2580 let mut gc = Vec::new();
2581
2582 if upsert {
2583 index.upsert(
2585 slot0,
2586 slot0,
2587 &key,
2588 &AccountSharedData::default(),
2589 &AccountSecondaryIndexes::default(),
2590 account_infos[0],
2591 &mut gc,
2592 UPSERT_POPULATE_RECLAIMS,
2593 );
2594 } else {
2595 let items = vec![(key, account_infos[0])];
2596 index.set_startup(Startup::Startup);
2597 let expected_len = items.len();
2598 let (_, _, result) = index.insert_new_if_missing_into_primary_index(
2599 slot0,
2600 items.len(),
2601 items.into_iter(),
2602 );
2603 assert_eq!(result.count, expected_len);
2604 index.set_startup(Startup::Normal);
2605 }
2606 assert!(gc.is_empty());
2607
2608 {
2610 let entry = index.get_cloned(&key).unwrap();
2611 let slot_list = entry.slot_list.read().unwrap();
2612 assert_eq!(entry.ref_count(), u64::from(!is_cached));
2613 assert_eq!(slot_list.as_slice(), &[(slot0, account_infos[0])]);
2614 let new_entry: AccountMapEntry<_> = PreAllocatedAccountMapEntry::new(
2615 slot0,
2616 account_infos[0],
2617 &index.storage.storage,
2618 false,
2619 )
2620 .into_account_map_entry(&index.storage.storage);
2621 assert_eq!(
2622 slot_list.as_slice(),
2623 new_entry.slot_list.read().unwrap().as_slice(),
2624 );
2625 }
2626
2627 if upsert {
2629 index.upsert(
2630 slot1,
2631 slot1,
2632 &key,
2633 &AccountSharedData::default(),
2634 &AccountSecondaryIndexes::default(),
2635 account_infos[1],
2636 &mut gc,
2637 UPSERT_POPULATE_RECLAIMS,
2638 );
2639 } else {
2640 for _ in 0..5 {
2642 index.set_startup(Startup::Startup);
2643 index.set_startup(Startup::Normal);
2644 }
2645
2646 let items = vec![(key, account_infos[1])];
2647 index.set_startup(Startup::Startup);
2648 let expected_len = items.len();
2649 let (_, _, result) = index.insert_new_if_missing_into_primary_index(
2650 slot1,
2651 items.len(),
2652 items.into_iter(),
2653 );
2654 assert_eq!(result.count, expected_len);
2655 index.set_startup(Startup::Normal);
2656 }
2657 assert!(gc.is_empty());
2658 index.populate_and_retrieve_duplicate_keys_from_startup(|_slot_keys| {});
2659
2660 let entry = index.get_cloned(&key).unwrap();
2661 let slot_list = entry.slot_list.read().unwrap();
2662
2663 assert_eq!(entry.ref_count(), if is_cached { 0 } else { 2 });
2664 assert_eq!(
2665 slot_list.as_slice(),
2666 &[(slot0, account_infos[0]), (slot1, account_infos[1])],
2667 );
2668
2669 let new_entry = PreAllocatedAccountMapEntry::new(
2670 slot1,
2671 account_infos[1],
2672 &index.storage.storage,
2673 false,
2674 );
2675 assert_eq!(slot_list[1], new_entry.into());
2676 }
2677
2678 #[test]
2679 fn test_new_entry_and_update_code_paths() {
2680 for use_disk in [false, true] {
2681 for is_upsert in &[false, true] {
2682 test_new_entry_code_paths_helper([1.0, 2.0], true, *is_upsert, use_disk);
2684
2685 test_new_entry_code_paths_helper([true, false], false, *is_upsert, use_disk);
2687 }
2688 }
2689 }
2690
2691 #[test]
2692 fn test_insert_with_lock_no_ancestors() {
2693 let key = solana_sdk::pubkey::new_rand();
2694 let index = AccountsIndex::<bool, bool>::default_for_tests();
2695 let slot = 0;
2696 let account_info = true;
2697
2698 let new_entry =
2699 PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage, false);
2700 assert_eq!(0, account_maps_stats_len(&index));
2701 assert_eq!((slot, account_info), new_entry.clone().into());
2702
2703 assert_eq!(0, account_maps_stats_len(&index));
2704 let r_account_maps = index.get_bin(&key);
2705 r_account_maps.upsert(
2706 &key,
2707 new_entry,
2708 None,
2709 &mut SlotList::default(),
2710 UPSERT_POPULATE_RECLAIMS,
2711 );
2712 assert_eq!(1, account_maps_stats_len(&index));
2713
2714 let mut ancestors = Ancestors::default();
2715 assert!(!index.contains_with(&key, Some(&ancestors), None));
2716 assert!(!index.contains_with(&key, None, None));
2717
2718 let mut num = 0;
2719 index.unchecked_scan_accounts(
2720 "",
2721 &ancestors,
2722 |_pubkey, _index| num += 1,
2723 &ScanConfig::default(),
2724 );
2725 assert_eq!(num, 0);
2726 ancestors.insert(slot, 0);
2727 assert!(index.contains_with(&key, Some(&ancestors), None));
2728 index.unchecked_scan_accounts(
2729 "",
2730 &ancestors,
2731 |_pubkey, _index| num += 1,
2732 &ScanConfig::default(),
2733 );
2734 assert_eq!(num, 1);
2735 }
2736
2737 #[test]
2738 fn test_insert_wrong_ancestors() {
2739 let key = solana_sdk::pubkey::new_rand();
2740 let index = AccountsIndex::<bool, bool>::default_for_tests();
2741 let mut gc = Vec::new();
2742 index.upsert(
2743 0,
2744 0,
2745 &key,
2746 &AccountSharedData::default(),
2747 &AccountSecondaryIndexes::default(),
2748 true,
2749 &mut gc,
2750 UPSERT_POPULATE_RECLAIMS,
2751 );
2752 assert!(gc.is_empty());
2753
2754 let ancestors = vec![(1, 1)].into_iter().collect();
2755 assert!(!index.contains_with(&key, Some(&ancestors), None));
2756
2757 let mut num = 0;
2758 index.unchecked_scan_accounts(
2759 "",
2760 &ancestors,
2761 |_pubkey, _index| num += 1,
2762 &ScanConfig::default(),
2763 );
2764 assert_eq!(num, 0);
2765 }
2766 #[test]
2767 fn test_insert_ignore_reclaims() {
2768 {
2769 let key = solana_sdk::pubkey::new_rand();
2771 let index = AccountsIndex::<u64, u64>::default_for_tests();
2772 let mut reclaims = Vec::new();
2773 let slot = 0;
2774 let value = 1;
2775 assert!(!value.is_cached());
2776 index.upsert(
2777 slot,
2778 slot,
2779 &key,
2780 &AccountSharedData::default(),
2781 &AccountSecondaryIndexes::default(),
2782 value,
2783 &mut reclaims,
2784 UpsertReclaim::PopulateReclaims,
2785 );
2786 assert!(reclaims.is_empty());
2787 index.upsert(
2788 slot,
2789 slot,
2790 &key,
2791 &AccountSharedData::default(),
2792 &AccountSecondaryIndexes::default(),
2793 value,
2794 &mut reclaims,
2795 UpsertReclaim::PopulateReclaims,
2796 );
2797 assert!(!reclaims.is_empty());
2799 reclaims.clear();
2800 index.upsert(
2801 slot,
2802 slot,
2803 &key,
2804 &AccountSharedData::default(),
2805 &AccountSecondaryIndexes::default(),
2806 value,
2807 &mut reclaims,
2808 UpsertReclaim::IgnoreReclaims,
2810 );
2811 assert!(reclaims.is_empty());
2813 }
2814 {
2815 let key = solana_sdk::pubkey::new_rand();
2817 let index = AccountsIndex::<AccountInfoTest, AccountInfoTest>::default_for_tests();
2818 let mut reclaims = Vec::new();
2819 let slot = 0;
2820 let value = 1.0;
2821 assert!(value.is_cached());
2822 index.upsert(
2823 slot,
2824 slot,
2825 &key,
2826 &AccountSharedData::default(),
2827 &AccountSecondaryIndexes::default(),
2828 value,
2829 &mut reclaims,
2830 UpsertReclaim::PopulateReclaims,
2831 );
2832 assert!(reclaims.is_empty());
2833 index.upsert(
2834 slot,
2835 slot,
2836 &key,
2837 &AccountSharedData::default(),
2838 &AccountSecondaryIndexes::default(),
2839 value,
2840 &mut reclaims,
2841 UpsertReclaim::PopulateReclaims,
2842 );
2843 assert!(!reclaims.is_empty());
2845 reclaims.clear();
2846 index.upsert(
2847 slot,
2848 slot,
2849 &key,
2850 &AccountSharedData::default(),
2851 &AccountSecondaryIndexes::default(),
2852 value,
2853 &mut reclaims,
2854 UpsertReclaim::IgnoreReclaims,
2856 );
2857 assert!(reclaims.is_empty());
2859 }
2860 }
2861
2862 #[test]
2863 fn test_insert_with_ancestors() {
2864 let key = solana_sdk::pubkey::new_rand();
2865 let index = AccountsIndex::<bool, bool>::default_for_tests();
2866 let mut gc = Vec::new();
2867 index.upsert(
2868 0,
2869 0,
2870 &key,
2871 &AccountSharedData::default(),
2872 &AccountSecondaryIndexes::default(),
2873 true,
2874 &mut gc,
2875 UPSERT_POPULATE_RECLAIMS,
2876 );
2877 assert!(gc.is_empty());
2878
2879 let ancestors = vec![(0, 0)].into_iter().collect();
2880 index
2881 .get_with_and_then(
2882 &key,
2883 Some(&ancestors),
2884 None,
2885 false,
2886 |(slot, account_info)| {
2887 assert_eq!(slot, 0);
2888 assert!(account_info);
2889 },
2890 )
2891 .unwrap();
2892
2893 let mut num = 0;
2894 let mut found_key = false;
2895 index.unchecked_scan_accounts(
2896 "",
2897 &ancestors,
2898 |pubkey, _index| {
2899 if pubkey == &key {
2900 found_key = true
2901 };
2902 num += 1
2903 },
2904 &ScanConfig::default(),
2905 );
2906 assert_eq!(num, 1);
2907 assert!(found_key);
2908 }
2909
2910 fn setup_accounts_index_keys(num_pubkeys: usize) -> (AccountsIndex<bool, bool>, Vec<Pubkey>) {
2911 let index = AccountsIndex::<bool, bool>::default_for_tests();
2912 let root_slot = 0;
2913
2914 let mut pubkeys: Vec<Pubkey> = std::iter::repeat_with(|| {
2915 let new_pubkey = solana_sdk::pubkey::new_rand();
2916 index.upsert(
2917 root_slot,
2918 root_slot,
2919 &new_pubkey,
2920 &AccountSharedData::default(),
2921 &AccountSecondaryIndexes::default(),
2922 true,
2923 &mut vec![],
2924 UPSERT_POPULATE_RECLAIMS,
2925 );
2926 new_pubkey
2927 })
2928 .take(num_pubkeys.saturating_sub(1))
2929 .collect();
2930
2931 if num_pubkeys != 0 {
2932 pubkeys.push(Pubkey::default());
2933 index.upsert(
2934 root_slot,
2935 root_slot,
2936 &Pubkey::default(),
2937 &AccountSharedData::default(),
2938 &AccountSecondaryIndexes::default(),
2939 true,
2940 &mut vec![],
2941 UPSERT_POPULATE_RECLAIMS,
2942 );
2943 }
2944
2945 index.add_root(root_slot);
2946
2947 (index, pubkeys)
2948 }
2949
2950 fn run_test_range(
2951 index: &AccountsIndex<bool, bool>,
2952 pubkeys: &[Pubkey],
2953 start_bound: Bound<usize>,
2954 end_bound: Bound<usize>,
2955 ) {
2956 let (pubkey_start, index_start) = match start_bound {
2958 Unbounded => (Unbounded, 0),
2959 Included(i) => (Included(pubkeys[i]), i),
2960 Excluded(i) => (Excluded(pubkeys[i]), i + 1),
2961 };
2962
2963 let (pubkey_end, index_end) = match end_bound {
2965 Unbounded => (Unbounded, pubkeys.len()),
2966 Included(i) => (Included(pubkeys[i]), i + 1),
2967 Excluded(i) => (Excluded(pubkeys[i]), i),
2968 };
2969 let pubkey_range = (pubkey_start, pubkey_end);
2970
2971 let ancestors = Ancestors::default();
2972 let mut scanned_keys = HashSet::new();
2973 index.range_scan_accounts(
2974 "",
2975 &ancestors,
2976 pubkey_range,
2977 &ScanConfig::default(),
2978 |pubkey, _index| {
2979 scanned_keys.insert(*pubkey);
2980 },
2981 );
2982
2983 let mut expected_len = 0;
2984 for key in &pubkeys[index_start..index_end] {
2985 expected_len += 1;
2986 assert!(scanned_keys.contains(key));
2987 }
2988
2989 assert_eq!(scanned_keys.len(), expected_len);
2990 }
2991
2992 fn run_test_range_indexes(
2993 index: &AccountsIndex<bool, bool>,
2994 pubkeys: &[Pubkey],
2995 start: Option<usize>,
2996 end: Option<usize>,
2997 ) {
2998 let start_options = start
2999 .map(|i| vec![Included(i), Excluded(i)])
3000 .unwrap_or_else(|| vec![Unbounded]);
3001 let end_options = end
3002 .map(|i| vec![Included(i), Excluded(i)])
3003 .unwrap_or_else(|| vec![Unbounded]);
3004
3005 for start in &start_options {
3006 for end in &end_options {
3007 run_test_range(index, pubkeys, *start, *end);
3008 }
3009 }
3010 }
3011
3012 #[test]
3013 fn test_range_scan_accounts() {
3014 let (index, mut pubkeys) = setup_accounts_index_keys(3 * ITER_BATCH_SIZE);
3015 pubkeys.sort();
3016
3017 run_test_range_indexes(&index, &pubkeys, None, None);
3018
3019 run_test_range_indexes(&index, &pubkeys, Some(ITER_BATCH_SIZE), None);
3020
3021 run_test_range_indexes(&index, &pubkeys, None, Some(2 * ITER_BATCH_SIZE));
3022
3023 run_test_range_indexes(
3024 &index,
3025 &pubkeys,
3026 Some(ITER_BATCH_SIZE),
3027 Some(2 * ITER_BATCH_SIZE),
3028 );
3029
3030 run_test_range_indexes(
3031 &index,
3032 &pubkeys,
3033 Some(ITER_BATCH_SIZE),
3034 Some(2 * ITER_BATCH_SIZE - 1),
3035 );
3036
3037 run_test_range_indexes(
3038 &index,
3039 &pubkeys,
3040 Some(ITER_BATCH_SIZE - 1_usize),
3041 Some(2 * ITER_BATCH_SIZE + 1),
3042 );
3043 }
3044
3045 fn run_test_scan_accounts(num_pubkeys: usize) {
3046 let (index, _) = setup_accounts_index_keys(num_pubkeys);
3047 let ancestors = Ancestors::default();
3048
3049 let mut scanned_keys = HashSet::new();
3050 index.unchecked_scan_accounts(
3051 "",
3052 &ancestors,
3053 |pubkey, _index| {
3054 scanned_keys.insert(*pubkey);
3055 },
3056 &ScanConfig::default(),
3057 );
3058 assert_eq!(scanned_keys.len(), num_pubkeys);
3059 }
3060
3061 #[test]
3062 fn test_scan_accounts() {
3063 run_test_scan_accounts(0);
3064 run_test_scan_accounts(1);
3065 run_test_scan_accounts(ITER_BATCH_SIZE * 10);
3066 run_test_scan_accounts(ITER_BATCH_SIZE * 10 - 1);
3067 run_test_scan_accounts(ITER_BATCH_SIZE * 10 + 1);
3068 }
3069
3070 #[test]
3071 fn test_accounts_iter_finished() {
3072 let (index, _) = setup_accounts_index_keys(0);
3073 let mut iter = index.iter(None::<&Range<Pubkey>>, COLLECT_ALL_UNSORTED_FALSE);
3074 assert!(iter.next().is_none());
3075 let mut gc = vec![];
3076 index.upsert(
3077 0,
3078 0,
3079 &solana_sdk::pubkey::new_rand(),
3080 &AccountSharedData::default(),
3081 &AccountSecondaryIndexes::default(),
3082 true,
3083 &mut gc,
3084 UPSERT_POPULATE_RECLAIMS,
3085 );
3086 assert!(iter.next().is_none());
3087 }
3088
3089 #[test]
3090 fn test_is_alive_root() {
3091 let index = AccountsIndex::<bool, bool>::default_for_tests();
3092 assert!(!index.is_alive_root(0));
3093 index.add_root(0);
3094 assert!(index.is_alive_root(0));
3095 }
3096
3097 #[test]
3098 fn test_insert_with_root() {
3099 let key = solana_sdk::pubkey::new_rand();
3100 let index = AccountsIndex::<bool, bool>::default_for_tests();
3101 let mut gc = Vec::new();
3102 index.upsert(
3103 0,
3104 0,
3105 &key,
3106 &AccountSharedData::default(),
3107 &AccountSecondaryIndexes::default(),
3108 true,
3109 &mut gc,
3110 UPSERT_POPULATE_RECLAIMS,
3111 );
3112 assert!(gc.is_empty());
3113
3114 index.add_root(0);
3115 index
3116 .get_with_and_then(&key, None, None, false, |(slot, account_info)| {
3117 assert_eq!(slot, 0);
3118 assert!(account_info);
3119 })
3120 .unwrap();
3121 }
3122
3123 #[test]
3124 fn test_clean_first() {
3125 let index = AccountsIndex::<bool, bool>::default_for_tests();
3126 index.add_root(0);
3127 index.add_root(1);
3128 index.clean_dead_slot(0);
3129 assert!(index.is_alive_root(1));
3130 assert!(!index.is_alive_root(0));
3131 }
3132
3133 #[test]
3134 fn test_clean_last() {
3135 let index = AccountsIndex::<bool, bool>::default_for_tests();
3137 index.add_root(0);
3138 index.add_root(1);
3139 index.clean_dead_slot(1);
3140 assert!(!index.is_alive_root(1));
3141 assert!(index.is_alive_root(0));
3142 }
3143
3144 #[test]
3145 fn test_clean_and_unclean_slot() {
3146 let index = AccountsIndex::<bool, bool>::default_for_tests();
3147 assert_eq!(0, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3148 index.add_root(0);
3149 index.add_root(1);
3150 index.add_uncleaned_roots([0, 1]);
3151 assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3152
3153 index.reset_uncleaned_roots(None);
3154 assert_eq!(2, index.roots_tracker.read().unwrap().alive_roots.len());
3155 assert_eq!(0, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3156
3157 index.add_root(2);
3158 index.add_root(3);
3159 index.add_uncleaned_roots([2, 3]);
3160 assert_eq!(4, index.roots_tracker.read().unwrap().alive_roots.len());
3161 assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3162
3163 index.clean_dead_slot(1);
3164 assert_eq!(3, index.roots_tracker.read().unwrap().alive_roots.len());
3165 assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3166
3167 index.clean_dead_slot(2);
3168 assert_eq!(2, index.roots_tracker.read().unwrap().alive_roots.len());
3169 assert_eq!(1, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3170 }
3171
3172 #[test]
3173 fn test_update_last_wins() {
3174 let key = solana_sdk::pubkey::new_rand();
3175 let index = AccountsIndex::<bool, bool>::default_for_tests();
3176 let ancestors = vec![(0, 0)].into_iter().collect();
3177 let mut gc = Vec::new();
3178 index.upsert(
3179 0,
3180 0,
3181 &key,
3182 &AccountSharedData::default(),
3183 &AccountSecondaryIndexes::default(),
3184 true,
3185 &mut gc,
3186 UPSERT_POPULATE_RECLAIMS,
3187 );
3188 assert!(gc.is_empty());
3189 index
3190 .get_with_and_then(
3191 &key,
3192 Some(&ancestors),
3193 None,
3194 false,
3195 |(slot, account_info)| {
3196 assert_eq!(slot, 0);
3197 assert!(account_info);
3198 },
3199 )
3200 .unwrap();
3201
3202 let mut gc = Vec::new();
3203 index.upsert(
3204 0,
3205 0,
3206 &key,
3207 &AccountSharedData::default(),
3208 &AccountSecondaryIndexes::default(),
3209 false,
3210 &mut gc,
3211 UPSERT_POPULATE_RECLAIMS,
3212 );
3213 assert_eq!(gc, vec![(0, true)]);
3214 index
3215 .get_with_and_then(
3216 &key,
3217 Some(&ancestors),
3218 None,
3219 false,
3220 |(slot, account_info)| {
3221 assert_eq!(slot, 0);
3222 assert!(!account_info);
3223 },
3224 )
3225 .unwrap();
3226 }
3227
3228 #[test]
3229 fn test_update_new_slot() {
3230 solana_logger::setup();
3231 let key = solana_sdk::pubkey::new_rand();
3232 let index = AccountsIndex::<bool, bool>::default_for_tests();
3233 let ancestors = vec![(0, 0)].into_iter().collect();
3234 let mut gc = Vec::new();
3235 index.upsert(
3236 0,
3237 0,
3238 &key,
3239 &AccountSharedData::default(),
3240 &AccountSecondaryIndexes::default(),
3241 true,
3242 &mut gc,
3243 UPSERT_POPULATE_RECLAIMS,
3244 );
3245 assert!(gc.is_empty());
3246 index.upsert(
3247 1,
3248 1,
3249 &key,
3250 &AccountSharedData::default(),
3251 &AccountSecondaryIndexes::default(),
3252 false,
3253 &mut gc,
3254 UPSERT_POPULATE_RECLAIMS,
3255 );
3256 assert!(gc.is_empty());
3257 index
3258 .get_with_and_then(
3259 &key,
3260 Some(&ancestors),
3261 None,
3262 false,
3263 |(slot, account_info)| {
3264 assert_eq!(slot, 0);
3265 assert!(account_info);
3266 },
3267 )
3268 .unwrap();
3269 let ancestors = vec![(1, 0)].into_iter().collect();
3270 index
3271 .get_with_and_then(
3272 &key,
3273 Some(&ancestors),
3274 None,
3275 false,
3276 |(slot, account_info)| {
3277 assert_eq!(slot, 1);
3278 assert!(!account_info);
3279 },
3280 )
3281 .unwrap();
3282 }
3283
3284 #[test]
3285 fn test_update_gc_purged_slot() {
3286 let key = solana_sdk::pubkey::new_rand();
3287 let index = AccountsIndex::<bool, bool>::default_for_tests();
3288 let mut gc = Vec::new();
3289 index.upsert(
3290 0,
3291 0,
3292 &key,
3293 &AccountSharedData::default(),
3294 &AccountSecondaryIndexes::default(),
3295 true,
3296 &mut gc,
3297 UPSERT_POPULATE_RECLAIMS,
3298 );
3299 assert!(gc.is_empty());
3300 index.upsert(
3301 1,
3302 1,
3303 &key,
3304 &AccountSharedData::default(),
3305 &AccountSecondaryIndexes::default(),
3306 false,
3307 &mut gc,
3308 UPSERT_POPULATE_RECLAIMS,
3309 );
3310 index.upsert(
3311 2,
3312 2,
3313 &key,
3314 &AccountSharedData::default(),
3315 &AccountSecondaryIndexes::default(),
3316 true,
3317 &mut gc,
3318 UPSERT_POPULATE_RECLAIMS,
3319 );
3320 index.upsert(
3321 3,
3322 3,
3323 &key,
3324 &AccountSharedData::default(),
3325 &AccountSecondaryIndexes::default(),
3326 true,
3327 &mut gc,
3328 UPSERT_POPULATE_RECLAIMS,
3329 );
3330 index.add_root(0);
3331 index.add_root(1);
3332 index.add_root(3);
3333 index.upsert(
3334 4,
3335 4,
3336 &key,
3337 &AccountSharedData::default(),
3338 &AccountSecondaryIndexes::default(),
3339 true,
3340 &mut gc,
3341 UPSERT_POPULATE_RECLAIMS,
3342 );
3343
3344 assert_eq!(gc, vec![]);
3347 index
3348 .get_with_and_then(&key, None, None, false, |(slot, account_info)| {
3349 assert_eq!(slot, 3);
3350 assert!(account_info);
3351 })
3352 .unwrap();
3353
3354 let mut num = 0;
3355 let mut found_key = false;
3356 index.unchecked_scan_accounts(
3357 "",
3358 &Ancestors::default(),
3359 |pubkey, index| {
3360 if pubkey == &key {
3361 found_key = true;
3362 assert_eq!(index, (&true, 3));
3363 };
3364 num += 1
3365 },
3366 &ScanConfig::default(),
3367 );
3368 assert_eq!(num, 1);
3369 assert!(found_key);
3370 }
3371
3372 fn account_maps_stats_len<T: IndexValue>(index: &AccountsIndex<T, T>) -> usize {
3373 index.storage.storage.stats.total_count()
3374 }
3375
3376 #[test]
3377 fn test_purge() {
3378 let key = solana_sdk::pubkey::new_rand();
3379 let index = AccountsIndex::<u64, u64>::default_for_tests();
3380 let mut gc = Vec::new();
3381 assert_eq!(0, account_maps_stats_len(&index));
3382 index.upsert(
3383 1,
3384 1,
3385 &key,
3386 &AccountSharedData::default(),
3387 &AccountSecondaryIndexes::default(),
3388 12,
3389 &mut gc,
3390 UPSERT_POPULATE_RECLAIMS,
3391 );
3392 assert_eq!(1, account_maps_stats_len(&index));
3393
3394 index.upsert(
3395 1,
3396 1,
3397 &key,
3398 &AccountSharedData::default(),
3399 &AccountSecondaryIndexes::default(),
3400 10,
3401 &mut gc,
3402 UPSERT_POPULATE_RECLAIMS,
3403 );
3404 assert_eq!(1, account_maps_stats_len(&index));
3405
3406 let purges = index.purge_roots(&key);
3407 assert_eq!(purges, (vec![], false));
3408 index.add_root(1);
3409
3410 let purges = index.purge_roots(&key);
3411 assert_eq!(purges, (vec![(1, 10)], true));
3412
3413 assert_eq!(1, account_maps_stats_len(&index));
3414 index.upsert(
3415 1,
3416 1,
3417 &key,
3418 &AccountSharedData::default(),
3419 &AccountSecondaryIndexes::default(),
3420 9,
3421 &mut gc,
3422 UPSERT_POPULATE_RECLAIMS,
3423 );
3424 assert_eq!(1, account_maps_stats_len(&index));
3425 }
3426
3427 #[test]
3428 fn test_latest_slot() {
3429 let slot_slice = vec![(0, true), (5, true), (3, true), (7, true)];
3430 let index = AccountsIndex::<bool, bool>::default_for_tests();
3431
3432 assert!(index.latest_slot(None, &slot_slice, None).is_none());
3434
3435 index.add_root(5);
3437 assert_eq!(index.latest_slot(None, &slot_slice, None).unwrap(), 1);
3438
3439 assert_eq!(index.latest_slot(None, &slot_slice, Some(5)).unwrap(), 1);
3441
3442 assert!(index.latest_slot(None, &slot_slice, Some(4)).is_none());
3444
3445 let ancestors = vec![(3, 1), (7, 1)].into_iter().collect();
3448 assert_eq!(
3449 index
3450 .latest_slot(Some(&ancestors), &slot_slice, Some(4))
3451 .unwrap(),
3452 3
3453 );
3454 assert_eq!(
3455 index
3456 .latest_slot(Some(&ancestors), &slot_slice, Some(7))
3457 .unwrap(),
3458 3
3459 );
3460
3461 assert_eq!(
3463 index
3464 .latest_slot(Some(&ancestors), &slot_slice, None)
3465 .unwrap(),
3466 3
3467 );
3468 }
3469
3470 fn make_empty_token_account_data() -> Vec<u8> {
3471 vec![0; solana_inline_spl::token::Account::get_packed_len()]
3472 }
3473
3474 fn run_test_purge_exact_secondary_index<
3475 SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3476 >(
3477 index: &AccountsIndex<bool, bool>,
3478 secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3479 key_start: usize,
3480 key_end: usize,
3481 secondary_indexes: &AccountSecondaryIndexes,
3482 ) {
3483 let slots = vec![1, 2, 5, 9];
3485 let index_key = Pubkey::new_unique();
3486 let account_key = Pubkey::new_unique();
3487
3488 let mut account_data = make_empty_token_account_data();
3489 account_data[key_start..key_end].clone_from_slice(&(index_key.to_bytes()));
3490
3491 for slot in &slots {
3493 index.upsert(
3494 *slot,
3495 *slot,
3496 &account_key,
3497 &AccountSharedData::create(
3499 0,
3500 account_data.to_vec(),
3501 solana_inline_spl::token::id(),
3502 false,
3503 0,
3504 ),
3505 secondary_indexes,
3506 true,
3507 &mut vec![],
3508 UPSERT_POPULATE_RECLAIMS,
3509 );
3510 }
3511
3512 assert_eq!(secondary_index.index.get(&index_key).unwrap().len(), 1);
3514
3515 assert_eq!(
3518 secondary_index
3519 .reverse_index
3520 .get(&account_key)
3521 .unwrap()
3522 .value()
3523 .read()
3524 .unwrap()
3525 .len(),
3526 1
3527 );
3528
3529 index.purge_exact(
3530 &account_key,
3531 &slots.into_iter().collect::<HashSet<Slot>>(),
3532 &mut vec![],
3533 );
3534
3535 let _ = index.handle_dead_keys(&[&account_key], secondary_indexes);
3536 assert!(secondary_index.index.is_empty());
3537 assert!(secondary_index.reverse_index.is_empty());
3538 }
3539
3540 #[test]
3541 fn test_purge_exact_spl_token_mint_secondary_index() {
3542 let (key_start, key_end, secondary_indexes) = create_spl_token_mint_secondary_index_state();
3543 let index = AccountsIndex::<bool, bool>::default_for_tests();
3544 run_test_purge_exact_secondary_index(
3545 &index,
3546 &index.spl_token_mint_index,
3547 key_start,
3548 key_end,
3549 &secondary_indexes,
3550 );
3551 }
3552
3553 #[test]
3554 fn test_purge_exact_spl_token_owner_secondary_index() {
3555 let (key_start, key_end, secondary_indexes) =
3556 create_spl_token_owner_secondary_index_state();
3557 let index = AccountsIndex::<bool, bool>::default_for_tests();
3558 run_test_purge_exact_secondary_index(
3559 &index,
3560 &index.spl_token_owner_index,
3561 key_start,
3562 key_end,
3563 &secondary_indexes,
3564 );
3565 }
3566
3567 #[test]
3568 fn test_purge_older_root_entries() {
3569 let index = AccountsIndex::<bool, bool>::default_for_tests();
3571 let mut slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3572 let mut reclaims = vec![];
3573 index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3574 assert!(reclaims.is_empty());
3575 assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3576
3577 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3579 index.add_root(1);
3580 index.add_root(5);
3582 reclaims = vec![];
3583 index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3584 assert_eq!(reclaims, vec![(1, true), (2, true)]);
3585 assert_eq!(slot_list, vec![(5, true), (9, true)]);
3586
3587 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3589 index.add_root(6);
3590 reclaims = vec![];
3591 index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3592 assert_eq!(reclaims, vec![(1, true), (2, true)]);
3593 assert_eq!(slot_list, vec![(5, true), (9, true)]);
3594
3595 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3598 reclaims = vec![];
3599 index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(6));
3600 assert_eq!(reclaims, vec![(1, true), (2, true)]);
3601 assert_eq!(slot_list, vec![(5, true), (9, true)]);
3602
3603 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3605 reclaims = vec![];
3606 index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(5));
3607 assert_eq!(reclaims, vec![(1, true), (2, true)]);
3608 assert_eq!(slot_list, vec![(5, true), (9, true)]);
3609
3610 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3613 reclaims = vec![];
3614 index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(2));
3615 assert!(reclaims.is_empty());
3616 assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3617
3618 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3621 reclaims = vec![];
3622 index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(1));
3623 assert!(reclaims.is_empty());
3624 assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3625
3626 slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3629 reclaims = vec![];
3630 index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(7));
3631 assert_eq!(reclaims, vec![(1, true), (2, true)]);
3632 assert_eq!(slot_list, vec![(5, true), (9, true)]);
3633 }
3634
3635 fn check_secondary_index_mapping_correct<SecondaryIndexEntryType>(
3636 secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3637 secondary_index_keys: &[Pubkey],
3638 account_key: &Pubkey,
3639 ) where
3640 SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3641 {
3642 for secondary_index_key in secondary_index_keys {
3645 assert_eq!(secondary_index.index.len(), secondary_index_keys.len());
3646 let account_key_map = secondary_index.get(secondary_index_key);
3647 assert_eq!(account_key_map.len(), 1);
3648 assert_eq!(account_key_map, vec![*account_key]);
3649 }
3650 let secondary_index_key_map = secondary_index.reverse_index.get(account_key).unwrap();
3652 assert_eq!(
3653 &*secondary_index_key_map.value().read().unwrap(),
3654 secondary_index_keys
3655 );
3656 }
3657
3658 fn run_test_spl_token_secondary_indexes<
3659 SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3660 >(
3661 token_id: &Pubkey,
3662 index: &AccountsIndex<bool, bool>,
3663 secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3664 key_start: usize,
3665 key_end: usize,
3666 secondary_indexes: &AccountSecondaryIndexes,
3667 ) {
3668 let mut secondary_indexes = secondary_indexes.clone();
3669 let account_key = Pubkey::new_unique();
3670 let index_key = Pubkey::new_unique();
3671 let mut account_data = make_empty_token_account_data();
3672 account_data[key_start..key_end].clone_from_slice(&(index_key.to_bytes()));
3673
3674 index.upsert(
3676 0,
3677 0,
3678 &account_key,
3679 &AccountSharedData::create(0, account_data.to_vec(), Pubkey::default(), false, 0),
3680 &secondary_indexes,
3681 true,
3682 &mut vec![],
3683 UPSERT_POPULATE_RECLAIMS,
3684 );
3685 assert!(secondary_index.index.is_empty());
3686 assert!(secondary_index.reverse_index.is_empty());
3687
3688 index.upsert(
3690 0,
3691 0,
3692 &account_key,
3693 &AccountSharedData::create(0, account_data[1..].to_vec(), *token_id, false, 0),
3694 &secondary_indexes,
3695 true,
3696 &mut vec![],
3697 UPSERT_POPULATE_RECLAIMS,
3698 );
3699 assert!(secondary_index.index.is_empty());
3700 assert!(secondary_index.reverse_index.is_empty());
3701
3702 secondary_indexes.keys = None;
3703
3704 for _ in 0..2 {
3706 index.update_secondary_indexes(
3707 &account_key,
3708 &AccountSharedData::create(0, account_data.to_vec(), *token_id, false, 0),
3709 &secondary_indexes,
3710 );
3711 check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3712 }
3713
3714 assert!(!secondary_index.index.is_empty());
3716 assert!(!secondary_index.reverse_index.is_empty());
3717
3718 secondary_indexes.keys = Some(AccountSecondaryIndexesIncludeExclude {
3719 keys: [index_key].iter().cloned().collect::<HashSet<_>>(),
3720 exclude: false,
3721 });
3722 secondary_index.index.clear();
3723 secondary_index.reverse_index.clear();
3724 index.update_secondary_indexes(
3725 &account_key,
3726 &AccountSharedData::create(0, account_data.to_vec(), *token_id, false, 0),
3727 &secondary_indexes,
3728 );
3729 assert!(!secondary_index.index.is_empty());
3730 assert!(!secondary_index.reverse_index.is_empty());
3731 check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3732
3733 secondary_indexes.keys = Some(AccountSecondaryIndexesIncludeExclude {
3735 keys: [].iter().cloned().collect::<HashSet<_>>(),
3736 exclude: true,
3737 });
3738 secondary_index.index.clear();
3739 secondary_index.reverse_index.clear();
3740 index.update_secondary_indexes(
3741 &account_key,
3742 &AccountSharedData::create(0, account_data.to_vec(), *token_id, false, 0),
3743 &secondary_indexes,
3744 );
3745 assert!(!secondary_index.index.is_empty());
3746 assert!(!secondary_index.reverse_index.is_empty());
3747 check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3748
3749 secondary_indexes.keys = None;
3750
3751 index.slot_list_mut(&account_key, |slot_list| slot_list.clear());
3752
3753 let _ = index.handle_dead_keys(&[&account_key], &secondary_indexes);
3755 assert!(secondary_index.index.is_empty());
3756 assert!(secondary_index.reverse_index.is_empty());
3757 }
3758
3759 #[test]
3760 fn test_spl_token_mint_secondary_index() {
3761 let (key_start, key_end, secondary_indexes) = create_spl_token_mint_secondary_index_state();
3762 let index = AccountsIndex::<bool, bool>::default_for_tests();
3763 for token_id in SPL_TOKENS {
3764 run_test_spl_token_secondary_indexes(
3765 token_id,
3766 &index,
3767 &index.spl_token_mint_index,
3768 key_start,
3769 key_end,
3770 &secondary_indexes,
3771 );
3772 }
3773 }
3774
3775 #[test]
3776 fn test_spl_token_owner_secondary_index() {
3777 let (key_start, key_end, secondary_indexes) =
3778 create_spl_token_owner_secondary_index_state();
3779 let index = AccountsIndex::<bool, bool>::default_for_tests();
3780 for token_id in SPL_TOKENS {
3781 run_test_spl_token_secondary_indexes(
3782 token_id,
3783 &index,
3784 &index.spl_token_owner_index,
3785 key_start,
3786 key_end,
3787 &secondary_indexes,
3788 );
3789 }
3790 }
3791
3792 fn run_test_secondary_indexes_same_slot_and_forks<
3793 SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3794 >(
3795 token_id: &Pubkey,
3796 index: &AccountsIndex<bool, bool>,
3797 secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3798 index_key_start: usize,
3799 index_key_end: usize,
3800 secondary_indexes: &AccountSecondaryIndexes,
3801 ) {
3802 let account_key = Pubkey::new_unique();
3803 let secondary_key1 = Pubkey::new_unique();
3804 let secondary_key2 = Pubkey::new_unique();
3805 let slot = 1;
3806 let mut account_data1 = make_empty_token_account_data();
3807 account_data1[index_key_start..index_key_end]
3808 .clone_from_slice(&(secondary_key1.to_bytes()));
3809 let mut account_data2 = make_empty_token_account_data();
3810 account_data2[index_key_start..index_key_end]
3811 .clone_from_slice(&(secondary_key2.to_bytes()));
3812
3813 index.upsert(
3815 slot,
3816 slot,
3817 &account_key,
3818 &AccountSharedData::create(0, account_data1.to_vec(), *token_id, false, 0),
3819 secondary_indexes,
3820 true,
3821 &mut vec![],
3822 UPSERT_POPULATE_RECLAIMS,
3823 );
3824
3825 index.upsert(
3827 slot,
3828 slot,
3829 &account_key,
3830 &AccountSharedData::create(0, account_data2.to_vec(), *token_id, false, 0),
3831 secondary_indexes,
3832 true,
3833 &mut vec![],
3834 UPSERT_POPULATE_RECLAIMS,
3835 );
3836
3837 check_secondary_index_mapping_correct(
3839 secondary_index,
3840 &[secondary_key1, secondary_key2],
3841 &account_key,
3842 );
3843
3844 let later_slot = slot + 1;
3846 index.upsert(
3847 later_slot,
3848 later_slot,
3849 &account_key,
3850 &AccountSharedData::create(0, account_data1.to_vec(), *token_id, false, 0),
3851 secondary_indexes,
3852 true,
3853 &mut vec![],
3854 UPSERT_POPULATE_RECLAIMS,
3855 );
3856 assert_eq!(secondary_index.get(&secondary_key1), vec![account_key]);
3857
3858 index.add_root(later_slot);
3862 index.slot_list_mut(&account_key, |slot_list| {
3863 index.purge_older_root_entries(slot_list, &mut vec![], None)
3864 });
3865
3866 check_secondary_index_mapping_correct(
3867 secondary_index,
3868 &[secondary_key1, secondary_key2],
3869 &account_key,
3870 );
3871
3872 let mut reclaims = vec![];
3875 index.purge_exact(&account_key, &later_slot, &mut reclaims);
3876 let _ = index.handle_dead_keys(&[&account_key], secondary_indexes);
3877 assert!(secondary_index.index.is_empty());
3878 assert!(secondary_index.reverse_index.is_empty());
3879 }
3880
3881 #[test]
3882 fn test_spl_token_mint_secondary_index_same_slot_and_forks() {
3883 let (key_start, key_end, account_index) = create_spl_token_mint_secondary_index_state();
3884 let index = AccountsIndex::<bool, bool>::default_for_tests();
3885 for token_id in SPL_TOKENS {
3886 run_test_secondary_indexes_same_slot_and_forks(
3887 token_id,
3888 &index,
3889 &index.spl_token_mint_index,
3890 key_start,
3891 key_end,
3892 &account_index,
3893 );
3894 }
3895 }
3896
3897 #[test]
3898 fn test_rwlock_secondary_index_same_slot_and_forks() {
3899 let (key_start, key_end, account_index) = create_spl_token_owner_secondary_index_state();
3900 let index = AccountsIndex::<bool, bool>::default_for_tests();
3901 for token_id in SPL_TOKENS {
3902 run_test_secondary_indexes_same_slot_and_forks(
3903 token_id,
3904 &index,
3905 &index.spl_token_owner_index,
3906 key_start,
3907 key_end,
3908 &account_index,
3909 );
3910 }
3911 }
3912
3913 impl IndexValue for bool {}
3914 impl IndexValue for u64 {}
3915 impl DiskIndexValue for bool {}
3916 impl DiskIndexValue for u64 {}
3917 impl IsCached for bool {
3918 fn is_cached(&self) -> bool {
3919 false
3920 }
3921 }
3922 impl IsCached for u64 {
3923 fn is_cached(&self) -> bool {
3924 false
3925 }
3926 }
3927 impl ZeroLamport for bool {
3928 fn is_zero_lamport(&self) -> bool {
3929 false
3930 }
3931 }
3932
3933 impl ZeroLamport for u64 {
3934 fn is_zero_lamport(&self) -> bool {
3935 false
3936 }
3937 }
3938
3939 #[test]
3940 fn test_bin_start_and_range() {
3941 let index = AccountsIndex::<bool, bool>::default_for_tests();
3942 let iter = AccountsIndexIterator::new(
3943 &index,
3944 None::<&RangeInclusive<Pubkey>>,
3945 COLLECT_ALL_UNSORTED_FALSE,
3946 );
3947 assert_eq!((0, usize::MAX), iter.bin_start_and_range());
3948
3949 let key_0 = Pubkey::from([0; 32]);
3950 let key_ff = Pubkey::from([0xff; 32]);
3951
3952 let iter = AccountsIndexIterator::new(
3953 &index,
3954 Some(&RangeInclusive::new(key_0, key_ff)),
3955 COLLECT_ALL_UNSORTED_FALSE,
3956 );
3957 let bins = index.bins();
3958 assert_eq!((0, bins), iter.bin_start_and_range());
3959 let iter = AccountsIndexIterator::new(
3960 &index,
3961 Some(&RangeInclusive::new(key_ff, key_0)),
3962 COLLECT_ALL_UNSORTED_FALSE,
3963 );
3964 assert_eq!((bins - 1, 0), iter.bin_start_and_range());
3965 let iter = AccountsIndexIterator::new(
3966 &index,
3967 Some(&(Included(key_0), Unbounded)),
3968 COLLECT_ALL_UNSORTED_FALSE,
3969 );
3970 assert_eq!((0, usize::MAX), iter.bin_start_and_range());
3971 let iter = AccountsIndexIterator::new(
3972 &index,
3973 Some(&(Included(key_ff), Unbounded)),
3974 COLLECT_ALL_UNSORTED_FALSE,
3975 );
3976 assert_eq!((bins - 1, usize::MAX), iter.bin_start_and_range());
3977
3978 assert_eq!((0..2).skip(1).take(usize::MAX).collect::<Vec<_>>(), vec![1]);
3979 }
3980
3981 #[test]
3982 fn test_get_newest_root_in_slot_list() {
3983 let index = AccountsIndex::<bool, bool>::default_for_tests();
3984 let return_0 = 0;
3985 let slot1 = 1;
3986 let slot2 = 2;
3987 let slot99 = 99;
3988
3989 {
3991 let roots_tracker = &index.roots_tracker.read().unwrap();
3992 let slot_list = Vec::<(Slot, bool)>::default();
3993 assert_eq!(
3994 return_0,
3995 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
3996 &roots_tracker.alive_roots,
3997 &slot_list,
3998 Some(slot1),
3999 )
4000 );
4001 assert_eq!(
4002 return_0,
4003 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4004 &roots_tracker.alive_roots,
4005 &slot_list,
4006 Some(slot2),
4007 )
4008 );
4009 assert_eq!(
4010 return_0,
4011 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4012 &roots_tracker.alive_roots,
4013 &slot_list,
4014 Some(slot99),
4015 )
4016 );
4017 }
4018
4019 index.add_root(slot2);
4020
4021 {
4022 let roots_tracker = &index.roots_tracker.read().unwrap();
4023 let slot_list = vec![(slot2, true)];
4024 assert_eq!(
4025 slot2,
4026 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4027 &roots_tracker.alive_roots,
4028 &slot_list,
4029 Some(slot2),
4030 )
4031 );
4032 assert_eq!(
4034 return_0,
4035 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4036 &roots_tracker.alive_roots,
4037 &slot_list,
4038 Some(slot1),
4039 )
4040 );
4041 assert_eq!(
4042 slot2,
4043 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4044 &roots_tracker.alive_roots,
4045 &slot_list,
4046 Some(slot99),
4047 )
4048 );
4049 }
4050 }
4051
4052 impl<T: IndexValue> AccountsIndex<T, T> {
4053 fn upsert_simple_test(&self, key: &Pubkey, slot: Slot, value: T) {
4054 let mut gc = Vec::new();
4055 self.upsert(
4056 slot,
4057 slot,
4058 key,
4059 &AccountSharedData::default(),
4060 &AccountSecondaryIndexes::default(),
4061 value,
4062 &mut gc,
4063 UPSERT_POPULATE_RECLAIMS,
4064 );
4065 assert!(gc.is_empty());
4066 }
4067
4068 pub fn clear_uncleaned_roots(&self, max_clean_root: Option<Slot>) -> HashSet<Slot> {
4069 let mut cleaned_roots = HashSet::new();
4070 let mut w_roots_tracker = self.roots_tracker.write().unwrap();
4071 w_roots_tracker.uncleaned_roots.retain(|root| {
4072 let is_cleaned = max_clean_root
4073 .map(|max_clean_root| *root <= max_clean_root)
4074 .unwrap_or(true);
4075 if is_cleaned {
4076 cleaned_roots.insert(*root);
4077 }
4078 !is_cleaned
4080 });
4081 cleaned_roots
4082 }
4083
4084 pub(crate) fn is_uncleaned_root(&self, slot: Slot) -> bool {
4085 self.roots_tracker
4086 .read()
4087 .unwrap()
4088 .uncleaned_roots
4089 .contains(&slot)
4090 }
4091
4092 pub fn clear_roots(&self) {
4093 self.roots_tracker.write().unwrap().alive_roots.clear()
4094 }
4095 }
4096
4097 #[test]
4098 fn test_unref() {
4099 let value = true;
4100 let key = solana_sdk::pubkey::new_rand();
4101 let index = AccountsIndex::<bool, bool>::default_for_tests();
4102 let slot1 = 1;
4103
4104 index.upsert_simple_test(&key, slot1, value);
4105
4106 let map = index.get_bin(&key);
4107 for expected in [false, true] {
4108 assert!(map.get_internal_inner(&key, |entry| {
4109 assert_eq!(u64::from(!expected), entry.unwrap().ref_count());
4111 assert_eq!(u64::from(!expected), entry.unwrap().unref());
4114 assert_eq!(
4116 if expected {
4117 (0 as RefCount).wrapping_sub(1)
4118 } else {
4119 0
4120 },
4121 entry.unwrap().ref_count()
4122 );
4123 (false, true)
4124 }));
4125 }
4126 }
4127
4128 #[test]
4129 fn test_clean_rooted_entries_return() {
4130 solana_logger::setup();
4131 let value = true;
4132 let key = solana_sdk::pubkey::new_rand();
4133 let key_unknown = solana_sdk::pubkey::new_rand();
4134 let index = AccountsIndex::<bool, bool>::default_for_tests();
4135 let slot1 = 1;
4136
4137 let mut gc = Vec::new();
4138 assert!(index.clean_rooted_entries(&key_unknown, &mut gc, None));
4141
4142 index.upsert_simple_test(&key, slot1, value);
4143
4144 let slot2 = 2;
4145 assert!(!index.clean_rooted_entries(&key, &mut gc, None));
4147 assert!(!index.clean_rooted_entries(&key, &mut gc, Some(slot1)));
4149 {
4152 let mut gc = Vec::new();
4153 assert!(index.clean_rooted_entries(&key, &mut gc, Some(slot2)));
4154 assert_eq!(gc, vec![(slot1, value)]);
4155 }
4156
4157 index.upsert_simple_test(&key, slot1, value);
4159
4160 index.add_root(slot1);
4161 assert!(!index.clean_rooted_entries(&key, &mut gc, Some(slot2)));
4162 index.upsert_simple_test(&key, slot2, value);
4163
4164 {
4165 let account_map_entry = index.get_cloned(&key).unwrap();
4166 let slot_list = account_map_entry.slot_list.read().unwrap();
4167 assert_eq!(2, slot_list.len());
4168 assert_eq!(&[(slot1, value), (slot2, value)], slot_list.as_slice());
4169 }
4170 assert!(!index.clean_rooted_entries(&key, &mut gc, Some(slot2)));
4171 assert_eq!(
4172 2,
4173 index
4174 .get_cloned(&key)
4175 .unwrap()
4176 .slot_list
4177 .read()
4178 .unwrap()
4179 .len()
4180 );
4181 assert!(gc.is_empty());
4182 {
4183 {
4184 let roots_tracker = &index.roots_tracker.read().unwrap();
4185 let slot_list = vec![(slot2, value)];
4186 assert_eq!(
4187 0,
4188 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4189 &roots_tracker.alive_roots,
4190 &slot_list,
4191 None,
4192 )
4193 );
4194 }
4195 index.add_root(slot2);
4196 {
4197 let roots_tracker = &index.roots_tracker.read().unwrap();
4198 let slot_list = vec![(slot2, value)];
4199 assert_eq!(
4200 slot2,
4201 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4202 &roots_tracker.alive_roots,
4203 &slot_list,
4204 None,
4205 )
4206 );
4207 assert_eq!(
4208 0,
4209 AccountsIndex::<bool, bool>::get_newest_root_in_slot_list(
4210 &roots_tracker.alive_roots,
4211 &slot_list,
4212 Some(0),
4213 )
4214 );
4215 }
4216 }
4217
4218 assert!(gc.is_empty());
4219 assert!(!index.clean_rooted_entries(&key, &mut gc, Some(slot2)));
4220 assert_eq!(gc, vec![(slot1, value)]);
4221 gc.clear();
4222 index.clean_dead_slot(slot2);
4223 let slot3 = 3;
4224 assert!(index.clean_rooted_entries(&key, &mut gc, Some(slot3)));
4225 assert_eq!(gc, vec![(slot2, value)]);
4226 }
4227
4228 #[test]
4229 fn test_handle_dead_keys_return() {
4230 let key = solana_sdk::pubkey::new_rand();
4231 let index = AccountsIndex::<bool, bool>::default_for_tests();
4232
4233 assert_eq!(
4234 index.handle_dead_keys(&[&key], &AccountSecondaryIndexes::default()),
4235 vec![key].into_iter().collect::<HashSet<_>>()
4236 );
4237 }
4238
4239 #[test]
4240 fn test_start_end_bin() {
4241 let index = AccountsIndex::<bool, bool>::default_for_tests();
4242 assert_eq!(index.bins(), BINS_FOR_TESTING);
4243 let iter = AccountsIndexIterator::new(
4244 &index,
4245 None::<&RangeInclusive<Pubkey>>,
4246 COLLECT_ALL_UNSORTED_FALSE,
4247 );
4248 assert_eq!(iter.start_bin(), 0); assert_eq!(iter.end_bin_inclusive(), usize::MAX); let key = Pubkey::from([0; 32]);
4252 let iter = AccountsIndexIterator::new(
4253 &index,
4254 Some(&RangeInclusive::new(key, key)),
4255 COLLECT_ALL_UNSORTED_FALSE,
4256 );
4257 assert_eq!(iter.start_bin(), 0); assert_eq!(iter.end_bin_inclusive(), 0); let iter = AccountsIndexIterator::new(
4260 &index,
4261 Some(&(Included(key), Excluded(key))),
4262 COLLECT_ALL_UNSORTED_FALSE,
4263 );
4264 assert_eq!(iter.start_bin(), 0); assert_eq!(iter.end_bin_inclusive(), 0); let iter = AccountsIndexIterator::new(
4267 &index,
4268 Some(&(Excluded(key), Excluded(key))),
4269 COLLECT_ALL_UNSORTED_FALSE,
4270 );
4271 assert_eq!(iter.start_bin(), 0); assert_eq!(iter.end_bin_inclusive(), 0); let key = Pubkey::from([0xff; 32]);
4275 let iter = AccountsIndexIterator::new(
4276 &index,
4277 Some(&RangeInclusive::new(key, key)),
4278 COLLECT_ALL_UNSORTED_FALSE,
4279 );
4280 let bins = index.bins();
4281 assert_eq!(iter.start_bin(), bins - 1); assert_eq!(iter.end_bin_inclusive(), bins - 1);
4283 let iter = AccountsIndexIterator::new(
4284 &index,
4285 Some(&(Included(key), Excluded(key))),
4286 COLLECT_ALL_UNSORTED_FALSE,
4287 );
4288 assert_eq!(iter.start_bin(), bins - 1); assert_eq!(iter.end_bin_inclusive(), bins - 1);
4290 let iter = AccountsIndexIterator::new(
4291 &index,
4292 Some(&(Excluded(key), Excluded(key))),
4293 COLLECT_ALL_UNSORTED_FALSE,
4294 );
4295 assert_eq!(iter.start_bin(), bins - 1); assert_eq!(iter.end_bin_inclusive(), bins - 1);
4297 }
4298
4299 #[test]
4300 #[should_panic(expected = "bins.is_power_of_two()")]
4301 #[allow(clippy::field_reassign_with_default)]
4302 fn test_illegal_bins() {
4303 let mut config = AccountsIndexConfig::default();
4304 config.bins = Some(3);
4305 AccountsIndex::<bool, bool>::new(Some(config), Arc::default());
4306 }
4307
4308 #[test]
4309 fn test_scan_config() {
4310 for collect_all_unsorted in [false, true] {
4311 let config = ScanConfig::new(collect_all_unsorted);
4312 assert_eq!(config.collect_all_unsorted, collect_all_unsorted);
4313 assert!(config.abort.is_none()); assert!(!config.is_aborted());
4315 config.abort(); assert!(!config.is_aborted());
4317 }
4318
4319 let config = ScanConfig::new(false);
4320 assert!(!config.collect_all_unsorted);
4321 assert!(config.abort.is_none());
4322
4323 let config = ScanConfig::default();
4324 assert!(config.collect_all_unsorted);
4325 assert!(config.abort.is_none());
4326
4327 let config = config.recreate_with_abort();
4328 assert!(config.abort.is_some());
4329 assert!(!config.is_aborted());
4330 config.abort();
4331 assert!(config.is_aborted());
4332
4333 let config = config.recreate_with_abort();
4334 assert!(config.is_aborted());
4335 }
4336}