Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit f7eebad

Browse files
AcctIdx: remove old items from cache (#20076)
1 parent 567f30a commit f7eebad

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

runtime/src/in_mem_accounts_index.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
562562
fn flush_internal(&self) {
563563
let was_dirty = self.bin_dirty.swap(false, Ordering::Acquire);
564564
let current_age = self.storage.current_age();
565-
let iterate_for_age = self.get_should_age(current_age);
565+
let mut iterate_for_age = self.get_should_age(current_age);
566566
if !was_dirty && !iterate_for_age {
567567
// wasn't dirty and no need to age, so no need to flush this bucket
568568
return;
@@ -612,7 +612,11 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
612612
flush_entries_updated_on_disk,
613613
);
614614

615-
// loop that processes 'removes' will go here
615+
let m = Measure::start("flush_remove");
616+
if !self.flush_remove_from_cache(removes, current_age) {
617+
iterate_for_age = false; // did not make it all the way through this bucket, so didn't handle age completely
618+
}
619+
Self::update_time_stat(&self.stats().flush_remove_us, m);
616620

617621
if iterate_for_age {
618622
// completed iteration of the buckets at the current age
@@ -621,6 +625,56 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
621625
}
622626
}
623627

628+
// remove keys in 'removes' from in-mem cache due to age
629+
// return true if the removal was completed
630+
fn flush_remove_from_cache(&self, removes: Vec<Pubkey>, current_age: Age) -> bool {
631+
let mut completed_scan = true;
632+
if removes.is_empty() {
633+
return completed_scan; // completed, don't need to get lock or do other work
634+
}
635+
636+
let ranges = self.cache_ranges_held.read().unwrap().clone();
637+
if ranges.iter().any(|range| range.is_none()) {
638+
return false; // range said to hold 'all', so not completed
639+
}
640+
let mut map = self.map().write().unwrap();
641+
for k in removes {
642+
if let Entry::Occupied(occupied) = map.entry(k) {
643+
let v = occupied.get();
644+
if Arc::strong_count(v) > 1 {
645+
// someone is holding the value arc's ref count and could modify it, so do not remove this from in-mem cache
646+
completed_scan = false;
647+
continue;
648+
}
649+
650+
if v.dirty() || !self.should_remove_from_mem(current_age, v) {
651+
// marked dirty or bumped in age after we looked above
652+
// these will be handled in later passes
653+
continue;
654+
}
655+
656+
if ranges.iter().any(|range| {
657+
range
658+
.as_ref()
659+
.map(|range| range.contains(&k))
660+
.unwrap_or(true) // None means 'full range', so true
661+
}) {
662+
// this item is held in mem by range, so don't remove
663+
completed_scan = false;
664+
continue;
665+
}
666+
667+
if self.get_stop_flush() {
668+
return false; // did NOT complete, told to stop
669+
}
670+
671+
// all conditions for removing succeeded, so really remove item from in-mem cache
672+
occupied.remove();
673+
}
674+
}
675+
completed_scan
676+
}
677+
624678
fn stats(&self) -> &BucketMapHolderStats {
625679
&self.storage.stats
626680
}

0 commit comments

Comments
 (0)