diff --git a/accounts-db/src/accounts_index/in_mem_accounts_index.rs b/accounts-db/src/accounts_index/in_mem_accounts_index.rs index 65d02a1f0c5321..aa8be77efe2cc8 100644 --- a/accounts-db/src/accounts_index/in_mem_accounts_index.rs +++ b/accounts-db/src/accounts_index/in_mem_accounts_index.rs @@ -30,55 +30,6 @@ pub struct StartupStats { pub copy_data_us: AtomicU64, } -#[derive(Debug)] -pub struct PossibleEvictions { - /// vec per age in the future, up to size 'ages_to_stay_in_cache' - possible_evictions: Vec, - /// next index to use into 'possible_evictions' - /// if 'index' >= 'possible_evictions.len()', then there are no available entries - index: usize, -} - -impl PossibleEvictions { - fn new(max_ages: Age) -> Self { - Self { - possible_evictions: (0..max_ages).map(|_| FlushScanResult::default()).collect(), - index: max_ages as usize, // initially no data - } - } - - /// remove the possible evictions queued for the current flush window - fn get_possible_evictions(&mut self) -> Option { - self.possible_evictions.get_mut(self.index).map(|result| { - self.index += 1; - // remove the list from 'possible_evictions' - std::mem::take(result) - }) - } - - /// clear existing data and prepare to add 'entries' more ages of data - fn reset(&mut self, entries: Age) { - self.possible_evictions.iter_mut().for_each(|entry| { - entry.evictions_age_possible.clear(); - }); - let entries = entries as usize; - assert!( - entries <= self.possible_evictions.len(), - "entries: {}, len: {}", - entries, - self.possible_evictions.len() - ); - self.index = self.possible_evictions.len() - entries; - } - - /// insert `key` at `relative_age` in the future into `possible_evictions` - fn insert(&mut self, relative_age: Age, key: Pubkey, is_dirty: bool) { - let index = self.index + (relative_age as usize); - let list = &mut self.possible_evictions[index]; - list.evictions_age_possible.push((key, is_dirty)); - } -} - // one instance of this represents one bin of the accounts index. pub struct InMemAccountsIndex + Into> { last_age_flushed: AtomicAge, @@ -98,9 +49,6 @@ pub struct InMemAccountsIndex + Into< /// info to streamline initial index generation startup_info: StartupInfo, - /// possible evictions for next few slots coming up - possible_evictions: RwLock, - /// how many more ages to skip before this bucket is flushed (as opposed to being skipped). /// When this reaches 0, this bucket is flushed. remaining_ages_to_skip_flushing: AtomicAge, @@ -159,14 +107,6 @@ struct StartupInfo + Into> { duplicates: Mutex>, } -#[derive(Default, Debug)] -/// result from scanning in-mem index during flush -struct FlushScanResult { - /// pubkeys whose age indicates they may be evicted now, pending further checks. - /// Entries with ref_count != 1 are filtered out during scan - evictions_age_possible: Vec<(Pubkey, /*is_dirty*/ bool)>, -} - impl + Into> InMemAccountsIndex { pub fn new( storage: &Arc>, @@ -203,7 +143,6 @@ impl + Into> InMemAccountsIndex + Into> InMemAccountsIndex( iter: impl Iterator>)>, - possible_evictions: &mut PossibleEvictions, + possible_evictions: &mut Vec<(Pubkey, /*is_dirty*/ bool)>, startup: bool, current_age: Age, ages_flushing_now: Age, @@ -960,22 +899,23 @@ impl + Into> InMemAccountsIndex FlushScanResult { - let mut possible_evictions = self.possible_evictions.write().unwrap(); - possible_evictions.reset(1); + ) -> Vec<(Pubkey, /*is_dirty*/ bool)> { + let mut possible_evictions = Vec::new(); let m; { let map = self.map_internal.read().unwrap(); @@ -990,7 +930,7 @@ impl + Into> InMemAccountsIndex + Into> InMemAccountsIndex::gather_possible_evictions( map.iter(), &mut possible_evictions, @@ -1786,29 +1724,34 @@ mod tests { current_age, ages_flushing_now, ); - let evictions = possible_evictions.possible_evictions.pop().unwrap(); - assert_eq!( - evictions.evictions_age_possible.len(), - 1 + ages_flushing_now as usize - ); - evictions - .evictions_age_possible - .iter() - .for_each(|(key, _is_dirty)| { - let entry = map.get(key).unwrap(); - assert!( - InMemAccountsIndex::::should_evict_based_on_age( - current_age, - entry, - startup, - ages_flushing_now, - ), - "current_age: {}, age: {}, ages_flushing_now: {}", + // Verify that the number of entries selected for eviction matches the expected count. + // Test setup: map contains 256 entries with ages 0-255 (one entry per age value). + // + // gather_possible_evictions includes entries where: + // current_age.wrapping_sub(entry.age) <= ages_flushing_now + // which is equivalent to: + // entry.age >= current_age - ages_flushing_now (with wrapping) + // + // This selects entries in the age window [current_age - ages_flushing_now, current_age]. + // The window size is (ages_flushing_now + 1) because both endpoints are inclusive. + // + // Example: If current_age=10 and ages_flushing_now=3, we select ages 7,8,9,10 = 4 entries. + assert_eq!(possible_evictions.len(), 1 + ages_flushing_now as usize); + possible_evictions.iter().for_each(|(key, _is_dirty)| { + let entry = map.get(key).unwrap(); + assert!( + InMemAccountsIndex::::should_evict_based_on_age( current_age, - entry.age(), - ages_flushing_now - ); - }); + entry, + startup, + ages_flushing_now, + ), + "current_age: {}, age: {}, ages_flushing_now: {}", + current_age, + entry.age(), + ages_flushing_now + ); + }); } } }