gemachain_runtime/
accounts_index.rs

1use crate::{
2    accounts_index_storage::AccountsIndexStorage,
3    ancestors::Ancestors,
4    bucket_map_holder::{Age, BucketMapHolder},
5    contains::Contains,
6    in_mem_accounts_index::InMemAccountsIndex,
7    inline_spl_token_v2_0::{self, SPL_TOKEN_ACCOUNT_MINT_OFFSET, SPL_TOKEN_ACCOUNT_OWNER_OFFSET},
8    pubkey_bins::PubkeyBinCalculator16,
9    secondary_index::*,
10};
11use bv::BitVec;
12use log::*;
13use ouroboros::self_referencing;
14use rand::thread_rng;
15use rand::Rng;
16use gemachain_measure::measure::Measure;
17use gemachain_sdk::{
18    clock::{BankId, Slot},
19    pubkey::{Pubkey, PUBKEY_BYTES},
20};
21use std::{
22    collections::{btree_map::BTreeMap, HashSet},
23    fmt::Debug,
24    ops::{
25        Bound,
26        Bound::{Excluded, Included, Unbounded},
27        Range, RangeBounds,
28    },
29    path::PathBuf,
30    sync::{
31        atomic::{AtomicBool, AtomicU64, AtomicU8, Ordering},
32        Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard,
33    },
34};
35use thiserror::Error;
36
37pub const ITER_BATCH_SIZE: usize = 1000;
38pub const BINS_DEFAULT: usize = 8192;
39pub const BINS_FOR_TESTING: usize = 2; // we want > 1, but each bin is a few disk files with a disk based index, so fewer is better
40pub const BINS_FOR_BENCHMARKS: usize = 2;
41pub const FLUSH_THREADS_TESTING: usize = 1;
42pub const ACCOUNTS_INDEX_CONFIG_FOR_TESTING: AccountsIndexConfig = AccountsIndexConfig {
43    bins: Some(BINS_FOR_TESTING),
44    flush_threads: Some(FLUSH_THREADS_TESTING),
45    drives: None,
46    index_limit_mb: Some(1),
47    ages_to_stay_in_cache: None,
48};
49pub const ACCOUNTS_INDEX_CONFIG_FOR_BENCHMARKS: AccountsIndexConfig = AccountsIndexConfig {
50    bins: Some(BINS_FOR_BENCHMARKS),
51    flush_threads: Some(FLUSH_THREADS_TESTING),
52    drives: None,
53    index_limit_mb: None,
54    ages_to_stay_in_cache: None,
55};
56pub type ScanResult<T> = Result<T, ScanError>;
57pub type SlotList<T> = Vec<(Slot, T)>;
58pub type SlotSlice<'s, T> = &'s [(Slot, T)];
59pub type RefCount = u64;
60pub type AccountMap<V> = Arc<InMemAccountsIndex<V>>;
61
62pub(crate) type AccountMapEntry<T> = Arc<AccountMapEntryInner<T>>;
63
64pub trait IsCached:
65    'static + Clone + Debug + PartialEq + ZeroCarat + Copy + Default + Sync + Send
66{
67    fn is_cached(&self) -> bool;
68}
69
70pub trait IndexValue:
71    'static + IsCached + Clone + Debug + PartialEq + ZeroCarat + Copy + Default + Sync + Send
72{
73}
74
75#[derive(Error, Debug, PartialEq)]
76pub enum ScanError {
77    #[error("Node detected it replayed bad version of slot {slot:?} with id {bank_id:?}, thus the scan on said slot was aborted")]
78    SlotRemoved { slot: Slot, bank_id: BankId },
79}
80
81enum ScanTypes<R: RangeBounds<Pubkey>> {
82    Unindexed(Option<R>),
83    Indexed(IndexKey),
84}
85
86#[derive(Debug, Clone, Copy)]
87pub enum IndexKey {
88    ProgramId(Pubkey),
89    SplTokenMint(Pubkey),
90    SplTokenOwner(Pubkey),
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Hash)]
94pub enum AccountIndex {
95    ProgramId,
96    SplTokenMint,
97    SplTokenOwner,
98}
99
100#[derive(Debug, PartialEq, Eq, Clone)]
101pub struct AccountSecondaryIndexesIncludeExclude {
102    pub exclude: bool,
103    pub keys: HashSet<Pubkey>,
104}
105
106#[derive(Debug, Default, Clone)]
107pub struct AccountsIndexConfig {
108    pub bins: Option<usize>,
109    pub flush_threads: Option<usize>,
110    pub drives: Option<Vec<PathBuf>>,
111    pub index_limit_mb: Option<usize>,
112    pub ages_to_stay_in_cache: Option<Age>,
113}
114
115#[derive(Debug, Default, Clone)]
116pub struct AccountSecondaryIndexes {
117    pub keys: Option<AccountSecondaryIndexesIncludeExclude>,
118    pub indexes: HashSet<AccountIndex>,
119}
120
121impl AccountSecondaryIndexes {
122    pub fn is_empty(&self) -> bool {
123        self.indexes.is_empty()
124    }
125    pub fn contains(&self, index: &AccountIndex) -> bool {
126        self.indexes.contains(index)
127    }
128    pub fn include_key(&self, key: &Pubkey) -> bool {
129        match &self.keys {
130            Some(options) => options.exclude ^ options.keys.contains(key),
131            None => true, // include all keys
132        }
133    }
134}
135
136#[derive(Debug, Default)]
137pub struct AccountMapEntryMeta {
138    pub dirty: AtomicBool,
139    pub age: AtomicU8,
140}
141
142impl AccountMapEntryMeta {
143    pub fn new_dirty<T: IndexValue>(storage: &Arc<BucketMapHolder<T>>) -> Self {
144        AccountMapEntryMeta {
145            dirty: AtomicBool::new(true),
146            age: AtomicU8::new(storage.future_age_to_flush()),
147        }
148    }
149}
150
151#[derive(Debug, Default)]
152pub struct AccountMapEntryInner<T> {
153    ref_count: AtomicU64,
154    pub slot_list: RwLock<SlotList<T>>,
155    pub meta: AccountMapEntryMeta,
156}
157
158impl<T: IndexValue> AccountMapEntryInner<T> {
159    pub fn new(slot_list: SlotList<T>, ref_count: RefCount, meta: AccountMapEntryMeta) -> Self {
160        Self {
161            slot_list: RwLock::new(slot_list),
162            ref_count: AtomicU64::new(ref_count),
163            meta,
164        }
165    }
166    pub fn ref_count(&self) -> RefCount {
167        self.ref_count.load(Ordering::Relaxed)
168    }
169
170    pub fn add_un_ref(&self, add: bool) {
171        if add {
172            self.ref_count.fetch_add(1, Ordering::Relaxed);
173        } else {
174            self.ref_count.fetch_sub(1, Ordering::Relaxed);
175        }
176        self.set_dirty(true);
177    }
178
179    pub fn dirty(&self) -> bool {
180        self.meta.dirty.load(Ordering::Acquire)
181    }
182
183    pub fn set_dirty(&self, value: bool) {
184        self.meta.dirty.store(value, Ordering::Release)
185    }
186
187    pub fn age(&self) -> Age {
188        self.meta.age.load(Ordering::Relaxed)
189    }
190
191    pub fn set_age(&self, value: Age) {
192        self.meta.age.store(value, Ordering::Relaxed)
193    }
194}
195
196pub enum AccountIndexGetResult<'a, T: IndexValue> {
197    Found(ReadAccountMapEntry<T>, usize),
198    NotFoundOnFork,
199    Missing(AccountMapsReadLock<'a, T>),
200}
201
202#[self_referencing]
203pub struct ReadAccountMapEntry<T: IndexValue> {
204    owned_entry: AccountMapEntry<T>,
205    #[borrows(owned_entry)]
206    #[covariant]
207    slot_list_guard: RwLockReadGuard<'this, SlotList<T>>,
208}
209
210impl<T: IndexValue> Debug for ReadAccountMapEntry<T> {
211    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
212        write!(f, "{:?}", self.borrow_owned_entry())
213    }
214}
215
216impl<T: IndexValue> ReadAccountMapEntry<T> {
217    pub fn from_account_map_entry(account_map_entry: AccountMapEntry<T>) -> Self {
218        ReadAccountMapEntryBuilder {
219            owned_entry: account_map_entry,
220            slot_list_guard_builder: |lock| lock.slot_list.read().unwrap(),
221        }
222        .build()
223    }
224
225    pub fn slot_list(&self) -> &SlotList<T> {
226        &*self.borrow_slot_list_guard()
227    }
228
229    pub fn ref_count(&self) -> RefCount {
230        self.borrow_owned_entry().ref_count()
231    }
232
233    pub fn unref(&self) {
234        self.borrow_owned_entry().add_un_ref(false);
235    }
236
237    pub fn addref(&self) {
238        self.borrow_owned_entry().add_un_ref(true);
239    }
240}
241
242pub struct PreAllocatedAccountMapEntry<T: IndexValue> {
243    entry: AccountMapEntry<T>,
244}
245
246impl<T: IndexValue> From<PreAllocatedAccountMapEntry<T>> for AccountMapEntry<T> {
247    fn from(source: PreAllocatedAccountMapEntry<T>) -> AccountMapEntry<T> {
248        source.entry
249    }
250}
251
252impl<T: IndexValue> From<PreAllocatedAccountMapEntry<T>> for (Slot, T) {
253    fn from(source: PreAllocatedAccountMapEntry<T>) -> (Slot, T) {
254        source.entry.slot_list.write().unwrap().remove(0)
255    }
256}
257
258impl<T: IndexValue> PreAllocatedAccountMapEntry<T> {
259    /// create an entry that is equivalent to this process:
260    /// 1. new empty (refcount=0, slot_list={})
261    /// 2. update(slot, account_info)
262    /// This code is called when the first entry [ie. (slot,account_info)] for a pubkey is inserted into the index.
263    pub fn new(
264        slot: Slot,
265        account_info: T,
266        storage: &Arc<BucketMapHolder<T>>,
267    ) -> PreAllocatedAccountMapEntry<T> {
268        Self::new_internal(slot, account_info, AccountMapEntryMeta::new_dirty(storage))
269    }
270
271    fn new_internal(
272        slot: Slot,
273        account_info: T,
274        meta: AccountMapEntryMeta,
275    ) -> PreAllocatedAccountMapEntry<T> {
276        let ref_count = if account_info.is_cached() { 0 } else { 1 };
277        PreAllocatedAccountMapEntry {
278            entry: Arc::new(AccountMapEntryInner::new(
279                vec![(slot, account_info)],
280                ref_count,
281                meta,
282            )),
283        }
284    }
285}
286
287#[self_referencing]
288pub struct WriteAccountMapEntry<T: IndexValue> {
289    owned_entry: AccountMapEntry<T>,
290    #[borrows(owned_entry)]
291    #[covariant]
292    slot_list_guard: RwLockWriteGuard<'this, SlotList<T>>,
293}
294
295impl<T: IndexValue> WriteAccountMapEntry<T> {
296    pub fn from_account_map_entry(account_map_entry: AccountMapEntry<T>) -> Self {
297        WriteAccountMapEntryBuilder {
298            owned_entry: account_map_entry,
299            slot_list_guard_builder: |lock| lock.slot_list.write().unwrap(),
300        }
301        .build()
302    }
303
304    pub fn slot_list(&self) -> &SlotList<T> {
305        &*self.borrow_slot_list_guard()
306    }
307
308    pub fn slot_list_mut<RT>(
309        &mut self,
310        user: impl for<'this> FnOnce(&mut RwLockWriteGuard<'this, SlotList<T>>) -> RT,
311    ) -> RT {
312        let result = self.with_slot_list_guard_mut(user);
313        self.borrow_owned_entry().set_dirty(true);
314        result
315    }
316}
317
318#[derive(Debug, Default, AbiExample, Clone)]
319pub struct RollingBitField {
320    max_width: u64,
321    min: u64,
322    max: u64, // exclusive
323    bits: BitVec,
324    count: usize,
325    // These are items that are true and lower than min.
326    // They would cause us to exceed max_width if we stored them in our bit field.
327    // We only expect these items in conditions where there is some other bug in the system
328    //  or in testing when large ranges are created.
329    excess: HashSet<u64>,
330}
331
332impl PartialEq<RollingBitField> for RollingBitField {
333    fn eq(&self, other: &Self) -> bool {
334        // 2 instances could have different internal data for the same values,
335        // so we have to compare data.
336        self.len() == other.len() && {
337            for item in self.get_all() {
338                if !other.contains(&item) {
339                    return false;
340                }
341            }
342            true
343        }
344    }
345}
346
347// functionally similar to a hashset
348// Relies on there being a sliding window of key values. The key values continue to increase.
349// Old key values are removed from the lesser values and do not accumulate.
350impl RollingBitField {
351    pub fn new(max_width: u64) -> Self {
352        assert!(max_width > 0);
353        assert!(max_width.is_power_of_two()); // power of 2 to make dividing a shift
354        let bits = BitVec::new_fill(false, max_width);
355        Self {
356            max_width,
357            bits,
358            count: 0,
359            min: 0,
360            max: 0,
361            excess: HashSet::new(),
362        }
363    }
364
365    // find the array index
366    fn get_address(&self, key: &u64) -> u64 {
367        key % self.max_width
368    }
369
370    pub fn range_width(&self) -> u64 {
371        // note that max isn't updated on remove, so it can be above the current max
372        self.max - self.min
373    }
374
375    pub fn min(&self) -> Option<u64> {
376        if self.is_empty() {
377            None
378        } else if self.excess.is_empty() {
379            Some(self.min)
380        } else {
381            let mut min = if self.all_items_in_excess() {
382                u64::MAX
383            } else {
384                self.min
385            };
386            for item in &self.excess {
387                min = std::cmp::min(min, *item);
388            }
389            Some(min)
390        }
391    }
392
393    pub fn insert(&mut self, key: u64) {
394        let mut bits_empty = self.count == 0 || self.all_items_in_excess();
395        let update_bits = if bits_empty {
396            true // nothing in bits, so in range
397        } else if key < self.min {
398            // bits not empty and this insert is before min, so add to excess
399            if self.excess.insert(key) {
400                self.count += 1;
401            }
402            false
403        } else if key < self.max {
404            true // fits current bit field range
405        } else {
406            // key is >= max
407            let new_max = key + 1;
408            loop {
409                let new_width = new_max.saturating_sub(self.min);
410                if new_width <= self.max_width {
411                    // this key will fit the max range
412                    break;
413                }
414
415                // move the min item from bits to excess and then purge from min to make room for this new max
416                let inserted = self.excess.insert(self.min);
417                assert!(inserted);
418
419                let key = self.min;
420                let address = self.get_address(&key);
421                self.bits.set(address, false);
422                self.purge(&key);
423
424                if self.all_items_in_excess() {
425                    // if we moved the last existing item to excess, then we are ready to insert the new item in the bits
426                    bits_empty = true;
427                    break;
428                }
429            }
430
431            true // moved things to excess if necessary, so update bits with the new entry
432        };
433
434        if update_bits {
435            let address = self.get_address(&key);
436            let value = self.bits.get(address);
437            if !value {
438                self.bits.set(address, true);
439                if bits_empty {
440                    self.min = key;
441                    self.max = key + 1;
442                } else {
443                    self.min = std::cmp::min(self.min, key);
444                    self.max = std::cmp::max(self.max, key + 1);
445                    assert!(
446                        self.min + self.max_width >= self.max,
447                        "min: {}, max: {}, max_width: {}",
448                        self.min,
449                        self.max,
450                        self.max_width
451                    );
452                }
453                self.count += 1;
454            }
455        }
456    }
457
458    pub fn remove(&mut self, key: &u64) -> bool {
459        if key >= &self.min {
460            // if asked to remove something bigger than max, then no-op
461            if key < &self.max {
462                let address = self.get_address(key);
463                let get = self.bits.get(address);
464                if get {
465                    self.count -= 1;
466                    self.bits.set(address, false);
467                    self.purge(key);
468                }
469                get
470            } else {
471                false
472            }
473        } else {
474            // asked to remove something < min. would be in excess if it exists
475            let remove = self.excess.remove(key);
476            if remove {
477                self.count -= 1;
478            }
479            remove
480        }
481    }
482
483    fn all_items_in_excess(&self) -> bool {
484        self.excess.len() == self.count
485    }
486
487    // after removing 'key' where 'key' = min, make min the correct new min value
488    fn purge(&mut self, key: &u64) {
489        if self.count > 0 && !self.all_items_in_excess() {
490            if key == &self.min {
491                let start = self.min + 1; // min just got removed
492                for key in start..self.max {
493                    if self.contains_assume_in_range(&key) {
494                        self.min = key;
495                        break;
496                    }
497                }
498            }
499        } else {
500            // The idea is that there are no items in the bitfield anymore.
501            // But, there MAY be items in excess. The model works such that items < min go into excess.
502            // So, after purging all items from bitfield, we hold max to be what it previously was, but set min to max.
503            // Thus, if we lookup >= max, answer is always false without having to look in excess.
504            // If we changed max here to 0, we would lose the ability to know the range of items in excess (if any).
505            // So, now, with min updated = max:
506            // If we lookup < max, then we first check min.
507            // If >= min, then we look in bitfield.
508            // Otherwise, we look in excess since the request is < min.
509            // So, resetting min like this after a remove results in the correct behavior for the model.
510            // Later, if we insert and there are 0 items total (excess + bitfield), then we reset min/max to reflect the new item only.
511            self.min = self.max;
512        }
513    }
514
515    fn contains_assume_in_range(&self, key: &u64) -> bool {
516        // the result may be aliased. Caller is responsible for determining key is in range.
517        let address = self.get_address(key);
518        self.bits.get(address)
519    }
520
521    // This is the 99% use case.
522    // This needs be fast for the most common case of asking for key >= min.
523    pub fn contains(&self, key: &u64) -> bool {
524        if key < &self.max {
525            if key >= &self.min {
526                // in the bitfield range
527                self.contains_assume_in_range(key)
528            } else {
529                self.excess.contains(key)
530            }
531        } else {
532            false
533        }
534    }
535
536    pub fn len(&self) -> usize {
537        self.count
538    }
539
540    pub fn is_empty(&self) -> bool {
541        self.len() == 0
542    }
543
544    pub fn clear(&mut self) {
545        let mut n = Self::new(self.max_width);
546        std::mem::swap(&mut n, self);
547    }
548
549    pub fn max(&self) -> u64 {
550        self.max
551    }
552
553    pub fn get_all(&self) -> Vec<u64> {
554        let mut all = Vec::with_capacity(self.count);
555        self.excess.iter().for_each(|slot| all.push(*slot));
556        for key in self.min..self.max {
557            if self.contains_assume_in_range(&key) {
558                all.push(key);
559            }
560        }
561        all
562    }
563}
564
565#[derive(Debug)]
566pub struct RootsTracker {
567    roots: RollingBitField,
568    max_root: Slot,
569    uncleaned_roots: HashSet<Slot>,
570    previous_uncleaned_roots: HashSet<Slot>,
571}
572
573impl Default for RootsTracker {
574    fn default() -> Self {
575        // we expect to keep a rolling set of 400k slots around at a time
576        // 4M gives us plenty of extra(?!) room to handle a width 10x what we should need.
577        // cost is 4M bits of memory, which is .5MB
578        RootsTracker::new(4194304)
579    }
580}
581
582impl RootsTracker {
583    pub fn new(max_width: u64) -> Self {
584        Self {
585            roots: RollingBitField::new(max_width),
586            max_root: 0,
587            uncleaned_roots: HashSet::new(),
588            previous_uncleaned_roots: HashSet::new(),
589        }
590    }
591
592    pub fn min_root(&self) -> Option<Slot> {
593        self.roots.min()
594    }
595}
596
597#[derive(Debug, Default)]
598pub struct AccountsIndexRootsStats {
599    pub roots_len: usize,
600    pub uncleaned_roots_len: usize,
601    pub previous_uncleaned_roots_len: usize,
602    pub roots_range: u64,
603    pub rooted_cleaned_count: usize,
604    pub unrooted_cleaned_count: usize,
605}
606
607pub struct AccountsIndexIterator<'a, T: IndexValue> {
608    account_maps: &'a LockMapTypeSlice<T>,
609    bin_calculator: &'a PubkeyBinCalculator16,
610    start_bound: Bound<Pubkey>,
611    end_bound: Bound<Pubkey>,
612    is_finished: bool,
613    collect_all_unsorted: bool,
614}
615
616impl<'a, T: IndexValue> AccountsIndexIterator<'a, T> {
617    fn range<R>(
618        map: &AccountMapsReadLock<T>,
619        range: R,
620        collect_all_unsorted: bool,
621    ) -> Vec<(Pubkey, AccountMapEntry<T>)>
622    where
623        R: RangeBounds<Pubkey> + std::fmt::Debug,
624    {
625        let mut result = map.items(&Some(&range));
626        if !collect_all_unsorted {
627            result.sort_unstable_by(|a, b| a.0.cmp(&b.0));
628        }
629        result
630    }
631
632    fn clone_bound(bound: Bound<&Pubkey>) -> Bound<Pubkey> {
633        match bound {
634            Unbounded => Unbounded,
635            Included(k) => Included(*k),
636            Excluded(k) => Excluded(*k),
637        }
638    }
639
640    fn bin_from_bound(&self, bound: &Bound<Pubkey>, unbounded_bin: usize) -> usize {
641        match bound {
642            Bound::Included(bound) | Bound::Excluded(bound) => {
643                self.bin_calculator.bin_from_pubkey(bound)
644            }
645            Bound::Unbounded => unbounded_bin,
646        }
647    }
648
649    fn start_bin(&self) -> usize {
650        // start in bin where 'start_bound' would exist
651        self.bin_from_bound(&self.start_bound, 0)
652    }
653
654    fn end_bin_inclusive(&self) -> usize {
655        // end in bin where 'end_bound' would exist
656        self.bin_from_bound(&self.end_bound, usize::MAX)
657    }
658
659    fn bin_start_and_range(&self) -> (usize, usize) {
660        let start_bin = self.start_bin();
661        // calculate the max range of bins to look in
662        let end_bin_inclusive = self.end_bin_inclusive();
663        let bin_range = if start_bin > end_bin_inclusive {
664            0 // empty range
665        } else if end_bin_inclusive == usize::MAX {
666            usize::MAX
667        } else {
668            // the range is end_inclusive + 1 - start
669            // end_inclusive could be usize::MAX already if no bound was specified
670            end_bin_inclusive.saturating_add(1) - start_bin
671        };
672        (start_bin, bin_range)
673    }
674
675    pub fn new<R>(
676        index: &'a AccountsIndex<T>,
677        range: Option<&R>,
678        collect_all_unsorted: bool,
679    ) -> Self
680    where
681        R: RangeBounds<Pubkey>,
682    {
683        Self {
684            start_bound: range
685                .as_ref()
686                .map(|r| Self::clone_bound(r.start_bound()))
687                .unwrap_or(Unbounded),
688            end_bound: range
689                .as_ref()
690                .map(|r| Self::clone_bound(r.end_bound()))
691                .unwrap_or(Unbounded),
692            account_maps: &index.account_maps,
693            is_finished: false,
694            bin_calculator: &index.bin_calculator,
695            collect_all_unsorted,
696        }
697    }
698
699    pub fn hold_range_in_memory<R>(&self, range: &R, start_holding: bool)
700    where
701        R: RangeBounds<Pubkey> + Debug,
702    {
703        // forward this hold request ONLY to the bins which contain keys in the specified range
704        let (start_bin, bin_range) = self.bin_start_and_range();
705        self.account_maps
706            .iter()
707            .skip(start_bin)
708            .take(bin_range)
709            .for_each(|map| {
710                map.read()
711                    .unwrap()
712                    .hold_range_in_memory(range, start_holding);
713            });
714    }
715}
716
717impl<'a, T: IndexValue> Iterator for AccountsIndexIterator<'a, T> {
718    type Item = Vec<(Pubkey, AccountMapEntry<T>)>;
719    fn next(&mut self) -> Option<Self::Item> {
720        if self.is_finished {
721            return None;
722        }
723        let (start_bin, bin_range) = self.bin_start_and_range();
724        let mut chunk = Vec::with_capacity(ITER_BATCH_SIZE);
725        'outer: for i in self.account_maps.iter().skip(start_bin).take(bin_range) {
726            for (pubkey, account_map_entry) in Self::range(
727                &i.read().unwrap(),
728                (self.start_bound, self.end_bound),
729                self.collect_all_unsorted,
730            ) {
731                if chunk.len() >= ITER_BATCH_SIZE && !self.collect_all_unsorted {
732                    break 'outer;
733                }
734                let item = (pubkey, account_map_entry);
735                chunk.push(item);
736            }
737        }
738
739        if chunk.is_empty() {
740            self.is_finished = true;
741            return None;
742        } else if self.collect_all_unsorted {
743            self.is_finished = true;
744        }
745
746        self.start_bound = Excluded(chunk.last().unwrap().0);
747        Some(chunk)
748    }
749}
750
751pub trait ZeroCarat {
752    fn is_zero_carat(&self) -> bool;
753}
754
755type MapType<T> = AccountMap<T>;
756type LockMapType<T> = Vec<RwLock<MapType<T>>>;
757type LockMapTypeSlice<T> = [RwLock<MapType<T>>];
758type AccountMapsWriteLock<'a, T> = RwLockWriteGuard<'a, MapType<T>>;
759type AccountMapsReadLock<'a, T> = RwLockReadGuard<'a, MapType<T>>;
760
761#[derive(Debug, Default)]
762pub struct ScanSlotTracker {
763    is_removed: bool,
764    ref_count: u64,
765}
766
767impl ScanSlotTracker {
768    pub fn is_removed(&self) -> bool {
769        self.is_removed
770    }
771
772    pub fn mark_removed(&mut self) {
773        self.is_removed = true;
774    }
775}
776
777#[derive(Debug)]
778pub struct AccountsIndex<T: IndexValue> {
779    pub account_maps: LockMapType<T>,
780    pub bin_calculator: PubkeyBinCalculator16,
781    program_id_index: SecondaryIndex<DashMapSecondaryIndexEntry>,
782    spl_token_mint_index: SecondaryIndex<DashMapSecondaryIndexEntry>,
783    spl_token_owner_index: SecondaryIndex<RwLockSecondaryIndexEntry>,
784    roots_tracker: RwLock<RootsTracker>,
785    ongoing_scan_roots: RwLock<BTreeMap<Slot, u64>>,
786    // Each scan has some latest slot `S` that is the tip of the fork the scan
787    // is iterating over. The unique id of that slot `S` is recorded here (note we don't use
788    // `S` as the id because there can be more than one version of a slot `S`). If a fork
789    // is abandoned, all of the slots on that fork up to `S` will be removed via
790    // `AccountsDb::remove_unrooted_slots()`. When the scan finishes, it'll realize that the
791    // results of the scan may have been corrupted by `remove_unrooted_slots` and abort its results.
792    //
793    // `removed_bank_ids` tracks all the slot ids that were removed via `remove_unrooted_slots()` so any attempted scans
794    // on any of these slots fails. This is safe to purge once the associated Bank is dropped and
795    // scanning the fork with that Bank at the tip is no longer possible.
796    pub removed_bank_ids: Mutex<HashSet<BankId>>,
797
798    storage: AccountsIndexStorage<T>,
799}
800
801impl<T: IndexValue> AccountsIndex<T> {
802    pub fn default_for_tests() -> Self {
803        Self::new(Some(ACCOUNTS_INDEX_CONFIG_FOR_TESTING))
804    }
805
806    pub fn new(config: Option<AccountsIndexConfig>) -> Self {
807        let (account_maps, bin_calculator, storage) = Self::allocate_accounts_index(config);
808        Self {
809            account_maps,
810            bin_calculator,
811            program_id_index: SecondaryIndex::<DashMapSecondaryIndexEntry>::new(
812                "program_id_index_stats",
813            ),
814            spl_token_mint_index: SecondaryIndex::<DashMapSecondaryIndexEntry>::new(
815                "spl_token_mint_index_stats",
816            ),
817            spl_token_owner_index: SecondaryIndex::<RwLockSecondaryIndexEntry>::new(
818                "spl_token_owner_index_stats",
819            ),
820            roots_tracker: RwLock::<RootsTracker>::default(),
821            ongoing_scan_roots: RwLock::<BTreeMap<Slot, u64>>::default(),
822            removed_bank_ids: Mutex::<HashSet<BankId>>::default(),
823            storage,
824        }
825    }
826
827    fn allocate_accounts_index(
828        config: Option<AccountsIndexConfig>,
829    ) -> (
830        LockMapType<T>,
831        PubkeyBinCalculator16,
832        AccountsIndexStorage<T>,
833    ) {
834        let bins = config
835            .as_ref()
836            .and_then(|config| config.bins)
837            .unwrap_or(BINS_DEFAULT);
838        // create bin_calculator early to verify # bins is reasonable
839        let bin_calculator = PubkeyBinCalculator16::new(bins);
840        let storage = AccountsIndexStorage::new(bins, &config);
841        let account_maps = (0..bins)
842            .into_iter()
843            .map(|bin| RwLock::new(Arc::clone(&storage.in_mem[bin])))
844            .collect::<Vec<_>>();
845        (account_maps, bin_calculator, storage)
846    }
847
848    fn iter<R>(&self, range: Option<&R>, collect_all_unsorted: bool) -> AccountsIndexIterator<T>
849    where
850        R: RangeBounds<Pubkey>,
851    {
852        AccountsIndexIterator::new(self, range, collect_all_unsorted)
853    }
854
855    fn do_checked_scan_accounts<F, R>(
856        &self,
857        metric_name: &'static str,
858        ancestors: &Ancestors,
859        scan_bank_id: BankId,
860        func: F,
861        scan_type: ScanTypes<R>,
862        collect_all_unsorted: bool,
863    ) -> Result<(), ScanError>
864    where
865        F: FnMut(&Pubkey, (&T, Slot)),
866        R: RangeBounds<Pubkey> + std::fmt::Debug,
867    {
868        {
869            let locked_removed_bank_ids = self.removed_bank_ids.lock().unwrap();
870            if locked_removed_bank_ids.contains(&scan_bank_id) {
871                return Err(ScanError::SlotRemoved {
872                    slot: ancestors.max_slot(),
873                    bank_id: scan_bank_id,
874                });
875            }
876        }
877
878        let max_root = {
879            let mut w_ongoing_scan_roots = self
880                // This lock is also grabbed by clean_accounts(), so clean
881                // has at most cleaned up to the current `max_root` (since
882                // clean only happens *after* BankForks::set_root() which sets
883                // the `max_root`)
884                .ongoing_scan_roots
885                .write()
886                .unwrap();
887            // `max_root()` grabs a lock while
888            // the `ongoing_scan_roots` lock is held,
889            // make sure inverse doesn't happen to avoid
890            // deadlock
891            let max_root = self.max_root();
892            *w_ongoing_scan_roots.entry(max_root).or_default() += 1;
893
894            max_root
895        };
896
897        // First we show that for any bank `B` that is a descendant of
898        // the current `max_root`, it must be true that and `B.ancestors.contains(max_root)`,
899        // regardless of the pattern of `squash()` behavior, where `ancestors` is the set
900        // of ancestors that is tracked in each bank.
901        //
902        // Proof: At startup, if starting from a snapshot, generate_index() adds all banks
903        // in the snapshot to the index via `add_root()` and so `max_root` will be the
904        // greatest of these. Thus, so the claim holds at startup since there are no
905        // descendants of `max_root`.
906        //
907        // Now we proceed by induction on each `BankForks::set_root()`.
908        // Assume the claim holds when the `max_root` is `R`. Call the set of
909        // descendants of `R` present in BankForks `R_descendants`.
910        //
911        // Then for any banks `B` in `R_descendants`, it must be that `B.ancestors.contains(S)`,
912        // where `S` is any ancestor of `B` such that `S >= R`.
913        //
914        // For example:
915        //          `R` -> `A` -> `C` -> `B`
916        // Then `B.ancestors == {R, A, C}`
917        //
918        // Next we call `BankForks::set_root()` at some descendant of `R`, `R_new`,
919        // where `R_new > R`.
920        //
921        // When we squash `R_new`, `max_root` in the AccountsIndex here is now set to `R_new`,
922        // and all nondescendants of `R_new` are pruned.
923        //
924        // Now consider any outstanding references to banks in the system that are descended from
925        // `max_root == R_new`. Take any one of these references and call it `B`. Because `B` is
926        // a descendant of `R_new`, this means `B` was also a descendant of `R`. Thus `B`
927        // must be a member of `R_descendants` because `B` was constructed and added to
928        // BankForks before the `set_root`.
929        //
930        // This means by the guarantees of `R_descendants` described above, because
931        // `R_new` is an ancestor of `B`, and `R < R_new < B`, then `B.ancestors.contains(R_new)`.
932        //
933        // Now until the next `set_root`, any new banks constructed from `new_from_parent` will
934        // also have `max_root == R_new` in their ancestor set, so the claim holds for those descendants
935        // as well. Once the next `set_root` happens, we once again update `max_root` and the same
936        // inductive argument can be applied again to show the claim holds.
937
938        // Check that the `max_root` is present in `ancestors`. From the proof above, if
939        // `max_root` is not present in `ancestors`, this means the bank `B` with the
940        // given `ancestors` is not descended from `max_root, which means
941        // either:
942        // 1) `B` is on a different fork or
943        // 2) `B` is an ancestor of `max_root`.
944        // In both cases we can ignore the given ancestors and instead just rely on the roots
945        // present as `max_root` indicates the roots present in the index are more up to date
946        // than the ancestors given.
947        let empty = Ancestors::default();
948        let ancestors = if ancestors.contains_key(&max_root) {
949            ancestors
950        } else {
951            /*
952            This takes of edge cases like:
953
954            Diagram 1:
955
956                        slot 0
957                          |
958                        slot 1
959                      /        \
960                 slot 2         |
961                    |       slot 3 (max root)
962            slot 4 (scan)
963
964            By the time the scan on slot 4 is called, slot 2 may already have been
965            cleaned by a clean on slot 3, but slot 4 may not have been cleaned.
966            The state in slot 2 would have been purged and is not saved in any roots.
967            In this case, a scan on slot 4 wouldn't accurately reflect the state when bank 4
968            was frozen. In cases like this, we default to a scan on the latest roots by
969            removing all `ancestors`.
970            */
971            &empty
972        };
973
974        /*
975        Now there are two cases, either `ancestors` is empty or nonempty:
976
977        1) If ancestors is empty, then this is the same as a scan on a rooted bank,
978        and `ongoing_scan_roots` provides protection against cleanup of roots necessary
979        for the scan, and  passing `Some(max_root)` to `do_scan_accounts()` ensures newer
980        roots don't appear in the scan.
981
982        2) If ancestors is non-empty, then from the `ancestors_contains(&max_root)` above, we know
983        that the fork structure must look something like:
984
985        Diagram 2:
986
987                Build fork structure:
988                        slot 0
989                          |
990                    slot 1 (max_root)
991                    /            \
992             slot 2              |
993                |            slot 3 (potential newer max root)
994              slot 4
995                |
996             slot 5 (scan)
997
998        Consider both types of ancestors, ancestor <= `max_root` and
999        ancestor > `max_root`, where `max_root == 1` as illustrated above.
1000
1001        a) The set of `ancestors <= max_root` are all rooted, which means their state
1002        is protected by the same guarantees as 1).
1003
1004        b) As for the `ancestors > max_root`, those banks have at least one reference discoverable
1005        through the chain of `Bank::BankRc::parent` starting from the calling bank. For instance
1006        bank 5's parent reference keeps bank 4 alive, which will prevent the `Bank::drop()` from
1007        running and cleaning up bank 4. Furthermore, no cleans can happen past the saved max_root == 1,
1008        so a potential newer max root at 3 will not clean up any of the ancestors > 1, so slot 4
1009        will not be cleaned in the middle of the scan either. (NOTE similar reasoning is employed for
1010        assert!() justification in AccountsDb::retry_to_get_account_accessor)
1011        */
1012        match scan_type {
1013            ScanTypes::Unindexed(range) => {
1014                // Pass "" not to log metrics, so RPC doesn't get spammy
1015                self.do_scan_accounts(
1016                    metric_name,
1017                    ancestors,
1018                    func,
1019                    range,
1020                    Some(max_root),
1021                    collect_all_unsorted,
1022                );
1023            }
1024            ScanTypes::Indexed(IndexKey::ProgramId(program_id)) => {
1025                self.do_scan_secondary_index(
1026                    ancestors,
1027                    func,
1028                    &self.program_id_index,
1029                    &program_id,
1030                    Some(max_root),
1031                );
1032            }
1033            ScanTypes::Indexed(IndexKey::SplTokenMint(mint_key)) => {
1034                self.do_scan_secondary_index(
1035                    ancestors,
1036                    func,
1037                    &self.spl_token_mint_index,
1038                    &mint_key,
1039                    Some(max_root),
1040                );
1041            }
1042            ScanTypes::Indexed(IndexKey::SplTokenOwner(owner_key)) => {
1043                self.do_scan_secondary_index(
1044                    ancestors,
1045                    func,
1046                    &self.spl_token_owner_index,
1047                    &owner_key,
1048                    Some(max_root),
1049                );
1050            }
1051        }
1052
1053        {
1054            let mut ongoing_scan_roots = self.ongoing_scan_roots.write().unwrap();
1055            let count = ongoing_scan_roots.get_mut(&max_root).unwrap();
1056            *count -= 1;
1057            if *count == 0 {
1058                ongoing_scan_roots.remove(&max_root);
1059            }
1060        }
1061
1062        // If the fork with tip at bank `scan_bank_id` was removed during our scan, then the scan
1063        // may have been corrupted, so abort the results.
1064        let was_scan_corrupted = self
1065            .removed_bank_ids
1066            .lock()
1067            .unwrap()
1068            .contains(&scan_bank_id);
1069
1070        if was_scan_corrupted {
1071            Err(ScanError::SlotRemoved {
1072                slot: ancestors.max_slot(),
1073                bank_id: scan_bank_id,
1074            })
1075        } else {
1076            Ok(())
1077        }
1078    }
1079
1080    fn do_unchecked_scan_accounts<F, R>(
1081        &self,
1082        metric_name: &'static str,
1083        ancestors: &Ancestors,
1084        func: F,
1085        range: Option<R>,
1086        collect_all_unsorted: bool,
1087    ) where
1088        F: FnMut(&Pubkey, (&T, Slot)),
1089        R: RangeBounds<Pubkey> + std::fmt::Debug,
1090    {
1091        self.do_scan_accounts(
1092            metric_name,
1093            ancestors,
1094            func,
1095            range,
1096            None,
1097            collect_all_unsorted,
1098        );
1099    }
1100
1101    // Scan accounts and return latest version of each account that is either:
1102    // 1) rooted or
1103    // 2) present in ancestors
1104    fn do_scan_accounts<F, R>(
1105        &self,
1106        metric_name: &'static str,
1107        ancestors: &Ancestors,
1108        mut func: F,
1109        range: Option<R>,
1110        max_root: Option<Slot>,
1111        collect_all_unsorted: bool,
1112    ) where
1113        F: FnMut(&Pubkey, (&T, Slot)),
1114        R: RangeBounds<Pubkey> + std::fmt::Debug,
1115    {
1116        // TODO: expand to use mint index to find the `pubkey_list` below more efficiently
1117        // instead of scanning the entire range
1118        let mut total_elapsed_timer = Measure::start("total");
1119        let mut num_keys_iterated = 0;
1120        let mut latest_slot_elapsed = 0;
1121        let mut load_account_elapsed = 0;
1122        let mut read_lock_elapsed = 0;
1123        let mut iterator_elapsed = 0;
1124        let mut iterator_timer = Measure::start("iterator_elapsed");
1125        for pubkey_list in self.iter(range.as_ref(), collect_all_unsorted) {
1126            iterator_timer.stop();
1127            iterator_elapsed += iterator_timer.as_us();
1128            for (pubkey, list) in pubkey_list {
1129                num_keys_iterated += 1;
1130                let mut read_lock_timer = Measure::start("read_lock");
1131                let list_r = &list.slot_list.read().unwrap();
1132                read_lock_timer.stop();
1133                read_lock_elapsed += read_lock_timer.as_us();
1134                let mut latest_slot_timer = Measure::start("latest_slot");
1135                if let Some(index) = self.latest_slot(Some(ancestors), list_r, max_root) {
1136                    latest_slot_timer.stop();
1137                    latest_slot_elapsed += latest_slot_timer.as_us();
1138                    let mut load_account_timer = Measure::start("load_account");
1139                    func(&pubkey, (&list_r[index].1, list_r[index].0));
1140                    load_account_timer.stop();
1141                    load_account_elapsed += load_account_timer.as_us();
1142                }
1143            }
1144            iterator_timer = Measure::start("iterator_elapsed");
1145        }
1146
1147        total_elapsed_timer.stop();
1148        if !metric_name.is_empty() {
1149            datapoint_info!(
1150                metric_name,
1151                ("total_elapsed", total_elapsed_timer.as_us(), i64),
1152                ("latest_slot_elapsed", latest_slot_elapsed, i64),
1153                ("read_lock_elapsed", read_lock_elapsed, i64),
1154                ("load_account_elapsed", load_account_elapsed, i64),
1155                ("iterator_elapsed", iterator_elapsed, i64),
1156                ("num_keys_iterated", num_keys_iterated, i64),
1157            )
1158        }
1159    }
1160
1161    fn do_scan_secondary_index<
1162        F,
1163        SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
1164    >(
1165        &self,
1166        ancestors: &Ancestors,
1167        mut func: F,
1168        index: &SecondaryIndex<SecondaryIndexEntryType>,
1169        index_key: &Pubkey,
1170        max_root: Option<Slot>,
1171    ) where
1172        F: FnMut(&Pubkey, (&T, Slot)),
1173    {
1174        for pubkey in index.get(index_key) {
1175            // Maybe these reads from the AccountsIndex can be batched every time it
1176            // grabs the read lock as well...
1177            if let AccountIndexGetResult::Found(list_r, index) =
1178                self.get(&pubkey, Some(ancestors), max_root)
1179            {
1180                func(
1181                    &pubkey,
1182                    (&list_r.slot_list()[index].1, list_r.slot_list()[index].0),
1183                );
1184            }
1185        }
1186    }
1187
1188    pub fn get_account_read_entry(&self, pubkey: &Pubkey) -> Option<ReadAccountMapEntry<T>> {
1189        let lock = self.get_account_maps_read_lock(pubkey);
1190        self.get_account_read_entry_with_lock(pubkey, &lock)
1191    }
1192
1193    pub fn get_account_read_entry_with_lock(
1194        &self,
1195        pubkey: &Pubkey,
1196        lock: &AccountMapsReadLock<'_, T>,
1197    ) -> Option<ReadAccountMapEntry<T>> {
1198        lock.get(pubkey)
1199            .map(ReadAccountMapEntry::from_account_map_entry)
1200    }
1201
1202    fn get_account_write_entry(&self, pubkey: &Pubkey) -> Option<WriteAccountMapEntry<T>> {
1203        self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)]
1204            .read()
1205            .unwrap()
1206            .get(pubkey)
1207            .map(WriteAccountMapEntry::from_account_map_entry)
1208    }
1209
1210    pub fn handle_dead_keys(
1211        &self,
1212        dead_keys: &[&Pubkey],
1213        account_indexes: &AccountSecondaryIndexes,
1214    ) {
1215        if !dead_keys.is_empty() {
1216            for key in dead_keys.iter() {
1217                let w_index = self.get_account_maps_write_lock(key);
1218                if w_index.remove_if_slot_list_empty(**key) {
1219                    // Note it's only safe to remove all the entries for this key
1220                    // because we have the lock for this key's entry in the AccountsIndex,
1221                    // so no other thread is also updating the index
1222                    self.purge_secondary_indexes_by_inner_key(key, account_indexes);
1223                }
1224            }
1225        }
1226    }
1227
1228    /// call func with every pubkey and index visible from a given set of ancestors
1229    pub(crate) fn scan_accounts<F>(
1230        &self,
1231        ancestors: &Ancestors,
1232        scan_bank_id: BankId,
1233        func: F,
1234    ) -> Result<(), ScanError>
1235    where
1236        F: FnMut(&Pubkey, (&T, Slot)),
1237    {
1238        let collect_all_unsorted = false;
1239        // Pass "" not to log metrics, so RPC doesn't get spammy
1240        self.do_checked_scan_accounts(
1241            "",
1242            ancestors,
1243            scan_bank_id,
1244            func,
1245            ScanTypes::Unindexed(None::<Range<Pubkey>>),
1246            collect_all_unsorted,
1247        )
1248    }
1249
1250    pub(crate) fn unchecked_scan_accounts<F>(
1251        &self,
1252        metric_name: &'static str,
1253        ancestors: &Ancestors,
1254        func: F,
1255        collect_all_unsorted: bool,
1256    ) where
1257        F: FnMut(&Pubkey, (&T, Slot)),
1258    {
1259        self.do_unchecked_scan_accounts(
1260            metric_name,
1261            ancestors,
1262            func,
1263            None::<Range<Pubkey>>,
1264            collect_all_unsorted,
1265        );
1266    }
1267
1268    /// call func with every pubkey and index visible from a given set of ancestors with range
1269    pub(crate) fn range_scan_accounts<F, R>(
1270        &self,
1271        metric_name: &'static str,
1272        ancestors: &Ancestors,
1273        range: R,
1274        collect_all_unsorted: bool,
1275        func: F,
1276    ) where
1277        F: FnMut(&Pubkey, (&T, Slot)),
1278        R: RangeBounds<Pubkey> + std::fmt::Debug,
1279    {
1280        // Only the rent logic should be calling this, which doesn't need the safety checks
1281        self.do_unchecked_scan_accounts(
1282            metric_name,
1283            ancestors,
1284            func,
1285            Some(range),
1286            collect_all_unsorted,
1287        );
1288    }
1289
1290    /// call func with every pubkey and index visible from a given set of ancestors
1291    pub(crate) fn index_scan_accounts<F>(
1292        &self,
1293        ancestors: &Ancestors,
1294        scan_bank_id: BankId,
1295        index_key: IndexKey,
1296        func: F,
1297    ) -> Result<(), ScanError>
1298    where
1299        F: FnMut(&Pubkey, (&T, Slot)),
1300    {
1301        let collect_all_unsorted = false;
1302
1303        // Pass "" not to log metrics, so RPC doesn't get spammy
1304        self.do_checked_scan_accounts(
1305            "",
1306            ancestors,
1307            scan_bank_id,
1308            func,
1309            ScanTypes::<Range<Pubkey>>::Indexed(index_key),
1310            collect_all_unsorted,
1311        )
1312    }
1313
1314    pub fn get_rooted_entries(&self, slice: SlotSlice<T>, max: Option<Slot>) -> SlotList<T> {
1315        let max = max.unwrap_or(Slot::MAX);
1316        let lock = &self.roots_tracker.read().unwrap().roots;
1317        slice
1318            .iter()
1319            .filter(|(slot, _)| *slot <= max && lock.contains(slot))
1320            .cloned()
1321            .collect()
1322    }
1323
1324    // returns the rooted entries and the storage ref count
1325    pub fn roots_and_ref_count(
1326        &self,
1327        locked_account_entry: &ReadAccountMapEntry<T>,
1328        max: Option<Slot>,
1329    ) -> (SlotList<T>, RefCount) {
1330        (
1331            self.get_rooted_entries(locked_account_entry.slot_list(), max),
1332            locked_account_entry.ref_count(),
1333        )
1334    }
1335
1336    pub fn purge_exact<'a, C>(
1337        &'a self,
1338        pubkey: &Pubkey,
1339        slots_to_purge: &'a C,
1340        reclaims: &mut SlotList<T>,
1341    ) -> bool
1342    where
1343        C: Contains<'a, Slot>,
1344    {
1345        if let Some(mut write_account_map_entry) = self.get_account_write_entry(pubkey) {
1346            write_account_map_entry.slot_list_mut(|slot_list| {
1347                slot_list.retain(|(slot, item)| {
1348                    let should_purge = slots_to_purge.contains(slot);
1349                    if should_purge {
1350                        reclaims.push((*slot, *item));
1351                        false
1352                    } else {
1353                        true
1354                    }
1355                });
1356                slot_list.is_empty()
1357            })
1358        } else {
1359            true
1360        }
1361    }
1362
1363    pub fn min_ongoing_scan_root(&self) -> Option<Slot> {
1364        self.ongoing_scan_roots
1365            .read()
1366            .unwrap()
1367            .keys()
1368            .next()
1369            .cloned()
1370    }
1371
1372    // Given a SlotSlice `L`, a list of ancestors and a maximum slot, find the latest element
1373    // in `L`, where the slot `S` is an ancestor or root, and if `S` is a root, then `S <= max_root`
1374    fn latest_slot(
1375        &self,
1376        ancestors: Option<&Ancestors>,
1377        slice: SlotSlice<T>,
1378        max_root: Option<Slot>,
1379    ) -> Option<usize> {
1380        let mut current_max = 0;
1381        let mut rv = None;
1382        if let Some(ancestors) = ancestors {
1383            if !ancestors.is_empty() {
1384                for (i, (slot, _t)) in slice.iter().rev().enumerate() {
1385                    if (rv.is_none() || *slot > current_max) && ancestors.contains_key(slot) {
1386                        rv = Some(i);
1387                        current_max = *slot;
1388                    }
1389                }
1390            }
1391        }
1392
1393        let max_root = max_root.unwrap_or(Slot::MAX);
1394        let mut tracker = None;
1395
1396        for (i, (slot, _t)) in slice.iter().rev().enumerate() {
1397            if (rv.is_none() || *slot > current_max) && *slot <= max_root {
1398                let lock = match tracker {
1399                    Some(inner) => inner,
1400                    None => self.roots_tracker.read().unwrap(),
1401                };
1402                if lock.roots.contains(slot) {
1403                    rv = Some(i);
1404                    current_max = *slot;
1405                }
1406                tracker = Some(lock);
1407            }
1408        }
1409
1410        rv.map(|index| slice.len() - 1 - index)
1411    }
1412
1413    pub fn hold_range_in_memory<R>(&self, range: &R, start_holding: bool)
1414    where
1415        R: RangeBounds<Pubkey> + Debug,
1416    {
1417        let iter = self.iter(Some(range), true);
1418        iter.hold_range_in_memory(range, start_holding);
1419    }
1420
1421    pub fn set_startup(&self, value: bool) {
1422        self.storage.storage.set_startup(value);
1423    }
1424
1425    /// Get an account
1426    /// The latest account that appears in `ancestors` or `roots` is returned.
1427    pub(crate) fn get(
1428        &self,
1429        pubkey: &Pubkey,
1430        ancestors: Option<&Ancestors>,
1431        max_root: Option<Slot>,
1432    ) -> AccountIndexGetResult<'_, T> {
1433        let read_lock = self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)]
1434            .read()
1435            .unwrap();
1436        let account = read_lock
1437            .get(pubkey)
1438            .map(ReadAccountMapEntry::from_account_map_entry);
1439
1440        match account {
1441            Some(locked_entry) => {
1442                drop(read_lock);
1443                let slot_list = locked_entry.slot_list();
1444                let found_index = self.latest_slot(ancestors, slot_list, max_root);
1445                match found_index {
1446                    Some(found_index) => AccountIndexGetResult::Found(locked_entry, found_index),
1447                    None => AccountIndexGetResult::NotFoundOnFork,
1448                }
1449            }
1450            None => AccountIndexGetResult::Missing(read_lock),
1451        }
1452    }
1453
1454    // Get the maximum root <= `max_allowed_root` from the given `slice`
1455    fn get_newest_root_in_slot_list(
1456        roots: &RollingBitField,
1457        slice: SlotSlice<T>,
1458        max_allowed_root: Option<Slot>,
1459    ) -> Slot {
1460        let mut max_root = 0;
1461        for (f, _) in slice.iter() {
1462            if let Some(max_allowed_root) = max_allowed_root {
1463                if *f > max_allowed_root {
1464                    continue;
1465                }
1466            }
1467            if *f > max_root && roots.contains(f) {
1468                max_root = *f;
1469            }
1470        }
1471        max_root
1472    }
1473
1474    pub(crate) fn update_secondary_indexes(
1475        &self,
1476        pubkey: &Pubkey,
1477        account_owner: &Pubkey,
1478        account_data: &[u8],
1479        account_indexes: &AccountSecondaryIndexes,
1480    ) {
1481        if account_indexes.is_empty() {
1482            return;
1483        }
1484
1485        if account_indexes.contains(&AccountIndex::ProgramId)
1486            && account_indexes.include_key(account_owner)
1487        {
1488            self.program_id_index.insert(account_owner, pubkey);
1489        }
1490        // Note because of the below check below on the account data length, when an
1491        // account hits zero carats and is reset to AccountSharedData::Default, then we skip
1492        // the below updates to the secondary indexes.
1493        //
1494        // Skipping means not updating secondary index to mark the account as missing.
1495        // This doesn't introduce false positives during a scan because the caller to scan
1496        // provides the ancestors to check. So even if a zero-carat account is not yet
1497        // removed from the secondary index, the scan function will:
1498        // 1) consult the primary index via `get(&pubkey, Some(ancestors), max_root)`
1499        // and find the zero-carat version
1500        // 2) When the fetch from storage occurs, it will return AccountSharedData::Default
1501        // (as persisted tombstone for snapshots). This will then ultimately be
1502        // filtered out by post-scan filters, like in `get_filtered_spl_token_accounts_by_owner()`.
1503        if *account_owner == inline_spl_token_v2_0::id()
1504            && account_data.len() == inline_spl_token_v2_0::state::Account::get_packed_len()
1505        {
1506            if account_indexes.contains(&AccountIndex::SplTokenOwner) {
1507                let owner_key = Pubkey::new(
1508                    &account_data[SPL_TOKEN_ACCOUNT_OWNER_OFFSET
1509                        ..SPL_TOKEN_ACCOUNT_OWNER_OFFSET + PUBKEY_BYTES],
1510                );
1511                if account_indexes.include_key(&owner_key) {
1512                    self.spl_token_owner_index.insert(&owner_key, pubkey);
1513                }
1514            }
1515
1516            if account_indexes.contains(&AccountIndex::SplTokenMint) {
1517                let mint_key = Pubkey::new(
1518                    &account_data[SPL_TOKEN_ACCOUNT_MINT_OFFSET
1519                        ..SPL_TOKEN_ACCOUNT_MINT_OFFSET + PUBKEY_BYTES],
1520                );
1521                if account_indexes.include_key(&mint_key) {
1522                    self.spl_token_mint_index.insert(&mint_key, pubkey);
1523                }
1524            }
1525        }
1526    }
1527
1528    fn get_account_maps_write_lock(&self, pubkey: &Pubkey) -> AccountMapsWriteLock<T> {
1529        self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)]
1530            .write()
1531            .unwrap()
1532    }
1533
1534    pub(crate) fn get_account_maps_read_lock(&self, pubkey: &Pubkey) -> AccountMapsReadLock<T> {
1535        self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)]
1536            .read()
1537            .unwrap()
1538    }
1539
1540    pub fn bins(&self) -> usize {
1541        self.account_maps.len()
1542    }
1543
1544    // Same functionally to upsert, but:
1545    // 1. operates on a batch of items
1546    // 2. holds the write lock for the duration of adding the items
1547    // Can save time when inserting lots of new keys.
1548    // But, does NOT update secondary index
1549    // This is designed to be called at startup time.
1550    #[allow(clippy::needless_collect)]
1551    pub(crate) fn insert_new_if_missing_into_primary_index(
1552        &self,
1553        slot: Slot,
1554        item_len: usize,
1555        items: impl Iterator<Item = (Pubkey, T)>,
1556    ) -> (Vec<Pubkey>, u64) {
1557        // big enough so not likely to re-allocate, small enough to not over-allocate by too much
1558        // this assumes the largest bin contains twice the expected amount of the average size per bin
1559        let bins = self.bins();
1560        let expected_items_per_bin = item_len * 2 / bins;
1561        // offset bin 0 in the 'binned' array by a random amount.
1562        // This results in calls to insert_new_entry_if_missing_with_lock from different threads starting at different bins.
1563        let random_offset = thread_rng().gen_range(0, bins);
1564        let mut binned = (0..bins)
1565            .into_iter()
1566            .map(|mut pubkey_bin| {
1567                // opposite of (pubkey_bin + random_offset) % bins
1568                pubkey_bin = if pubkey_bin < random_offset {
1569                    pubkey_bin + bins - random_offset
1570                } else {
1571                    pubkey_bin - random_offset
1572                };
1573                (pubkey_bin, Vec::with_capacity(expected_items_per_bin))
1574            })
1575            .collect::<Vec<_>>();
1576        let mut dirty_pubkeys = items
1577            .filter_map(|(pubkey, account_info)| {
1578                let pubkey_bin = self.bin_calculator.bin_from_pubkey(&pubkey);
1579                let binned_index = (pubkey_bin + random_offset) % bins;
1580                // this value is equivalent to what update() below would have created if we inserted a new item
1581                let is_zero_carat = account_info.is_zero_carat();
1582                let result = if is_zero_carat { Some(pubkey) } else { None };
1583
1584                let info =
1585                    PreAllocatedAccountMapEntry::new(slot, account_info, &self.storage.storage);
1586                binned[binned_index].1.push((pubkey, info));
1587                result
1588            })
1589            .collect::<Vec<_>>();
1590        binned.retain(|x| !x.1.is_empty());
1591
1592        let insertion_time = AtomicU64::new(0);
1593
1594        binned.into_iter().for_each(|(pubkey_bin, items)| {
1595            let mut _reclaims = SlotList::new();
1596
1597            // big enough so not likely to re-allocate, small enough to not over-allocate by too much
1598            // this assumes 10% of keys are duplicates. This vector will be flattened below.
1599            let w_account_maps = self.account_maps[pubkey_bin].write().unwrap();
1600            let mut insert_time = Measure::start("insert_into_primary_index");
1601            items.into_iter().for_each(|(pubkey, new_item)| {
1602                let already_exists =
1603                    w_account_maps.insert_new_entry_if_missing_with_lock(pubkey, new_item);
1604                if let Some((account_entry, account_info, pubkey)) = already_exists {
1605                    let is_zero_carat = account_info.is_zero_carat();
1606                    InMemAccountsIndex::lock_and_update_slot_list(
1607                        &account_entry,
1608                        (slot, account_info),
1609                        &mut _reclaims,
1610                        false,
1611                    );
1612
1613                    if !is_zero_carat {
1614                        // zero carats were already added to dirty_pubkeys above
1615                        dirty_pubkeys.push(pubkey);
1616                    }
1617                }
1618            });
1619            insert_time.stop();
1620            insertion_time.fetch_add(insert_time.as_us(), Ordering::Relaxed);
1621        });
1622
1623        (dirty_pubkeys, insertion_time.load(Ordering::Relaxed))
1624    }
1625
1626    // Updates the given pubkey at the given slot with the new account information.
1627    // Returns true if the pubkey was newly inserted into the index, otherwise, if the
1628    // pubkey updates an existing entry in the index, returns false.
1629    pub fn upsert(
1630        &self,
1631        slot: Slot,
1632        pubkey: &Pubkey,
1633        account_owner: &Pubkey,
1634        account_data: &[u8],
1635        account_indexes: &AccountSecondaryIndexes,
1636        account_info: T,
1637        reclaims: &mut SlotList<T>,
1638        previous_slot_entry_was_cached: bool,
1639    ) {
1640        // We don't atomically update both primary index and secondary index together.
1641        // This certainly creates a small time window with inconsistent state across the two indexes.
1642        // However, this is acceptable because:
1643        //
1644        //  - A strict consistent view at any given moment of time is not necessary, because the only
1645        //  use case for the secondary index is `scan`, and `scans` are only supported/require consistency
1646        //  on frozen banks, and this inconsistency is only possible on working banks.
1647        //
1648        //  - The secondary index is never consulted as primary source of truth for gets/stores.
1649        //  So, what the accounts_index sees alone is sufficient as a source of truth for other non-scan
1650        //  account operations.
1651        let new_item = PreAllocatedAccountMapEntry::new(slot, account_info, &self.storage.storage);
1652        let map = &self.account_maps[self.bin_calculator.bin_from_pubkey(pubkey)];
1653
1654        {
1655            let r_account_maps = map.read().unwrap();
1656            r_account_maps.upsert(pubkey, new_item, reclaims, previous_slot_entry_was_cached);
1657        }
1658        self.update_secondary_indexes(pubkey, account_owner, account_data, account_indexes);
1659    }
1660
1661    pub fn unref_from_storage(&self, pubkey: &Pubkey) {
1662        if let Some(locked_entry) = self.get_account_read_entry(pubkey) {
1663            locked_entry.unref();
1664        }
1665    }
1666
1667    pub fn ref_count_from_storage(&self, pubkey: &Pubkey) -> RefCount {
1668        if let Some(locked_entry) = self.get_account_read_entry(pubkey) {
1669            locked_entry.ref_count()
1670        } else {
1671            0
1672        }
1673    }
1674
1675    fn purge_secondary_indexes_by_inner_key<'a>(
1676        &'a self,
1677        inner_key: &Pubkey,
1678        account_indexes: &AccountSecondaryIndexes,
1679    ) {
1680        if account_indexes.contains(&AccountIndex::ProgramId) {
1681            self.program_id_index.remove_by_inner_key(inner_key);
1682        }
1683
1684        if account_indexes.contains(&AccountIndex::SplTokenOwner) {
1685            self.spl_token_owner_index.remove_by_inner_key(inner_key);
1686        }
1687
1688        if account_indexes.contains(&AccountIndex::SplTokenMint) {
1689            self.spl_token_mint_index.remove_by_inner_key(inner_key);
1690        }
1691    }
1692
1693    fn purge_older_root_entries(
1694        &self,
1695        slot_list: &mut SlotList<T>,
1696        reclaims: &mut SlotList<T>,
1697        max_clean_root: Option<Slot>,
1698    ) {
1699        let roots_tracker = &self.roots_tracker.read().unwrap();
1700        let newest_root_in_slot_list =
1701            Self::get_newest_root_in_slot_list(&roots_tracker.roots, slot_list, max_clean_root);
1702        let max_clean_root = max_clean_root.unwrap_or(roots_tracker.max_root);
1703
1704        slot_list.retain(|(slot, value)| {
1705            let should_purge =
1706                Self::can_purge_older_entries(max_clean_root, newest_root_in_slot_list, *slot)
1707                    && !value.is_cached();
1708            if should_purge {
1709                reclaims.push((*slot, *value));
1710            }
1711            !should_purge
1712        });
1713    }
1714
1715    pub fn clean_rooted_entries(
1716        &self,
1717        pubkey: &Pubkey,
1718        reclaims: &mut SlotList<T>,
1719        max_clean_root: Option<Slot>,
1720    ) {
1721        let mut is_slot_list_empty = false;
1722        if let Some(mut locked_entry) = self.get_account_write_entry(pubkey) {
1723            locked_entry.slot_list_mut(|slot_list| {
1724                self.purge_older_root_entries(slot_list, reclaims, max_clean_root);
1725                is_slot_list_empty = slot_list.is_empty();
1726            });
1727        }
1728
1729        // If the slot list is empty, remove the pubkey from `account_maps`.  Make sure to grab the
1730        // lock and double check the slot list is still empty, because another writer could have
1731        // locked and inserted the pubkey inbetween when `is_slot_list_empty=true` and the call to
1732        // remove() below.
1733        if is_slot_list_empty {
1734            let w_maps = self.get_account_maps_write_lock(pubkey);
1735            w_maps.remove_if_slot_list_empty(*pubkey);
1736        }
1737    }
1738
1739    /// When can an entry be purged?
1740    ///
1741    /// If we get a slot update where slot != newest_root_in_slot_list for an account where slot <
1742    /// max_clean_root, then we know it's safe to delete because:
1743    ///
1744    /// a) If slot < newest_root_in_slot_list, then we know the update is outdated by a later rooted
1745    /// update, namely the one in newest_root_in_slot_list
1746    ///
1747    /// b) If slot > newest_root_in_slot_list, then because slot < max_clean_root and we know there are
1748    /// no roots in the slot list between newest_root_in_slot_list and max_clean_root, (otherwise there
1749    /// would be a bigger newest_root_in_slot_list, which is a contradiction), then we know slot must be
1750    /// an unrooted slot less than max_clean_root and thus safe to clean as well.
1751    fn can_purge_older_entries(
1752        max_clean_root: Slot,
1753        newest_root_in_slot_list: Slot,
1754        slot: Slot,
1755    ) -> bool {
1756        slot < max_clean_root && slot != newest_root_in_slot_list
1757    }
1758
1759    /// Given a list of slots, return a new list of only the slots that are rooted
1760    pub fn get_rooted_from_list<'a>(&self, slots: impl Iterator<Item = &'a Slot>) -> Vec<Slot> {
1761        let roots_tracker = self.roots_tracker.read().unwrap();
1762        slots
1763            .filter_map(|s| {
1764                if roots_tracker.roots.contains(s) {
1765                    Some(*s)
1766                } else {
1767                    None
1768                }
1769            })
1770            .collect()
1771    }
1772
1773    pub fn is_root(&self, slot: Slot) -> bool {
1774        self.roots_tracker.read().unwrap().roots.contains(&slot)
1775    }
1776
1777    pub fn add_root(&self, slot: Slot, caching_enabled: bool) {
1778        let mut w_roots_tracker = self.roots_tracker.write().unwrap();
1779        w_roots_tracker.roots.insert(slot);
1780        // we delay cleaning until flushing!
1781        if !caching_enabled {
1782            w_roots_tracker.uncleaned_roots.insert(slot);
1783        }
1784        // `AccountsDb::flush_accounts_cache()` relies on roots being added in order
1785        assert!(slot >= w_roots_tracker.max_root);
1786        w_roots_tracker.max_root = slot;
1787    }
1788
1789    pub fn add_uncleaned_roots<I>(&self, roots: I)
1790    where
1791        I: IntoIterator<Item = Slot>,
1792    {
1793        let mut w_roots_tracker = self.roots_tracker.write().unwrap();
1794        w_roots_tracker.uncleaned_roots.extend(roots);
1795    }
1796
1797    pub fn max_root(&self) -> Slot {
1798        self.roots_tracker.read().unwrap().max_root
1799    }
1800
1801    /// Remove the slot when the storage for the slot is freed
1802    /// Accounts no longer reference this slot.
1803    pub fn clean_dead_slot(&self, slot: Slot) -> Option<AccountsIndexRootsStats> {
1804        let (roots_len, uncleaned_roots_len, previous_uncleaned_roots_len, roots_range) = {
1805            let mut w_roots_tracker = self.roots_tracker.write().unwrap();
1806            let removed_from_unclean_roots = w_roots_tracker.uncleaned_roots.remove(&slot);
1807            let removed_from_previous_uncleaned_roots =
1808                w_roots_tracker.previous_uncleaned_roots.remove(&slot);
1809            if !w_roots_tracker.roots.remove(&slot) {
1810                if removed_from_unclean_roots {
1811                    error!("clean_dead_slot-removed_from_unclean_roots: {}", slot);
1812                    inc_new_counter_error!("clean_dead_slot-removed_from_unclean_roots", 1, 1);
1813                }
1814                if removed_from_previous_uncleaned_roots {
1815                    error!(
1816                        "clean_dead_slot-removed_from_previous_uncleaned_roots: {}",
1817                        slot
1818                    );
1819                    inc_new_counter_error!(
1820                        "clean_dead_slot-removed_from_previous_uncleaned_roots",
1821                        1,
1822                        1
1823                    );
1824                }
1825                return None;
1826            }
1827            (
1828                w_roots_tracker.roots.len(),
1829                w_roots_tracker.uncleaned_roots.len(),
1830                w_roots_tracker.previous_uncleaned_roots.len(),
1831                w_roots_tracker.roots.range_width(),
1832            )
1833        };
1834        Some(AccountsIndexRootsStats {
1835            roots_len,
1836            uncleaned_roots_len,
1837            previous_uncleaned_roots_len,
1838            roots_range,
1839            rooted_cleaned_count: 0,
1840            unrooted_cleaned_count: 0,
1841        })
1842    }
1843
1844    pub fn min_root(&self) -> Option<Slot> {
1845        self.roots_tracker.read().unwrap().min_root()
1846    }
1847
1848    pub fn reset_uncleaned_roots(&self, max_clean_root: Option<Slot>) -> HashSet<Slot> {
1849        let mut cleaned_roots = HashSet::new();
1850        let mut w_roots_tracker = self.roots_tracker.write().unwrap();
1851        w_roots_tracker.uncleaned_roots.retain(|root| {
1852            let is_cleaned = max_clean_root
1853                .map(|max_clean_root| *root <= max_clean_root)
1854                .unwrap_or(true);
1855            if is_cleaned {
1856                cleaned_roots.insert(*root);
1857            }
1858            // Only keep the slots that have yet to be cleaned
1859            !is_cleaned
1860        });
1861        std::mem::replace(&mut w_roots_tracker.previous_uncleaned_roots, cleaned_roots)
1862    }
1863
1864    #[cfg(test)]
1865    pub fn clear_uncleaned_roots(&self, max_clean_root: Option<Slot>) -> HashSet<Slot> {
1866        let mut cleaned_roots = HashSet::new();
1867        let mut w_roots_tracker = self.roots_tracker.write().unwrap();
1868        w_roots_tracker.uncleaned_roots.retain(|root| {
1869            let is_cleaned = max_clean_root
1870                .map(|max_clean_root| *root <= max_clean_root)
1871                .unwrap_or(true);
1872            if is_cleaned {
1873                cleaned_roots.insert(*root);
1874            }
1875            // Only keep the slots that have yet to be cleaned
1876            !is_cleaned
1877        });
1878        cleaned_roots
1879    }
1880
1881    pub fn is_uncleaned_root(&self, slot: Slot) -> bool {
1882        self.roots_tracker
1883            .read()
1884            .unwrap()
1885            .uncleaned_roots
1886            .contains(&slot)
1887    }
1888
1889    pub fn num_roots(&self) -> usize {
1890        self.roots_tracker.read().unwrap().roots.len()
1891    }
1892
1893    pub fn all_roots(&self) -> Vec<Slot> {
1894        let tracker = self.roots_tracker.read().unwrap();
1895        tracker.roots.get_all()
1896    }
1897
1898    #[cfg(test)]
1899    pub fn clear_roots(&self) {
1900        self.roots_tracker.write().unwrap().roots.clear()
1901    }
1902
1903    #[cfg(test)]
1904    pub fn uncleaned_roots_len(&self) -> usize {
1905        self.roots_tracker.read().unwrap().uncleaned_roots.len()
1906    }
1907
1908    #[cfg(test)]
1909    // filter any rooted entries and return them along with a bool that indicates
1910    // if this account has no more entries. Note this does not update the secondary
1911    // indexes!
1912    pub fn purge_roots(&self, pubkey: &Pubkey) -> (SlotList<T>, bool) {
1913        let mut write_account_map_entry = self.get_account_write_entry(pubkey).unwrap();
1914        write_account_map_entry.slot_list_mut(|slot_list| {
1915            let reclaims = self.get_rooted_entries(slot_list, None);
1916            slot_list.retain(|(slot, _)| !self.is_root(*slot));
1917            (reclaims, slot_list.is_empty())
1918        })
1919    }
1920}
1921
1922#[cfg(test)]
1923pub mod tests {
1924    use super::*;
1925    use gemachain_sdk::signature::{Keypair, Signer};
1926    use std::ops::RangeInclusive;
1927
1928    pub enum SecondaryIndexTypes<'a> {
1929        RwLock(&'a SecondaryIndex<RwLockSecondaryIndexEntry>),
1930        DashMap(&'a SecondaryIndex<DashMapSecondaryIndexEntry>),
1931    }
1932
1933    pub fn spl_token_mint_index_enabled() -> AccountSecondaryIndexes {
1934        let mut account_indexes = HashSet::new();
1935        account_indexes.insert(AccountIndex::SplTokenMint);
1936        AccountSecondaryIndexes {
1937            indexes: account_indexes,
1938            keys: None,
1939        }
1940    }
1941
1942    pub fn spl_token_owner_index_enabled() -> AccountSecondaryIndexes {
1943        let mut account_indexes = HashSet::new();
1944        account_indexes.insert(AccountIndex::SplTokenOwner);
1945        AccountSecondaryIndexes {
1946            indexes: account_indexes,
1947            keys: None,
1948        }
1949    }
1950
1951    impl<'a, T: IndexValue> AccountIndexGetResult<'a, T> {
1952        pub fn unwrap(self) -> (ReadAccountMapEntry<T>, usize) {
1953            match self {
1954                AccountIndexGetResult::Found(lock, size) => (lock, size),
1955                _ => {
1956                    panic!("trying to unwrap AccountIndexGetResult with non-Success result");
1957                }
1958            }
1959        }
1960
1961        pub fn is_none(&self) -> bool {
1962            !self.is_some()
1963        }
1964
1965        pub fn is_some(&self) -> bool {
1966            matches!(self, AccountIndexGetResult::Found(_lock, _size))
1967        }
1968
1969        pub fn map<V, F: FnOnce((ReadAccountMapEntry<T>, usize)) -> V>(self, f: F) -> Option<V> {
1970            match self {
1971                AccountIndexGetResult::Found(lock, size) => Some(f((lock, size))),
1972                _ => None,
1973            }
1974        }
1975    }
1976
1977    fn create_dashmap_secondary_index_state() -> (usize, usize, AccountSecondaryIndexes) {
1978        {
1979            // Check that we're actually testing the correct variant
1980            let index = AccountsIndex::<bool>::default_for_tests();
1981            let _type_check = SecondaryIndexTypes::DashMap(&index.spl_token_mint_index);
1982        }
1983
1984        (0, PUBKEY_BYTES, spl_token_mint_index_enabled())
1985    }
1986
1987    fn create_rwlock_secondary_index_state() -> (usize, usize, AccountSecondaryIndexes) {
1988        {
1989            // Check that we're actually testing the correct variant
1990            let index = AccountsIndex::<bool>::default_for_tests();
1991            let _type_check = SecondaryIndexTypes::RwLock(&index.spl_token_owner_index);
1992        }
1993
1994        (
1995            SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
1996            SPL_TOKEN_ACCOUNT_OWNER_OFFSET + PUBKEY_BYTES,
1997            spl_token_owner_index_enabled(),
1998        )
1999    }
2000
2001    impl<T: IndexValue> Clone for PreAllocatedAccountMapEntry<T> {
2002        fn clone(&self) -> Self {
2003            // clone the AccountMapEntryInner into a new Arc
2004            let (slot, info) = self.entry.slot_list.read().unwrap()[0];
2005            let meta = AccountMapEntryMeta {
2006                dirty: AtomicBool::new(self.entry.dirty()),
2007                age: AtomicU8::new(self.entry.age()),
2008            };
2009            PreAllocatedAccountMapEntry::new_internal(slot, info, meta)
2010        }
2011    }
2012
2013    #[test]
2014    fn test_bitfield_delete_non_excess() {
2015        gemachain_logger::setup();
2016        let len = 16;
2017        let mut bitfield = RollingBitField::new(len);
2018        assert_eq!(bitfield.min(), None);
2019
2020        bitfield.insert(0);
2021        assert_eq!(bitfield.min(), Some(0));
2022        let too_big = len + 1;
2023        bitfield.insert(too_big);
2024        assert!(bitfield.contains(&0));
2025        assert!(bitfield.contains(&too_big));
2026        assert_eq!(bitfield.len(), 2);
2027        assert_eq!(bitfield.excess.len(), 1);
2028        assert_eq!(bitfield.min, too_big);
2029        assert_eq!(bitfield.min(), Some(0));
2030        assert_eq!(bitfield.max, too_big + 1);
2031
2032        // delete the thing that is NOT in excess
2033        bitfield.remove(&too_big);
2034        assert_eq!(bitfield.min, too_big + 1);
2035        assert_eq!(bitfield.max, too_big + 1);
2036        let too_big_times_2 = too_big * 2;
2037        bitfield.insert(too_big_times_2);
2038        assert!(bitfield.contains(&0));
2039        assert!(bitfield.contains(&too_big_times_2));
2040        assert_eq!(bitfield.len(), 2);
2041        assert_eq!(bitfield.excess.len(), 1);
2042        assert_eq!(bitfield.min(), bitfield.excess.iter().min().copied());
2043        assert_eq!(bitfield.min, too_big_times_2);
2044        assert_eq!(bitfield.max, too_big_times_2 + 1);
2045
2046        bitfield.remove(&0);
2047        bitfield.remove(&too_big_times_2);
2048        assert!(bitfield.is_empty());
2049        let other = 5;
2050        bitfield.insert(other);
2051        assert!(bitfield.contains(&other));
2052        assert!(bitfield.excess.is_empty());
2053        assert_eq!(bitfield.min, other);
2054        assert_eq!(bitfield.max, other + 1);
2055    }
2056
2057    #[test]
2058    fn test_bitfield_insert_excess() {
2059        gemachain_logger::setup();
2060        let len = 16;
2061        let mut bitfield = RollingBitField::new(len);
2062
2063        bitfield.insert(0);
2064        let too_big = len + 1;
2065        bitfield.insert(too_big);
2066        assert!(bitfield.contains(&0));
2067        assert!(bitfield.contains(&too_big));
2068        assert_eq!(bitfield.len(), 2);
2069        assert_eq!(bitfield.excess.len(), 1);
2070        assert!(bitfield.excess.contains(&0));
2071        assert_eq!(bitfield.min, too_big);
2072        assert_eq!(bitfield.max, too_big + 1);
2073
2074        // delete the thing that IS in excess
2075        // this does NOT affect min/max
2076        bitfield.remove(&0);
2077        assert_eq!(bitfield.min, too_big);
2078        assert_eq!(bitfield.max, too_big + 1);
2079        // re-add to excess
2080        bitfield.insert(0);
2081        assert!(bitfield.contains(&0));
2082        assert!(bitfield.contains(&too_big));
2083        assert_eq!(bitfield.len(), 2);
2084        assert_eq!(bitfield.excess.len(), 1);
2085        assert_eq!(bitfield.min, too_big);
2086        assert_eq!(bitfield.max, too_big + 1);
2087    }
2088
2089    #[test]
2090    fn test_bitfield_permutations() {
2091        gemachain_logger::setup();
2092        let mut bitfield = RollingBitField::new(2097152);
2093        let mut hash = HashSet::new();
2094
2095        let min = 101_000;
2096        let width = 400_000;
2097        let dead = 19;
2098
2099        let mut slot = min;
2100        while hash.len() < width {
2101            slot += 1;
2102            if slot % dead == 0 {
2103                continue;
2104            }
2105            hash.insert(slot);
2106            bitfield.insert(slot);
2107        }
2108        compare(&hash, &bitfield);
2109
2110        let max = slot + 1;
2111
2112        let mut time = Measure::start("");
2113        let mut count = 0;
2114        for slot in (min - 10)..max + 100 {
2115            if hash.contains(&slot) {
2116                count += 1;
2117            }
2118        }
2119        time.stop();
2120
2121        let mut time2 = Measure::start("");
2122        let mut count2 = 0;
2123        for slot in (min - 10)..max + 100 {
2124            if bitfield.contains(&slot) {
2125                count2 += 1;
2126            }
2127        }
2128        time2.stop();
2129        info!(
2130            "{}ms, {}ms, {} ratio",
2131            time.as_ms(),
2132            time2.as_ms(),
2133            time.as_ns() / time2.as_ns()
2134        );
2135        assert_eq!(count, count2);
2136    }
2137
2138    #[test]
2139    #[should_panic(expected = "assertion failed: max_width.is_power_of_two()")]
2140    fn test_bitfield_power_2() {
2141        let _ = RollingBitField::new(3);
2142    }
2143
2144    #[test]
2145    #[should_panic(expected = "assertion failed: max_width > 0")]
2146    fn test_bitfield_0() {
2147        let _ = RollingBitField::new(0);
2148    }
2149
2150    fn setup_empty(width: u64) -> RollingBitFieldTester {
2151        let bitfield = RollingBitField::new(width);
2152        let hash_set = HashSet::new();
2153        RollingBitFieldTester { bitfield, hash_set }
2154    }
2155
2156    struct RollingBitFieldTester {
2157        pub bitfield: RollingBitField,
2158        pub hash_set: HashSet<u64>,
2159    }
2160
2161    impl RollingBitFieldTester {
2162        fn insert(&mut self, slot: u64) {
2163            self.bitfield.insert(slot);
2164            self.hash_set.insert(slot);
2165            assert!(self.bitfield.contains(&slot));
2166            compare(&self.hash_set, &self.bitfield);
2167        }
2168        fn remove(&mut self, slot: &u64) -> bool {
2169            let result = self.bitfield.remove(slot);
2170            assert_eq!(result, self.hash_set.remove(slot));
2171            assert!(!self.bitfield.contains(slot));
2172            self.compare();
2173            result
2174        }
2175        fn compare(&self) {
2176            compare(&self.hash_set, &self.bitfield);
2177        }
2178    }
2179
2180    fn setup_wide(width: u64, start: u64) -> RollingBitFieldTester {
2181        let mut tester = setup_empty(width);
2182
2183        tester.compare();
2184        tester.insert(start);
2185        tester.insert(start + 1);
2186        tester
2187    }
2188
2189    #[test]
2190    fn test_bitfield_insert_wide() {
2191        gemachain_logger::setup();
2192        let width = 16;
2193        let start = 0;
2194        let mut tester = setup_wide(width, start);
2195
2196        let slot = start + width;
2197        let all = tester.bitfield.get_all();
2198        // higher than max range by 1
2199        tester.insert(slot);
2200        let bitfield = tester.bitfield;
2201        for slot in all {
2202            assert!(bitfield.contains(&slot));
2203        }
2204        assert_eq!(bitfield.excess.len(), 1);
2205        assert_eq!(bitfield.count, 3);
2206    }
2207
2208    #[test]
2209    fn test_bitfield_insert_wide_before() {
2210        gemachain_logger::setup();
2211        let width = 16;
2212        let start = 100;
2213        let mut bitfield = setup_wide(width, start).bitfield;
2214
2215        let slot = start + 1 - width;
2216        // assert here - would make min too low, causing too wide of a range
2217        bitfield.insert(slot);
2218        assert_eq!(1, bitfield.excess.len());
2219        assert_eq!(3, bitfield.count);
2220        assert!(bitfield.contains(&slot));
2221    }
2222
2223    #[test]
2224    fn test_bitfield_insert_wide_before_ok() {
2225        gemachain_logger::setup();
2226        let width = 16;
2227        let start = 100;
2228        let mut bitfield = setup_wide(width, start).bitfield;
2229
2230        let slot = start + 2 - width; // this item would make our width exactly equal to what is allowed, but it is also inserting prior to min
2231        bitfield.insert(slot);
2232        assert_eq!(1, bitfield.excess.len());
2233        assert!(bitfield.contains(&slot));
2234        assert_eq!(3, bitfield.count);
2235    }
2236
2237    #[test]
2238    fn test_bitfield_contains_wide_no_assert() {
2239        {
2240            let width = 16;
2241            let start = 0;
2242            let bitfield = setup_wide(width, start).bitfield;
2243
2244            let mut slot = width;
2245            assert!(!bitfield.contains(&slot));
2246            slot += 1;
2247            assert!(!bitfield.contains(&slot));
2248        }
2249        {
2250            let width = 16;
2251            let start = 100;
2252            let bitfield = setup_wide(width, start).bitfield;
2253
2254            // too large
2255            let mut slot = width;
2256            assert!(!bitfield.contains(&slot));
2257            slot += 1;
2258            assert!(!bitfield.contains(&slot));
2259            // too small, before min
2260            slot = 0;
2261            assert!(!bitfield.contains(&slot));
2262        }
2263    }
2264
2265    #[test]
2266    fn test_bitfield_remove_wide() {
2267        let width = 16;
2268        let start = 0;
2269        let mut tester = setup_wide(width, start);
2270        let slot = width;
2271        assert!(!tester.remove(&slot));
2272    }
2273
2274    #[test]
2275    fn test_bitfield_excess2() {
2276        gemachain_logger::setup();
2277        let width = 16;
2278        let mut tester = setup_empty(width);
2279        let slot = 100;
2280        // insert 1st slot
2281        tester.insert(slot);
2282        assert!(tester.bitfield.excess.is_empty());
2283
2284        // insert a slot before the previous one. this is 'excess' since we don't use this pattern in normal operation
2285        let slot2 = slot - 1;
2286        tester.insert(slot2);
2287        assert_eq!(tester.bitfield.excess.len(), 1);
2288
2289        // remove the 1st slot. we will be left with only excess
2290        tester.remove(&slot);
2291        assert!(tester.bitfield.contains(&slot2));
2292        assert_eq!(tester.bitfield.excess.len(), 1);
2293
2294        // re-insert at valid range, making sure we don't insert into excess
2295        tester.insert(slot);
2296        assert_eq!(tester.bitfield.excess.len(), 1);
2297
2298        // remove the excess slot.
2299        tester.remove(&slot2);
2300        assert!(tester.bitfield.contains(&slot));
2301        assert!(tester.bitfield.excess.is_empty());
2302
2303        // re-insert the excess slot
2304        tester.insert(slot2);
2305        assert_eq!(tester.bitfield.excess.len(), 1);
2306    }
2307
2308    #[test]
2309    fn test_bitfield_excess() {
2310        gemachain_logger::setup();
2311        // start at slot 0 or a separate, higher slot
2312        for width in [16, 4194304].iter() {
2313            let width = *width;
2314            let mut tester = setup_empty(width);
2315            for start in [0, width * 5].iter().cloned() {
2316                // recreate means create empty bitfield with each iteration, otherwise re-use
2317                for recreate in [false, true].iter().cloned() {
2318                    let max = start + 3;
2319                    // first root to add
2320                    for slot in start..max {
2321                        // subsequent roots to add
2322                        for slot2 in (slot + 1)..max {
2323                            // reverse_slots = 1 means add slots in reverse order (max to min). This causes us to add second and later slots to excess.
2324                            for reverse_slots in [false, true].iter().cloned() {
2325                                let maybe_reverse = |slot| {
2326                                    if reverse_slots {
2327                                        max - slot
2328                                    } else {
2329                                        slot
2330                                    }
2331                                };
2332                                if recreate {
2333                                    let recreated = setup_empty(width);
2334                                    tester = recreated;
2335                                }
2336
2337                                // insert
2338                                for slot in slot..=slot2 {
2339                                    let slot_use = maybe_reverse(slot);
2340                                    tester.insert(slot_use);
2341                                    debug!(
2342                                    "slot: {}, bitfield: {:?}, reverse: {}, len: {}, excess: {:?}",
2343                                    slot_use,
2344                                    tester.bitfield,
2345                                    reverse_slots,
2346                                    tester.bitfield.len(),
2347                                    tester.bitfield.excess
2348                                );
2349                                    assert!(
2350                                        (reverse_slots && tester.bitfield.len() > 1)
2351                                            ^ tester.bitfield.excess.is_empty()
2352                                    );
2353                                }
2354                                if start > width * 2 {
2355                                    assert!(!tester.bitfield.contains(&(start - width * 2)));
2356                                }
2357                                assert!(!tester.bitfield.contains(&(start + width * 2)));
2358                                let len = (slot2 - slot + 1) as usize;
2359                                assert_eq!(tester.bitfield.len(), len);
2360                                assert_eq!(tester.bitfield.count, len);
2361
2362                                // remove
2363                                for slot in slot..=slot2 {
2364                                    let slot_use = maybe_reverse(slot);
2365                                    assert!(tester.remove(&slot_use));
2366                                    assert!(
2367                                        (reverse_slots && !tester.bitfield.is_empty())
2368                                            ^ tester.bitfield.excess.is_empty()
2369                                    );
2370                                }
2371                                assert!(tester.bitfield.is_empty());
2372                                assert_eq!(tester.bitfield.count, 0);
2373                                if start > width * 2 {
2374                                    assert!(!tester.bitfield.contains(&(start - width * 2)));
2375                                }
2376                                assert!(!tester.bitfield.contains(&(start + width * 2)));
2377                            }
2378                        }
2379                    }
2380                }
2381            }
2382        }
2383    }
2384
2385    #[test]
2386    fn test_bitfield_remove_wide_before() {
2387        let width = 16;
2388        let start = 100;
2389        let mut tester = setup_wide(width, start);
2390        let slot = start + 1 - width;
2391        assert!(!tester.remove(&slot));
2392    }
2393
2394    fn compare_internal(hashset: &HashSet<u64>, bitfield: &RollingBitField) {
2395        assert_eq!(hashset.len(), bitfield.len());
2396        assert_eq!(hashset.is_empty(), bitfield.is_empty());
2397        if !bitfield.is_empty() {
2398            let mut min = Slot::MAX;
2399            let mut overall_min = Slot::MAX;
2400            let mut max = Slot::MIN;
2401            for item in bitfield.get_all() {
2402                assert!(hashset.contains(&item));
2403                if !bitfield.excess.contains(&item) {
2404                    min = std::cmp::min(min, item);
2405                    max = std::cmp::max(max, item);
2406                }
2407                overall_min = std::cmp::min(overall_min, item);
2408            }
2409            assert_eq!(bitfield.min(), Some(overall_min));
2410            assert_eq!(bitfield.get_all().len(), hashset.len());
2411            // range isn't tracked for excess items
2412            if bitfield.excess.len() != bitfield.len() {
2413                let width = if bitfield.is_empty() {
2414                    0
2415                } else {
2416                    max + 1 - min
2417                };
2418                assert!(
2419                    bitfield.range_width() >= width,
2420                    "hashset: {:?}, bitfield: {:?}, bitfield.range_width: {}, width: {}",
2421                    hashset,
2422                    bitfield.get_all(),
2423                    bitfield.range_width(),
2424                    width,
2425                );
2426            }
2427        } else {
2428            assert_eq!(bitfield.min(), None);
2429        }
2430    }
2431
2432    fn compare(hashset: &HashSet<u64>, bitfield: &RollingBitField) {
2433        compare_internal(hashset, bitfield);
2434        let clone = bitfield.clone();
2435        compare_internal(hashset, &clone);
2436        assert!(clone.eq(bitfield));
2437        assert_eq!(clone, *bitfield);
2438    }
2439
2440    #[test]
2441    fn test_bitfield_functionality() {
2442        gemachain_logger::setup();
2443
2444        // bitfield sizes are powers of 2, cycle through values of 1, 2, 4, .. 2^9
2445        for power in 0..10 {
2446            let max_bitfield_width = 2u64.pow(power) as u64;
2447            let width_iteration_max = if max_bitfield_width > 1 {
2448                // add up to 2 items so we can test out multiple items
2449                3
2450            } else {
2451                // 0 or 1 items is all we can fit with a width of 1 item
2452                2
2453            };
2454            for width in 0..width_iteration_max {
2455                let mut tester = setup_empty(max_bitfield_width);
2456
2457                let min = 101_000;
2458                let dead = 19;
2459
2460                let mut slot = min;
2461                while tester.hash_set.len() < width {
2462                    slot += 1;
2463                    if max_bitfield_width > 2 && slot % dead == 0 {
2464                        // with max_bitfield_width of 1 and 2, there is no room for dead slots
2465                        continue;
2466                    }
2467                    tester.insert(slot);
2468                }
2469                let max = slot + 1;
2470
2471                for slot in (min - 10)..max + 100 {
2472                    assert_eq!(
2473                        tester.bitfield.contains(&slot),
2474                        tester.hash_set.contains(&slot)
2475                    );
2476                }
2477
2478                if width > 0 {
2479                    assert!(tester.remove(&slot));
2480                    assert!(!tester.remove(&slot));
2481                }
2482
2483                let all = tester.bitfield.get_all();
2484
2485                // remove the rest, including a call that removes slot again
2486                for item in all.iter() {
2487                    assert!(tester.remove(item));
2488                    assert!(!tester.remove(item));
2489                }
2490
2491                let min = max + ((width * 2) as u64) + 3;
2492                let slot = min; // several widths past previous min
2493                let max = slot + 1;
2494                tester.insert(slot);
2495
2496                for slot in (min - 10)..max + 100 {
2497                    assert_eq!(
2498                        tester.bitfield.contains(&slot),
2499                        tester.hash_set.contains(&slot)
2500                    );
2501                }
2502            }
2503        }
2504    }
2505
2506    fn bitfield_insert_and_test(bitfield: &mut RollingBitField, slot: Slot) {
2507        let len = bitfield.len();
2508        let old_all = bitfield.get_all();
2509        let (new_min, new_max) = if bitfield.is_empty() {
2510            (slot, slot + 1)
2511        } else {
2512            (
2513                std::cmp::min(bitfield.min, slot),
2514                std::cmp::max(bitfield.max, slot + 1),
2515            )
2516        };
2517        bitfield.insert(slot);
2518        assert_eq!(bitfield.min, new_min);
2519        assert_eq!(bitfield.max, new_max);
2520        assert_eq!(bitfield.len(), len + 1);
2521        assert!(!bitfield.is_empty());
2522        assert!(bitfield.contains(&slot));
2523        // verify aliasing is what we expect
2524        assert!(bitfield.contains_assume_in_range(&(slot + bitfield.max_width)));
2525        let get_all = bitfield.get_all();
2526        old_all
2527            .into_iter()
2528            .for_each(|slot| assert!(get_all.contains(&slot)));
2529        assert!(get_all.contains(&slot));
2530        assert!(get_all.len() == len + 1);
2531    }
2532
2533    #[test]
2534    fn test_bitfield_clear() {
2535        let mut bitfield = RollingBitField::new(4);
2536        assert_eq!(bitfield.len(), 0);
2537        assert!(bitfield.is_empty());
2538        bitfield_insert_and_test(&mut bitfield, 0);
2539        bitfield.clear();
2540        assert_eq!(bitfield.len(), 0);
2541        assert!(bitfield.is_empty());
2542        assert!(bitfield.get_all().is_empty());
2543        bitfield_insert_and_test(&mut bitfield, 1);
2544        bitfield.clear();
2545        assert_eq!(bitfield.len(), 0);
2546        assert!(bitfield.is_empty());
2547        assert!(bitfield.get_all().is_empty());
2548        bitfield_insert_and_test(&mut bitfield, 4);
2549    }
2550
2551    #[test]
2552    fn test_bitfield_wrapping() {
2553        let mut bitfield = RollingBitField::new(4);
2554        assert_eq!(bitfield.len(), 0);
2555        assert!(bitfield.is_empty());
2556        bitfield_insert_and_test(&mut bitfield, 0);
2557        assert_eq!(bitfield.get_all(), vec![0]);
2558        bitfield_insert_and_test(&mut bitfield, 2);
2559        assert_eq!(bitfield.get_all(), vec![0, 2]);
2560        bitfield_insert_and_test(&mut bitfield, 3);
2561        bitfield.insert(3); // redundant insert
2562        assert_eq!(bitfield.get_all(), vec![0, 2, 3]);
2563        assert!(bitfield.remove(&0));
2564        assert!(!bitfield.remove(&0));
2565        assert_eq!(bitfield.min, 2);
2566        assert_eq!(bitfield.max, 4);
2567        assert_eq!(bitfield.len(), 2);
2568        assert!(!bitfield.remove(&0)); // redundant remove
2569        assert_eq!(bitfield.len(), 2);
2570        assert_eq!(bitfield.get_all(), vec![2, 3]);
2571        bitfield.insert(4); // wrapped around value - same bit as '0'
2572        assert_eq!(bitfield.min, 2);
2573        assert_eq!(bitfield.max, 5);
2574        assert_eq!(bitfield.len(), 3);
2575        assert_eq!(bitfield.get_all(), vec![2, 3, 4]);
2576        assert!(bitfield.remove(&2));
2577        assert_eq!(bitfield.min, 3);
2578        assert_eq!(bitfield.max, 5);
2579        assert_eq!(bitfield.len(), 2);
2580        assert_eq!(bitfield.get_all(), vec![3, 4]);
2581        assert!(bitfield.remove(&3));
2582        assert_eq!(bitfield.min, 4);
2583        assert_eq!(bitfield.max, 5);
2584        assert_eq!(bitfield.len(), 1);
2585        assert_eq!(bitfield.get_all(), vec![4]);
2586        assert!(bitfield.remove(&4));
2587        assert_eq!(bitfield.len(), 0);
2588        assert!(bitfield.is_empty());
2589        assert!(bitfield.get_all().is_empty());
2590        bitfield_insert_and_test(&mut bitfield, 8);
2591        assert!(bitfield.remove(&8));
2592        assert_eq!(bitfield.len(), 0);
2593        assert!(bitfield.is_empty());
2594        assert!(bitfield.get_all().is_empty());
2595        bitfield_insert_and_test(&mut bitfield, 9);
2596        assert!(bitfield.remove(&9));
2597        assert_eq!(bitfield.len(), 0);
2598        assert!(bitfield.is_empty());
2599        assert!(bitfield.get_all().is_empty());
2600    }
2601
2602    #[test]
2603    fn test_bitfield_smaller() {
2604        // smaller bitfield, fewer entries, including 0
2605        gemachain_logger::setup();
2606
2607        for width in 0..34 {
2608            let mut bitfield = RollingBitField::new(4096);
2609            let mut hash_set = HashSet::new();
2610
2611            let min = 1_010_000;
2612            let dead = 19;
2613
2614            let mut slot = min;
2615            while hash_set.len() < width {
2616                slot += 1;
2617                if slot % dead == 0 {
2618                    continue;
2619                }
2620                hash_set.insert(slot);
2621                bitfield.insert(slot);
2622            }
2623
2624            let max = slot + 1;
2625
2626            let mut time = Measure::start("");
2627            let mut count = 0;
2628            for slot in (min - 10)..max + 100 {
2629                if hash_set.contains(&slot) {
2630                    count += 1;
2631                }
2632            }
2633            time.stop();
2634
2635            let mut time2 = Measure::start("");
2636            let mut count2 = 0;
2637            for slot in (min - 10)..max + 100 {
2638                if bitfield.contains(&slot) {
2639                    count2 += 1;
2640                }
2641            }
2642            time2.stop();
2643            info!(
2644                "{}, {}, {}",
2645                time.as_ms(),
2646                time2.as_ms(),
2647                time.as_ns() / time2.as_ns()
2648            );
2649            assert_eq!(count, count2);
2650        }
2651    }
2652
2653    const COLLECT_ALL_UNSORTED_FALSE: bool = false;
2654
2655    #[test]
2656    fn test_get_empty() {
2657        let key = Keypair::new();
2658        let index = AccountsIndex::<bool>::default_for_tests();
2659        let ancestors = Ancestors::default();
2660        assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
2661        assert!(index.get(&key.pubkey(), None, None).is_none());
2662
2663        let mut num = 0;
2664        index.unchecked_scan_accounts(
2665            "",
2666            &ancestors,
2667            |_pubkey, _index| num += 1,
2668            COLLECT_ALL_UNSORTED_FALSE,
2669        );
2670        assert_eq!(num, 0);
2671    }
2672
2673    #[test]
2674    fn test_secondary_index_include_exclude() {
2675        let pk1 = Pubkey::new_unique();
2676        let pk2 = Pubkey::new_unique();
2677        let mut index = AccountSecondaryIndexes::default();
2678
2679        assert!(!index.contains(&AccountIndex::ProgramId));
2680        index.indexes.insert(AccountIndex::ProgramId);
2681        assert!(index.contains(&AccountIndex::ProgramId));
2682        assert!(index.include_key(&pk1));
2683        assert!(index.include_key(&pk2));
2684
2685        let exclude = false;
2686        index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2687            keys: [pk1].iter().cloned().collect::<HashSet<_>>(),
2688            exclude,
2689        });
2690        assert!(index.include_key(&pk1));
2691        assert!(!index.include_key(&pk2));
2692
2693        let exclude = true;
2694        index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2695            keys: [pk1].iter().cloned().collect::<HashSet<_>>(),
2696            exclude,
2697        });
2698        assert!(!index.include_key(&pk1));
2699        assert!(index.include_key(&pk2));
2700
2701        let exclude = true;
2702        index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2703            keys: [pk1, pk2].iter().cloned().collect::<HashSet<_>>(),
2704            exclude,
2705        });
2706        assert!(!index.include_key(&pk1));
2707        assert!(!index.include_key(&pk2));
2708
2709        let exclude = false;
2710        index.keys = Some(AccountSecondaryIndexesIncludeExclude {
2711            keys: [pk1, pk2].iter().cloned().collect::<HashSet<_>>(),
2712            exclude,
2713        });
2714        assert!(index.include_key(&pk1));
2715        assert!(index.include_key(&pk2));
2716    }
2717
2718    const UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE: bool = false;
2719
2720    #[test]
2721    fn test_insert_no_ancestors() {
2722        let key = Keypair::new();
2723        let index = AccountsIndex::<bool>::default_for_tests();
2724        let mut gc = Vec::new();
2725        index.upsert(
2726            0,
2727            &key.pubkey(),
2728            &Pubkey::default(),
2729            &[],
2730            &AccountSecondaryIndexes::default(),
2731            true,
2732            &mut gc,
2733            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2734        );
2735        assert!(gc.is_empty());
2736
2737        let ancestors = Ancestors::default();
2738        assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
2739        assert!(index.get(&key.pubkey(), None, None).is_none());
2740
2741        let mut num = 0;
2742        index.unchecked_scan_accounts(
2743            "",
2744            &ancestors,
2745            |_pubkey, _index| num += 1,
2746            COLLECT_ALL_UNSORTED_FALSE,
2747        );
2748        assert_eq!(num, 0);
2749    }
2750
2751    type AccountInfoTest = f64;
2752
2753    impl IndexValue for AccountInfoTest {}
2754    impl IsCached for AccountInfoTest {
2755        fn is_cached(&self) -> bool {
2756            true
2757        }
2758    }
2759
2760    impl ZeroCarat for AccountInfoTest {
2761        fn is_zero_carat(&self) -> bool {
2762            true
2763        }
2764    }
2765    #[test]
2766    fn test_insert_new_with_lock_no_ancestors() {
2767        let key = Keypair::new();
2768        let pubkey = &key.pubkey();
2769        let slot = 0;
2770
2771        let index = AccountsIndex::<bool>::default_for_tests();
2772        let account_info = true;
2773        let items = vec![(*pubkey, account_info)];
2774        index.insert_new_if_missing_into_primary_index(slot, items.len(), items.into_iter());
2775
2776        let mut ancestors = Ancestors::default();
2777        assert!(index.get(pubkey, Some(&ancestors), None).is_none());
2778        assert!(index.get(pubkey, None, None).is_none());
2779
2780        let mut num = 0;
2781        index.unchecked_scan_accounts(
2782            "",
2783            &ancestors,
2784            |_pubkey, _index| num += 1,
2785            COLLECT_ALL_UNSORTED_FALSE,
2786        );
2787        assert_eq!(num, 0);
2788        ancestors.insert(slot, 0);
2789        assert!(index.get(pubkey, Some(&ancestors), None).is_some());
2790        assert_eq!(index.ref_count_from_storage(pubkey), 1);
2791        index.unchecked_scan_accounts(
2792            "",
2793            &ancestors,
2794            |_pubkey, _index| num += 1,
2795            COLLECT_ALL_UNSORTED_FALSE,
2796        );
2797        assert_eq!(num, 1);
2798
2799        // not zero carats
2800        let index = AccountsIndex::<AccountInfoTest>::default_for_tests();
2801        let account_info: AccountInfoTest = 0 as AccountInfoTest;
2802        let items = vec![(*pubkey, account_info)];
2803        index.insert_new_if_missing_into_primary_index(slot, items.len(), items.into_iter());
2804
2805        let mut ancestors = Ancestors::default();
2806        assert!(index.get(pubkey, Some(&ancestors), None).is_none());
2807        assert!(index.get(pubkey, None, None).is_none());
2808
2809        let mut num = 0;
2810        index.unchecked_scan_accounts(
2811            "",
2812            &ancestors,
2813            |_pubkey, _index| num += 1,
2814            COLLECT_ALL_UNSORTED_FALSE,
2815        );
2816        assert_eq!(num, 0);
2817        ancestors.insert(slot, 0);
2818        assert!(index.get(pubkey, Some(&ancestors), None).is_some());
2819        assert_eq!(index.ref_count_from_storage(pubkey), 0); // cached, so 0
2820        index.unchecked_scan_accounts(
2821            "",
2822            &ancestors,
2823            |_pubkey, _index| num += 1,
2824            COLLECT_ALL_UNSORTED_FALSE,
2825        );
2826        assert_eq!(num, 1);
2827    }
2828
2829    #[test]
2830    fn test_new_entry() {
2831        let slot = 0;
2832        // account_info type that IS cached
2833        let account_info = AccountInfoTest::default();
2834        let index = AccountsIndex::default_for_tests();
2835
2836        let new_entry: AccountMapEntry<_> =
2837            PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage).into();
2838        assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 0);
2839        assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
2840        assert_eq!(
2841            new_entry.slot_list.read().unwrap().to_vec(),
2842            vec![(slot, account_info)]
2843        );
2844
2845        // account_info type that is NOT cached
2846        let account_info = true;
2847        let index = AccountsIndex::default_for_tests();
2848
2849        let new_entry: AccountMapEntry<_> =
2850            PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage).into();
2851        assert_eq!(new_entry.ref_count.load(Ordering::Relaxed), 1);
2852        assert_eq!(new_entry.slot_list.read().unwrap().capacity(), 1);
2853        assert_eq!(
2854            new_entry.slot_list.read().unwrap().to_vec(),
2855            vec![(slot, account_info)]
2856        );
2857    }
2858
2859    #[test]
2860    fn test_batch_insert() {
2861        let slot0 = 0;
2862        let key0 = Keypair::new().pubkey();
2863        let key1 = Keypair::new().pubkey();
2864
2865        let index = AccountsIndex::<bool>::default_for_tests();
2866        let account_infos = [true, false];
2867
2868        let items = vec![(key0, account_infos[0]), (key1, account_infos[1])];
2869        index.insert_new_if_missing_into_primary_index(slot0, items.len(), items.into_iter());
2870
2871        for (i, key) in [key0, key1].iter().enumerate() {
2872            let entry = index.get_account_read_entry(key).unwrap();
2873            assert_eq!(entry.ref_count(), 1);
2874            assert_eq!(entry.slot_list().to_vec(), vec![(slot0, account_infos[i]),]);
2875        }
2876    }
2877
2878    fn test_new_entry_code_paths_helper<T: IndexValue>(
2879        account_infos: [T; 2],
2880        is_cached: bool,
2881        upsert: bool,
2882    ) {
2883        let slot0 = 0;
2884        let slot1 = 1;
2885        let key = Keypair::new().pubkey();
2886
2887        let index = AccountsIndex::<T>::default_for_tests();
2888        let mut gc = Vec::new();
2889
2890        if upsert {
2891            // insert first entry for pubkey. This will use new_entry_after_update and not call update.
2892            index.upsert(
2893                slot0,
2894                &key,
2895                &Pubkey::default(),
2896                &[],
2897                &AccountSecondaryIndexes::default(),
2898                account_infos[0],
2899                &mut gc,
2900                UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2901            );
2902        } else {
2903            let items = vec![(key, account_infos[0])];
2904            index.insert_new_if_missing_into_primary_index(slot0, items.len(), items.into_iter());
2905        }
2906        assert!(gc.is_empty());
2907
2908        // verify the added entry matches expected
2909        {
2910            let entry = index.get_account_read_entry(&key).unwrap();
2911            assert_eq!(entry.ref_count(), if is_cached { 0 } else { 1 });
2912            let expected = vec![(slot0, account_infos[0])];
2913            assert_eq!(entry.slot_list().to_vec(), expected);
2914            let new_entry: AccountMapEntry<_> =
2915                PreAllocatedAccountMapEntry::new(slot0, account_infos[0], &index.storage.storage)
2916                    .into();
2917            assert_eq!(
2918                entry.slot_list().to_vec(),
2919                new_entry.slot_list.read().unwrap().to_vec(),
2920            );
2921        }
2922
2923        // insert second entry for pubkey. This will use update and NOT use new_entry_after_update.
2924        if upsert {
2925            index.upsert(
2926                slot1,
2927                &key,
2928                &Pubkey::default(),
2929                &[],
2930                &AccountSecondaryIndexes::default(),
2931                account_infos[1],
2932                &mut gc,
2933                UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2934            );
2935        } else {
2936            let items = vec![(key, account_infos[1])];
2937            index.insert_new_if_missing_into_primary_index(slot1, items.len(), items.into_iter());
2938        }
2939        assert!(gc.is_empty());
2940
2941        for lock in &[false, true] {
2942            let read_lock = if *lock {
2943                Some(index.get_account_maps_read_lock(&key))
2944            } else {
2945                None
2946            };
2947
2948            let entry = if *lock {
2949                index
2950                    .get_account_read_entry_with_lock(&key, read_lock.as_ref().unwrap())
2951                    .unwrap()
2952            } else {
2953                index.get_account_read_entry(&key).unwrap()
2954            };
2955
2956            assert_eq!(entry.ref_count(), if is_cached { 0 } else { 2 });
2957            assert_eq!(
2958                entry.slot_list().to_vec(),
2959                vec![(slot0, account_infos[0]), (slot1, account_infos[1])]
2960            );
2961
2962            let new_entry =
2963                PreAllocatedAccountMapEntry::new(slot1, account_infos[1], &index.storage.storage);
2964            assert_eq!(entry.slot_list()[1], new_entry.into());
2965        }
2966    }
2967
2968    #[test]
2969    fn test_new_entry_and_update_code_paths() {
2970        for is_upsert in &[false, true] {
2971            // account_info type that IS cached
2972            test_new_entry_code_paths_helper([1.0, 2.0], true, *is_upsert);
2973
2974            // account_info type that is NOT cached
2975            test_new_entry_code_paths_helper([true, false], false, *is_upsert);
2976        }
2977    }
2978
2979    #[test]
2980    fn test_insert_with_lock_no_ancestors() {
2981        let key = Keypair::new();
2982        let index = AccountsIndex::<bool>::default_for_tests();
2983        let slot = 0;
2984        let account_info = true;
2985
2986        let new_entry =
2987            PreAllocatedAccountMapEntry::new(slot, account_info, &index.storage.storage);
2988        assert_eq!(0, account_maps_len_expensive(&index));
2989        assert_eq!((slot, account_info), new_entry.clone().into());
2990
2991        assert_eq!(0, account_maps_len_expensive(&index));
2992        let w_account_maps = index.get_account_maps_write_lock(&key.pubkey());
2993        w_account_maps.upsert(
2994            &key.pubkey(),
2995            new_entry,
2996            &mut SlotList::default(),
2997            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
2998        );
2999        drop(w_account_maps);
3000        assert_eq!(1, account_maps_len_expensive(&index));
3001
3002        let mut ancestors = Ancestors::default();
3003        assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
3004        assert!(index.get(&key.pubkey(), None, None).is_none());
3005
3006        let mut num = 0;
3007        index.unchecked_scan_accounts(
3008            "",
3009            &ancestors,
3010            |_pubkey, _index| num += 1,
3011            COLLECT_ALL_UNSORTED_FALSE,
3012        );
3013        assert_eq!(num, 0);
3014        ancestors.insert(slot, 0);
3015        assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_some());
3016        index.unchecked_scan_accounts(
3017            "",
3018            &ancestors,
3019            |_pubkey, _index| num += 1,
3020            COLLECT_ALL_UNSORTED_FALSE,
3021        );
3022        assert_eq!(num, 1);
3023    }
3024
3025    #[test]
3026    fn test_insert_wrong_ancestors() {
3027        let key = Keypair::new();
3028        let index = AccountsIndex::<bool>::default_for_tests();
3029        let mut gc = Vec::new();
3030        index.upsert(
3031            0,
3032            &key.pubkey(),
3033            &Pubkey::default(),
3034            &[],
3035            &AccountSecondaryIndexes::default(),
3036            true,
3037            &mut gc,
3038            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3039        );
3040        assert!(gc.is_empty());
3041
3042        let ancestors = vec![(1, 1)].into_iter().collect();
3043        assert!(index.get(&key.pubkey(), Some(&ancestors), None).is_none());
3044
3045        let mut num = 0;
3046        index.unchecked_scan_accounts(
3047            "",
3048            &ancestors,
3049            |_pubkey, _index| num += 1,
3050            COLLECT_ALL_UNSORTED_FALSE,
3051        );
3052        assert_eq!(num, 0);
3053    }
3054
3055    #[test]
3056    fn test_insert_with_ancestors() {
3057        let key = Keypair::new();
3058        let index = AccountsIndex::<bool>::default_for_tests();
3059        let mut gc = Vec::new();
3060        index.upsert(
3061            0,
3062            &key.pubkey(),
3063            &Pubkey::default(),
3064            &[],
3065            &AccountSecondaryIndexes::default(),
3066            true,
3067            &mut gc,
3068            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3069        );
3070        assert!(gc.is_empty());
3071
3072        let ancestors = vec![(0, 0)].into_iter().collect();
3073        let (list, idx) = index.get(&key.pubkey(), Some(&ancestors), None).unwrap();
3074        assert_eq!(list.slot_list()[idx], (0, true));
3075
3076        let mut num = 0;
3077        let mut found_key = false;
3078        index.unchecked_scan_accounts(
3079            "",
3080            &ancestors,
3081            |pubkey, _index| {
3082                if pubkey == &key.pubkey() {
3083                    found_key = true
3084                };
3085                num += 1
3086            },
3087            COLLECT_ALL_UNSORTED_FALSE,
3088        );
3089        assert_eq!(num, 1);
3090        assert!(found_key);
3091    }
3092
3093    fn setup_accounts_index_keys(num_pubkeys: usize) -> (AccountsIndex<bool>, Vec<Pubkey>) {
3094        let index = AccountsIndex::<bool>::default_for_tests();
3095        let root_slot = 0;
3096
3097        let mut pubkeys: Vec<Pubkey> = std::iter::repeat_with(|| {
3098            let new_pubkey = gemachain_sdk::pubkey::new_rand();
3099            index.upsert(
3100                root_slot,
3101                &new_pubkey,
3102                &Pubkey::default(),
3103                &[],
3104                &AccountSecondaryIndexes::default(),
3105                true,
3106                &mut vec![],
3107                UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3108            );
3109            new_pubkey
3110        })
3111        .take(num_pubkeys.saturating_sub(1))
3112        .collect();
3113
3114        if num_pubkeys != 0 {
3115            pubkeys.push(Pubkey::default());
3116            index.upsert(
3117                root_slot,
3118                &Pubkey::default(),
3119                &Pubkey::default(),
3120                &[],
3121                &AccountSecondaryIndexes::default(),
3122                true,
3123                &mut vec![],
3124                UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3125            );
3126        }
3127
3128        index.add_root(root_slot, false);
3129
3130        (index, pubkeys)
3131    }
3132
3133    fn run_test_range(
3134        index: &AccountsIndex<bool>,
3135        pubkeys: &[Pubkey],
3136        start_bound: Bound<usize>,
3137        end_bound: Bound<usize>,
3138    ) {
3139        // Exclusive `index_start`
3140        let (pubkey_start, index_start) = match start_bound {
3141            Unbounded => (Unbounded, 0),
3142            Included(i) => (Included(pubkeys[i]), i),
3143            Excluded(i) => (Excluded(pubkeys[i]), i + 1),
3144        };
3145
3146        // Exclusive `index_end`
3147        let (pubkey_end, index_end) = match end_bound {
3148            Unbounded => (Unbounded, pubkeys.len()),
3149            Included(i) => (Included(pubkeys[i]), i + 1),
3150            Excluded(i) => (Excluded(pubkeys[i]), i),
3151        };
3152        let pubkey_range = (pubkey_start, pubkey_end);
3153
3154        let ancestors = Ancestors::default();
3155        let mut scanned_keys = HashSet::new();
3156        index.range_scan_accounts(
3157            "",
3158            &ancestors,
3159            pubkey_range,
3160            COLLECT_ALL_UNSORTED_FALSE,
3161            |pubkey, _index| {
3162                scanned_keys.insert(*pubkey);
3163            },
3164        );
3165
3166        let mut expected_len = 0;
3167        for key in &pubkeys[index_start..index_end] {
3168            expected_len += 1;
3169            assert!(scanned_keys.contains(key));
3170        }
3171
3172        assert_eq!(scanned_keys.len(), expected_len);
3173    }
3174
3175    fn run_test_range_indexes(
3176        index: &AccountsIndex<bool>,
3177        pubkeys: &[Pubkey],
3178        start: Option<usize>,
3179        end: Option<usize>,
3180    ) {
3181        let start_options = start
3182            .map(|i| vec![Included(i), Excluded(i)])
3183            .unwrap_or_else(|| vec![Unbounded]);
3184        let end_options = end
3185            .map(|i| vec![Included(i), Excluded(i)])
3186            .unwrap_or_else(|| vec![Unbounded]);
3187
3188        for start in &start_options {
3189            for end in &end_options {
3190                run_test_range(index, pubkeys, *start, *end);
3191            }
3192        }
3193    }
3194
3195    #[test]
3196    fn test_range_scan_accounts() {
3197        let (index, mut pubkeys) = setup_accounts_index_keys(3 * ITER_BATCH_SIZE);
3198        pubkeys.sort();
3199
3200        run_test_range_indexes(&index, &pubkeys, None, None);
3201
3202        run_test_range_indexes(&index, &pubkeys, Some(ITER_BATCH_SIZE), None);
3203
3204        run_test_range_indexes(&index, &pubkeys, None, Some(2 * ITER_BATCH_SIZE as usize));
3205
3206        run_test_range_indexes(
3207            &index,
3208            &pubkeys,
3209            Some(ITER_BATCH_SIZE as usize),
3210            Some(2 * ITER_BATCH_SIZE as usize),
3211        );
3212
3213        run_test_range_indexes(
3214            &index,
3215            &pubkeys,
3216            Some(ITER_BATCH_SIZE as usize),
3217            Some(2 * ITER_BATCH_SIZE as usize - 1),
3218        );
3219
3220        run_test_range_indexes(
3221            &index,
3222            &pubkeys,
3223            Some(ITER_BATCH_SIZE - 1_usize),
3224            Some(2 * ITER_BATCH_SIZE as usize + 1),
3225        );
3226    }
3227
3228    fn run_test_scan_accounts(num_pubkeys: usize) {
3229        let (index, _) = setup_accounts_index_keys(num_pubkeys);
3230        let ancestors = Ancestors::default();
3231
3232        let mut scanned_keys = HashSet::new();
3233        index.unchecked_scan_accounts(
3234            "",
3235            &ancestors,
3236            |pubkey, _index| {
3237                scanned_keys.insert(*pubkey);
3238            },
3239            COLLECT_ALL_UNSORTED_FALSE,
3240        );
3241        assert_eq!(scanned_keys.len(), num_pubkeys);
3242    }
3243
3244    #[test]
3245    fn test_scan_accounts() {
3246        run_test_scan_accounts(0);
3247        run_test_scan_accounts(1);
3248        run_test_scan_accounts(ITER_BATCH_SIZE * 10);
3249        run_test_scan_accounts(ITER_BATCH_SIZE * 10 - 1);
3250        run_test_scan_accounts(ITER_BATCH_SIZE * 10 + 1);
3251    }
3252
3253    #[test]
3254    fn test_accounts_iter_finished() {
3255        let (index, _) = setup_accounts_index_keys(0);
3256        let mut iter = index.iter(None::<&Range<Pubkey>>, COLLECT_ALL_UNSORTED_FALSE);
3257        assert!(iter.next().is_none());
3258        let mut gc = vec![];
3259        index.upsert(
3260            0,
3261            &gemachain_sdk::pubkey::new_rand(),
3262            &Pubkey::default(),
3263            &[],
3264            &AccountSecondaryIndexes::default(),
3265            true,
3266            &mut gc,
3267            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3268        );
3269        assert!(iter.next().is_none());
3270    }
3271
3272    #[test]
3273    fn test_is_root() {
3274        let index = AccountsIndex::<bool>::default_for_tests();
3275        assert!(!index.is_root(0));
3276        index.add_root(0, false);
3277        assert!(index.is_root(0));
3278    }
3279
3280    #[test]
3281    fn test_insert_with_root() {
3282        let key = Keypair::new();
3283        let index = AccountsIndex::<bool>::default_for_tests();
3284        let mut gc = Vec::new();
3285        index.upsert(
3286            0,
3287            &key.pubkey(),
3288            &Pubkey::default(),
3289            &[],
3290            &AccountSecondaryIndexes::default(),
3291            true,
3292            &mut gc,
3293            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3294        );
3295        assert!(gc.is_empty());
3296
3297        index.add_root(0, false);
3298        let (list, idx) = index.get(&key.pubkey(), None, None).unwrap();
3299        assert_eq!(list.slot_list()[idx], (0, true));
3300    }
3301
3302    #[test]
3303    fn test_clean_first() {
3304        let index = AccountsIndex::<bool>::default_for_tests();
3305        index.add_root(0, false);
3306        index.add_root(1, false);
3307        index.clean_dead_slot(0);
3308        assert!(index.is_root(1));
3309        assert!(!index.is_root(0));
3310    }
3311
3312    #[test]
3313    fn test_clean_last() {
3314        //this behavior might be undefined, clean up should only occur on older slots
3315        let index = AccountsIndex::<bool>::default_for_tests();
3316        index.add_root(0, false);
3317        index.add_root(1, false);
3318        index.clean_dead_slot(1);
3319        assert!(!index.is_root(1));
3320        assert!(index.is_root(0));
3321    }
3322
3323    #[test]
3324    fn test_clean_and_unclean_slot() {
3325        let index = AccountsIndex::<bool>::default_for_tests();
3326        assert_eq!(0, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3327        index.add_root(0, false);
3328        index.add_root(1, false);
3329        assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3330
3331        assert_eq!(
3332            0,
3333            index
3334                .roots_tracker
3335                .read()
3336                .unwrap()
3337                .previous_uncleaned_roots
3338                .len()
3339        );
3340        index.reset_uncleaned_roots(None);
3341        assert_eq!(2, index.roots_tracker.read().unwrap().roots.len());
3342        assert_eq!(0, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3343        assert_eq!(
3344            2,
3345            index
3346                .roots_tracker
3347                .read()
3348                .unwrap()
3349                .previous_uncleaned_roots
3350                .len()
3351        );
3352
3353        index.add_root(2, false);
3354        index.add_root(3, false);
3355        assert_eq!(4, index.roots_tracker.read().unwrap().roots.len());
3356        assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3357        assert_eq!(
3358            2,
3359            index
3360                .roots_tracker
3361                .read()
3362                .unwrap()
3363                .previous_uncleaned_roots
3364                .len()
3365        );
3366
3367        index.clean_dead_slot(1);
3368        assert_eq!(3, index.roots_tracker.read().unwrap().roots.len());
3369        assert_eq!(2, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3370        assert_eq!(
3371            1,
3372            index
3373                .roots_tracker
3374                .read()
3375                .unwrap()
3376                .previous_uncleaned_roots
3377                .len()
3378        );
3379
3380        index.clean_dead_slot(2);
3381        assert_eq!(2, index.roots_tracker.read().unwrap().roots.len());
3382        assert_eq!(1, index.roots_tracker.read().unwrap().uncleaned_roots.len());
3383        assert_eq!(
3384            1,
3385            index
3386                .roots_tracker
3387                .read()
3388                .unwrap()
3389                .previous_uncleaned_roots
3390                .len()
3391        );
3392    }
3393
3394    #[test]
3395    fn test_update_last_wins() {
3396        let key = Keypair::new();
3397        let index = AccountsIndex::<bool>::default_for_tests();
3398        let ancestors = vec![(0, 0)].into_iter().collect();
3399        let mut gc = Vec::new();
3400        index.upsert(
3401            0,
3402            &key.pubkey(),
3403            &Pubkey::default(),
3404            &[],
3405            &AccountSecondaryIndexes::default(),
3406            true,
3407            &mut gc,
3408            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3409        );
3410        assert!(gc.is_empty());
3411        let (list, idx) = index.get(&key.pubkey(), Some(&ancestors), None).unwrap();
3412        assert_eq!(list.slot_list()[idx], (0, true));
3413        drop(list);
3414
3415        let mut gc = Vec::new();
3416        index.upsert(
3417            0,
3418            &key.pubkey(),
3419            &Pubkey::default(),
3420            &[],
3421            &AccountSecondaryIndexes::default(),
3422            false,
3423            &mut gc,
3424            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3425        );
3426        assert_eq!(gc, vec![(0, true)]);
3427        let (list, idx) = index.get(&key.pubkey(), Some(&ancestors), None).unwrap();
3428        assert_eq!(list.slot_list()[idx], (0, false));
3429    }
3430
3431    #[test]
3432    fn test_update_new_slot() {
3433        gemachain_logger::setup();
3434        let key = Keypair::new();
3435        let index = AccountsIndex::<bool>::default_for_tests();
3436        let ancestors = vec![(0, 0)].into_iter().collect();
3437        let mut gc = Vec::new();
3438        index.upsert(
3439            0,
3440            &key.pubkey(),
3441            &Pubkey::default(),
3442            &[],
3443            &AccountSecondaryIndexes::default(),
3444            true,
3445            &mut gc,
3446            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3447        );
3448        assert!(gc.is_empty());
3449        index.upsert(
3450            1,
3451            &key.pubkey(),
3452            &Pubkey::default(),
3453            &[],
3454            &AccountSecondaryIndexes::default(),
3455            false,
3456            &mut gc,
3457            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3458        );
3459        assert!(gc.is_empty());
3460        let (list, idx) = index.get(&key.pubkey(), Some(&ancestors), None).unwrap();
3461        assert_eq!(list.slot_list()[idx], (0, true));
3462        let ancestors = vec![(1, 0)].into_iter().collect();
3463        let (list, idx) = index.get(&key.pubkey(), Some(&ancestors), None).unwrap();
3464        assert_eq!(list.slot_list()[idx], (1, false));
3465    }
3466
3467    #[test]
3468    fn test_update_gc_purged_slot() {
3469        let key = Keypair::new();
3470        let index = AccountsIndex::<bool>::default_for_tests();
3471        let mut gc = Vec::new();
3472        index.upsert(
3473            0,
3474            &key.pubkey(),
3475            &Pubkey::default(),
3476            &[],
3477            &AccountSecondaryIndexes::default(),
3478            true,
3479            &mut gc,
3480            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3481        );
3482        assert!(gc.is_empty());
3483        index.upsert(
3484            1,
3485            &key.pubkey(),
3486            &Pubkey::default(),
3487            &[],
3488            &AccountSecondaryIndexes::default(),
3489            false,
3490            &mut gc,
3491            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3492        );
3493        index.upsert(
3494            2,
3495            &key.pubkey(),
3496            &Pubkey::default(),
3497            &[],
3498            &AccountSecondaryIndexes::default(),
3499            true,
3500            &mut gc,
3501            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3502        );
3503        index.upsert(
3504            3,
3505            &key.pubkey(),
3506            &Pubkey::default(),
3507            &[],
3508            &AccountSecondaryIndexes::default(),
3509            true,
3510            &mut gc,
3511            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3512        );
3513        index.add_root(0, false);
3514        index.add_root(1, false);
3515        index.add_root(3, false);
3516        index.upsert(
3517            4,
3518            &key.pubkey(),
3519            &Pubkey::default(),
3520            &[],
3521            &AccountSecondaryIndexes::default(),
3522            true,
3523            &mut gc,
3524            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3525        );
3526
3527        // Updating index should not purge older roots, only purges
3528        // previous updates within the same slot
3529        assert_eq!(gc, vec![]);
3530        let (list, idx) = index.get(&key.pubkey(), None, None).unwrap();
3531        assert_eq!(list.slot_list()[idx], (3, true));
3532
3533        let mut num = 0;
3534        let mut found_key = false;
3535        index.unchecked_scan_accounts(
3536            "",
3537            &Ancestors::default(),
3538            |pubkey, _index| {
3539                if pubkey == &key.pubkey() {
3540                    found_key = true;
3541                    assert_eq!(_index, (&true, 3));
3542                };
3543                num += 1
3544            },
3545            COLLECT_ALL_UNSORTED_FALSE,
3546        );
3547        assert_eq!(num, 1);
3548        assert!(found_key);
3549    }
3550
3551    fn account_maps_len_expensive<T: IndexValue>(index: &AccountsIndex<T>) -> usize {
3552        index
3553            .account_maps
3554            .iter()
3555            .map(|bin_map| bin_map.read().unwrap().len())
3556            .sum()
3557    }
3558
3559    #[test]
3560    fn test_purge() {
3561        let key = Keypair::new();
3562        let index = AccountsIndex::<u64>::default_for_tests();
3563        let mut gc = Vec::new();
3564        assert_eq!(0, account_maps_len_expensive(&index));
3565        index.upsert(
3566            1,
3567            &key.pubkey(),
3568            &Pubkey::default(),
3569            &[],
3570            &AccountSecondaryIndexes::default(),
3571            12,
3572            &mut gc,
3573            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3574        );
3575        assert_eq!(1, account_maps_len_expensive(&index));
3576
3577        index.upsert(
3578            1,
3579            &key.pubkey(),
3580            &Pubkey::default(),
3581            &[],
3582            &AccountSecondaryIndexes::default(),
3583            10,
3584            &mut gc,
3585            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3586        );
3587        assert_eq!(1, account_maps_len_expensive(&index));
3588
3589        let purges = index.purge_roots(&key.pubkey());
3590        assert_eq!(purges, (vec![], false));
3591        index.add_root(1, false);
3592
3593        let purges = index.purge_roots(&key.pubkey());
3594        assert_eq!(purges, (vec![(1, 10)], true));
3595
3596        assert_eq!(1, account_maps_len_expensive(&index));
3597        index.upsert(
3598            1,
3599            &key.pubkey(),
3600            &Pubkey::default(),
3601            &[],
3602            &AccountSecondaryIndexes::default(),
3603            9,
3604            &mut gc,
3605            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3606        );
3607        assert_eq!(1, account_maps_len_expensive(&index));
3608    }
3609
3610    #[test]
3611    fn test_latest_slot() {
3612        let slot_slice = vec![(0, true), (5, true), (3, true), (7, true)];
3613        let index = AccountsIndex::<bool>::default_for_tests();
3614
3615        // No ancestors, no root, should return None
3616        assert!(index.latest_slot(None, &slot_slice, None).is_none());
3617
3618        // Given a root, should return the root
3619        index.add_root(5, false);
3620        assert_eq!(index.latest_slot(None, &slot_slice, None).unwrap(), 1);
3621
3622        // Given a max_root == root, should still return the root
3623        assert_eq!(index.latest_slot(None, &slot_slice, Some(5)).unwrap(), 1);
3624
3625        // Given a max_root < root, should filter out the root
3626        assert!(index.latest_slot(None, &slot_slice, Some(4)).is_none());
3627
3628        // Given a max_root, should filter out roots < max_root, but specified
3629        // ancestors should not be affected
3630        let ancestors = vec![(3, 1), (7, 1)].into_iter().collect();
3631        assert_eq!(
3632            index
3633                .latest_slot(Some(&ancestors), &slot_slice, Some(4))
3634                .unwrap(),
3635            3
3636        );
3637        assert_eq!(
3638            index
3639                .latest_slot(Some(&ancestors), &slot_slice, Some(7))
3640                .unwrap(),
3641            3
3642        );
3643
3644        // Given no max_root, should just return the greatest ancestor or root
3645        assert_eq!(
3646            index
3647                .latest_slot(Some(&ancestors), &slot_slice, None)
3648                .unwrap(),
3649            3
3650        );
3651    }
3652
3653    fn run_test_purge_exact_secondary_index<
3654        SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3655    >(
3656        index: &AccountsIndex<bool>,
3657        secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3658        key_start: usize,
3659        key_end: usize,
3660        secondary_indexes: &AccountSecondaryIndexes,
3661    ) {
3662        // No roots, should be no reclaims
3663        let slots = vec![1, 2, 5, 9];
3664        let index_key = Pubkey::new_unique();
3665        let account_key = Pubkey::new_unique();
3666
3667        let mut account_data = vec![0; inline_spl_token_v2_0::state::Account::get_packed_len()];
3668        account_data[key_start..key_end].clone_from_slice(&(index_key.to_bytes()));
3669
3670        // Insert slots into secondary index
3671        for slot in &slots {
3672            index.upsert(
3673                *slot,
3674                &account_key,
3675                // Make sure these accounts are added to secondary index
3676                &inline_spl_token_v2_0::id(),
3677                &account_data,
3678                secondary_indexes,
3679                true,
3680                &mut vec![],
3681                UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3682            );
3683        }
3684
3685        // Only one top level index entry exists
3686        assert_eq!(secondary_index.index.get(&index_key).unwrap().len(), 1);
3687
3688        // In the reverse index, one account maps across multiple slots
3689        // to the same top level key
3690        assert_eq!(
3691            secondary_index
3692                .reverse_index
3693                .get(&account_key)
3694                .unwrap()
3695                .value()
3696                .read()
3697                .unwrap()
3698                .len(),
3699            1
3700        );
3701
3702        index.purge_exact(
3703            &account_key,
3704            &slots.into_iter().collect::<HashSet<Slot>>(),
3705            &mut vec![],
3706        );
3707
3708        index.handle_dead_keys(&[&account_key], secondary_indexes);
3709        assert!(secondary_index.index.is_empty());
3710        assert!(secondary_index.reverse_index.is_empty());
3711    }
3712
3713    #[test]
3714    fn test_purge_exact_dashmap_secondary_index() {
3715        let (key_start, key_end, secondary_indexes) = create_dashmap_secondary_index_state();
3716        let index = AccountsIndex::<bool>::default_for_tests();
3717        run_test_purge_exact_secondary_index(
3718            &index,
3719            &index.spl_token_mint_index,
3720            key_start,
3721            key_end,
3722            &secondary_indexes,
3723        );
3724    }
3725
3726    #[test]
3727    fn test_purge_exact_rwlock_secondary_index() {
3728        let (key_start, key_end, secondary_indexes) = create_rwlock_secondary_index_state();
3729        let index = AccountsIndex::<bool>::default_for_tests();
3730        run_test_purge_exact_secondary_index(
3731            &index,
3732            &index.spl_token_owner_index,
3733            key_start,
3734            key_end,
3735            &secondary_indexes,
3736        );
3737    }
3738
3739    #[test]
3740    fn test_purge_older_root_entries() {
3741        // No roots, should be no reclaims
3742        let index = AccountsIndex::<bool>::default_for_tests();
3743        let mut slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3744        let mut reclaims = vec![];
3745        index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3746        assert!(reclaims.is_empty());
3747        assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3748
3749        // Add a later root, earlier slots should be reclaimed
3750        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3751        index.add_root(1, false);
3752        // Note 2 is not a root
3753        index.add_root(5, false);
3754        reclaims = vec![];
3755        index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3756        assert_eq!(reclaims, vec![(1, true), (2, true)]);
3757        assert_eq!(slot_list, vec![(5, true), (9, true)]);
3758
3759        // Add a later root that is not in the list, should not affect the outcome
3760        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3761        index.add_root(6, false);
3762        reclaims = vec![];
3763        index.purge_older_root_entries(&mut slot_list, &mut reclaims, None);
3764        assert_eq!(reclaims, vec![(1, true), (2, true)]);
3765        assert_eq!(slot_list, vec![(5, true), (9, true)]);
3766
3767        // Pass a max root >= than any root in the slot list, should not affect
3768        // outcome
3769        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3770        reclaims = vec![];
3771        index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(6));
3772        assert_eq!(reclaims, vec![(1, true), (2, true)]);
3773        assert_eq!(slot_list, vec![(5, true), (9, true)]);
3774
3775        // Pass a max root, earlier slots should be reclaimed
3776        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3777        reclaims = vec![];
3778        index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(5));
3779        assert_eq!(reclaims, vec![(1, true), (2, true)]);
3780        assert_eq!(slot_list, vec![(5, true), (9, true)]);
3781
3782        // Pass a max root 2. This means the latest root < 2 is 1 because 2 is not a root
3783        // so nothing will be purged
3784        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3785        reclaims = vec![];
3786        index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(2));
3787        assert!(reclaims.is_empty());
3788        assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3789
3790        // Pass a max root 1. This means the latest root < 3 is 1 because 2 is not a root
3791        // so nothing will be purged
3792        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3793        reclaims = vec![];
3794        index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(1));
3795        assert!(reclaims.is_empty());
3796        assert_eq!(slot_list, vec![(1, true), (2, true), (5, true), (9, true)]);
3797
3798        // Pass a max root that doesn't exist in the list but is greater than
3799        // some of the roots in the list, shouldn't return those smaller roots
3800        slot_list = vec![(1, true), (2, true), (5, true), (9, true)];
3801        reclaims = vec![];
3802        index.purge_older_root_entries(&mut slot_list, &mut reclaims, Some(7));
3803        assert_eq!(reclaims, vec![(1, true), (2, true)]);
3804        assert_eq!(slot_list, vec![(5, true), (9, true)]);
3805    }
3806
3807    fn check_secondary_index_mapping_correct<SecondaryIndexEntryType>(
3808        secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3809        secondary_index_keys: &[Pubkey],
3810        account_key: &Pubkey,
3811    ) where
3812        SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3813    {
3814        // Check secondary index has unique mapping from secondary index key
3815        // to the account key and slot
3816        for secondary_index_key in secondary_index_keys {
3817            assert_eq!(secondary_index.index.len(), secondary_index_keys.len());
3818            let account_key_map = secondary_index.get(secondary_index_key);
3819            assert_eq!(account_key_map.len(), 1);
3820            assert_eq!(account_key_map, vec![*account_key]);
3821        }
3822        // Check reverse index contains all of the `secondary_index_keys`
3823        let secondary_index_key_map = secondary_index.reverse_index.get(account_key).unwrap();
3824        assert_eq!(
3825            &*secondary_index_key_map.value().read().unwrap(),
3826            secondary_index_keys
3827        );
3828    }
3829
3830    fn run_test_secondary_indexes<
3831        SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3832    >(
3833        index: &AccountsIndex<bool>,
3834        secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3835        key_start: usize,
3836        key_end: usize,
3837        secondary_indexes: &AccountSecondaryIndexes,
3838    ) {
3839        let mut secondary_indexes = secondary_indexes.clone();
3840        let account_key = Pubkey::new_unique();
3841        let index_key = Pubkey::new_unique();
3842        let mut account_data = vec![0; inline_spl_token_v2_0::state::Account::get_packed_len()];
3843        account_data[key_start..key_end].clone_from_slice(&(index_key.to_bytes()));
3844
3845        // Wrong program id
3846        index.upsert(
3847            0,
3848            &account_key,
3849            &Pubkey::default(),
3850            &account_data,
3851            &secondary_indexes,
3852            true,
3853            &mut vec![],
3854            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3855        );
3856        assert!(secondary_index.index.is_empty());
3857        assert!(secondary_index.reverse_index.is_empty());
3858
3859        // Wrong account data size
3860        index.upsert(
3861            0,
3862            &account_key,
3863            &inline_spl_token_v2_0::id(),
3864            &account_data[1..],
3865            &secondary_indexes,
3866            true,
3867            &mut vec![],
3868            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3869        );
3870        assert!(secondary_index.index.is_empty());
3871        assert!(secondary_index.reverse_index.is_empty());
3872
3873        secondary_indexes.keys = None;
3874
3875        // Just right. Inserting the same index multiple times should be ok
3876        for _ in 0..2 {
3877            index.update_secondary_indexes(
3878                &account_key,
3879                &inline_spl_token_v2_0::id(),
3880                &account_data,
3881                &secondary_indexes,
3882            );
3883            check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3884        }
3885
3886        // included
3887        assert!(!secondary_index.index.is_empty());
3888        assert!(!secondary_index.reverse_index.is_empty());
3889
3890        secondary_indexes.keys = Some(AccountSecondaryIndexesIncludeExclude {
3891            keys: [index_key].iter().cloned().collect::<HashSet<_>>(),
3892            exclude: false,
3893        });
3894        secondary_index.index.clear();
3895        secondary_index.reverse_index.clear();
3896        index.update_secondary_indexes(
3897            &account_key,
3898            &inline_spl_token_v2_0::id(),
3899            &account_data,
3900            &secondary_indexes,
3901        );
3902        assert!(!secondary_index.index.is_empty());
3903        assert!(!secondary_index.reverse_index.is_empty());
3904        check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3905
3906        // not-excluded
3907        secondary_indexes.keys = Some(AccountSecondaryIndexesIncludeExclude {
3908            keys: [].iter().cloned().collect::<HashSet<_>>(),
3909            exclude: true,
3910        });
3911        secondary_index.index.clear();
3912        secondary_index.reverse_index.clear();
3913        index.update_secondary_indexes(
3914            &account_key,
3915            &inline_spl_token_v2_0::id(),
3916            &account_data,
3917            &secondary_indexes,
3918        );
3919        assert!(!secondary_index.index.is_empty());
3920        assert!(!secondary_index.reverse_index.is_empty());
3921        check_secondary_index_mapping_correct(secondary_index, &[index_key], &account_key);
3922
3923        secondary_indexes.keys = None;
3924
3925        index
3926            .get_account_write_entry(&account_key)
3927            .unwrap()
3928            .slot_list_mut(|slot_list| slot_list.clear());
3929
3930        // Everything should be deleted
3931        index.handle_dead_keys(&[&account_key], &secondary_indexes);
3932        assert!(secondary_index.index.is_empty());
3933        assert!(secondary_index.reverse_index.is_empty());
3934    }
3935
3936    #[test]
3937    fn test_dashmap_secondary_index() {
3938        let (key_start, key_end, secondary_indexes) = create_dashmap_secondary_index_state();
3939        let index = AccountsIndex::<bool>::default_for_tests();
3940        run_test_secondary_indexes(
3941            &index,
3942            &index.spl_token_mint_index,
3943            key_start,
3944            key_end,
3945            &secondary_indexes,
3946        );
3947    }
3948
3949    #[test]
3950    fn test_rwlock_secondary_index() {
3951        let (key_start, key_end, secondary_indexes) = create_rwlock_secondary_index_state();
3952        let index = AccountsIndex::<bool>::default_for_tests();
3953        run_test_secondary_indexes(
3954            &index,
3955            &index.spl_token_owner_index,
3956            key_start,
3957            key_end,
3958            &secondary_indexes,
3959        );
3960    }
3961
3962    fn run_test_secondary_indexes_same_slot_and_forks<
3963        SecondaryIndexEntryType: SecondaryIndexEntry + Default + Sync + Send,
3964    >(
3965        index: &AccountsIndex<bool>,
3966        secondary_index: &SecondaryIndex<SecondaryIndexEntryType>,
3967        index_key_start: usize,
3968        index_key_end: usize,
3969        secondary_indexes: &AccountSecondaryIndexes,
3970    ) {
3971        let account_key = Pubkey::new_unique();
3972        let secondary_key1 = Pubkey::new_unique();
3973        let secondary_key2 = Pubkey::new_unique();
3974        let slot = 1;
3975        let mut account_data1 = vec![0; inline_spl_token_v2_0::state::Account::get_packed_len()];
3976        account_data1[index_key_start..index_key_end]
3977            .clone_from_slice(&(secondary_key1.to_bytes()));
3978        let mut account_data2 = vec![0; inline_spl_token_v2_0::state::Account::get_packed_len()];
3979        account_data2[index_key_start..index_key_end]
3980            .clone_from_slice(&(secondary_key2.to_bytes()));
3981
3982        // First write one mint index
3983        index.upsert(
3984            slot,
3985            &account_key,
3986            &inline_spl_token_v2_0::id(),
3987            &account_data1,
3988            secondary_indexes,
3989            true,
3990            &mut vec![],
3991            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
3992        );
3993
3994        // Now write a different mint index for the same account
3995        index.upsert(
3996            slot,
3997            &account_key,
3998            &inline_spl_token_v2_0::id(),
3999            &account_data2,
4000            secondary_indexes,
4001            true,
4002            &mut vec![],
4003            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
4004        );
4005
4006        // Both pubkeys will now be present in the index
4007        check_secondary_index_mapping_correct(
4008            secondary_index,
4009            &[secondary_key1, secondary_key2],
4010            &account_key,
4011        );
4012
4013        // If a later slot also introduces secondary_key1, then it should still exist in the index
4014        let later_slot = slot + 1;
4015        index.upsert(
4016            later_slot,
4017            &account_key,
4018            &inline_spl_token_v2_0::id(),
4019            &account_data1,
4020            secondary_indexes,
4021            true,
4022            &mut vec![],
4023            UPSERT_PREVIOUS_SLOT_ENTRY_WAS_CACHED_FALSE,
4024        );
4025        assert_eq!(secondary_index.get(&secondary_key1), vec![account_key]);
4026
4027        // If we set a root at `later_slot`, and clean, then even though the account with secondary_key1
4028        // was outdated by the update in the later slot, the primary account key is still alive,
4029        // so both secondary keys will still be kept alive.
4030        index.add_root(later_slot, false);
4031        index
4032            .get_account_write_entry(&account_key)
4033            .unwrap()
4034            .slot_list_mut(|slot_list| {
4035                index.purge_older_root_entries(slot_list, &mut vec![], None)
4036            });
4037
4038        check_secondary_index_mapping_correct(
4039            secondary_index,
4040            &[secondary_key1, secondary_key2],
4041            &account_key,
4042        );
4043
4044        // Removing the remaining entry for this pubkey in the index should mark the
4045        // pubkey as dead and finally remove all the secondary indexes
4046        let mut reclaims = vec![];
4047        index.purge_exact(&account_key, &later_slot, &mut reclaims);
4048        index.handle_dead_keys(&[&account_key], secondary_indexes);
4049        assert!(secondary_index.index.is_empty());
4050        assert!(secondary_index.reverse_index.is_empty());
4051    }
4052
4053    #[test]
4054    fn test_dashmap_secondary_index_same_slot_and_forks() {
4055        let (key_start, key_end, account_index) = create_dashmap_secondary_index_state();
4056        let index = AccountsIndex::<bool>::default_for_tests();
4057        run_test_secondary_indexes_same_slot_and_forks(
4058            &index,
4059            &index.spl_token_mint_index,
4060            key_start,
4061            key_end,
4062            &account_index,
4063        );
4064    }
4065
4066    #[test]
4067    fn test_rwlock_secondary_index_same_slot_and_forks() {
4068        let (key_start, key_end, account_index) = create_rwlock_secondary_index_state();
4069        let index = AccountsIndex::<bool>::default_for_tests();
4070        run_test_secondary_indexes_same_slot_and_forks(
4071            &index,
4072            &index.spl_token_owner_index,
4073            key_start,
4074            key_end,
4075            &account_index,
4076        );
4077    }
4078
4079    impl IndexValue for bool {}
4080    impl IndexValue for u64 {}
4081    impl IsCached for bool {
4082        fn is_cached(&self) -> bool {
4083            false
4084        }
4085    }
4086    impl IsCached for u64 {
4087        fn is_cached(&self) -> bool {
4088            false
4089        }
4090    }
4091    impl ZeroCarat for bool {
4092        fn is_zero_carat(&self) -> bool {
4093            false
4094        }
4095    }
4096
4097    impl ZeroCarat for u64 {
4098        fn is_zero_carat(&self) -> bool {
4099            false
4100        }
4101    }
4102
4103    #[test]
4104    fn test_bin_start_and_range() {
4105        let index = AccountsIndex::<bool>::default_for_tests();
4106        let iter = AccountsIndexIterator::new(
4107            &index,
4108            None::<&RangeInclusive<Pubkey>>,
4109            COLLECT_ALL_UNSORTED_FALSE,
4110        );
4111        assert_eq!((0, usize::MAX), iter.bin_start_and_range());
4112
4113        let key_0 = Pubkey::new(&[0; 32]);
4114        let key_ff = Pubkey::new(&[0xff; 32]);
4115
4116        let iter = AccountsIndexIterator::new(
4117            &index,
4118            Some(&RangeInclusive::new(key_0, key_ff)),
4119            COLLECT_ALL_UNSORTED_FALSE,
4120        );
4121        let bins = index.bins();
4122        assert_eq!((0, bins), iter.bin_start_and_range());
4123        let iter = AccountsIndexIterator::new(
4124            &index,
4125            Some(&RangeInclusive::new(key_ff, key_0)),
4126            COLLECT_ALL_UNSORTED_FALSE,
4127        );
4128        assert_eq!((bins - 1, 0), iter.bin_start_and_range());
4129        let iter = AccountsIndexIterator::new(
4130            &index,
4131            Some(&(Included(key_0), Unbounded)),
4132            COLLECT_ALL_UNSORTED_FALSE,
4133        );
4134        assert_eq!((0, usize::MAX), iter.bin_start_and_range());
4135        let iter = AccountsIndexIterator::new(
4136            &index,
4137            Some(&(Included(key_ff), Unbounded)),
4138            COLLECT_ALL_UNSORTED_FALSE,
4139        );
4140        assert_eq!((bins - 1, usize::MAX), iter.bin_start_and_range());
4141
4142        assert_eq!(
4143            (0..2)
4144                .into_iter()
4145                .skip(1)
4146                .take(usize::MAX)
4147                .collect::<Vec<_>>(),
4148            vec![1]
4149        );
4150    }
4151
4152    #[test]
4153    fn test_start_end_bin() {
4154        let index = AccountsIndex::<bool>::default_for_tests();
4155        assert_eq!(index.bins(), BINS_FOR_TESTING);
4156        let iter = AccountsIndexIterator::new(
4157            &index,
4158            None::<&RangeInclusive<Pubkey>>,
4159            COLLECT_ALL_UNSORTED_FALSE,
4160        );
4161        assert_eq!(iter.start_bin(), 0); // no range, so 0
4162        assert_eq!(iter.end_bin_inclusive(), usize::MAX); // no range, so max
4163
4164        let key = Pubkey::new(&[0; 32]);
4165        let iter = AccountsIndexIterator::new(
4166            &index,
4167            Some(&RangeInclusive::new(key, key)),
4168            COLLECT_ALL_UNSORTED_FALSE,
4169        );
4170        assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
4171        assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
4172        let iter = AccountsIndexIterator::new(
4173            &index,
4174            Some(&(Included(key), Excluded(key))),
4175            COLLECT_ALL_UNSORTED_FALSE,
4176        );
4177        assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
4178        assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
4179        let iter = AccountsIndexIterator::new(
4180            &index,
4181            Some(&(Excluded(key), Excluded(key))),
4182            COLLECT_ALL_UNSORTED_FALSE,
4183        );
4184        assert_eq!(iter.start_bin(), 0); // start at pubkey 0, so 0
4185        assert_eq!(iter.end_bin_inclusive(), 0); // end at pubkey 0, so 0
4186
4187        let key = Pubkey::new(&[0xff; 32]);
4188        let iter = AccountsIndexIterator::new(
4189            &index,
4190            Some(&RangeInclusive::new(key, key)),
4191            COLLECT_ALL_UNSORTED_FALSE,
4192        );
4193        let bins = index.bins();
4194        assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
4195        assert_eq!(iter.end_bin_inclusive(), bins - 1);
4196        let iter = AccountsIndexIterator::new(
4197            &index,
4198            Some(&(Included(key), Excluded(key))),
4199            COLLECT_ALL_UNSORTED_FALSE,
4200        );
4201        assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
4202        assert_eq!(iter.end_bin_inclusive(), bins - 1);
4203        let iter = AccountsIndexIterator::new(
4204            &index,
4205            Some(&(Excluded(key), Excluded(key))),
4206            COLLECT_ALL_UNSORTED_FALSE,
4207        );
4208        assert_eq!(iter.start_bin(), bins - 1); // start at highest possible pubkey, so bins - 1
4209        assert_eq!(iter.end_bin_inclusive(), bins - 1);
4210    }
4211
4212    #[test]
4213    #[should_panic(expected = "bins.is_power_of_two()")]
4214    #[allow(clippy::field_reassign_with_default)]
4215    fn test_illegal_bins() {
4216        let mut config = AccountsIndexConfig::default();
4217        config.bins = Some(3);
4218        AccountsIndex::<bool>::new(Some(config));
4219    }
4220}