diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index b4896fa954..35c54ef5e3 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -2631,8 +2631,9 @@ impl AccountsDb { let mut not_found_on_fork = 0; let mut missing = 0; let mut useful = 0; - self.accounts_index - .scan(pubkeys.iter(), |pubkey, slots_refs| { + self.accounts_index.scan( + pubkeys.iter(), + |pubkey, slots_refs| { let mut useless = true; if let Some((slot_list, ref_count)) = slots_refs { let index_in_slot_list = self.accounts_index.latest_slot( @@ -2696,7 +2697,9 @@ impl AccountsDb { } else { AccountsIndexScanResult::KeepInMemory } - }); + }, + None, + ); found_not_zero_accum.fetch_add(found_not_zero, Ordering::Relaxed); not_found_on_fork_accum.fetch_add(not_found_on_fork, Ordering::Relaxed); missing_accum.fetch_add(missing, Ordering::Relaxed); @@ -3191,6 +3194,7 @@ impl AccountsDb { index += 1; result }, + None, ); assert_eq!(index, std::cmp::min(accounts.len(), count)); self.shrink_stats @@ -7598,7 +7602,8 @@ impl AccountsDb { .skip(skip) .take(BATCH_SIZE) .map(|(_slot, pubkey)| pubkey), - |_pubkey, _slots_refs| AccountsIndexScanResult::Unref, + |_pubkey, _slots_refs| /* unused */AccountsIndexScanResult::Unref, + Some(AccountsIndexScanResult::Unref), ) }) }); diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 9c008d8c59..983c6d4d44 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -651,6 +651,7 @@ impl ScanSlotTracker { } } +#[derive(Copy, Clone)] pub enum AccountsIndexScanResult { /// if the entry is not in the in-memory index, do not add it, make no modifications to it None, @@ -1342,15 +1343,22 @@ impl AccountsIndex { } /// For each pubkey, find the slot list in the accounts index - /// call `callback` - pub(crate) fn scan<'a, F, I>(&'a self, pubkeys: I, mut callback: F) - where + /// apply 'avoid_callback_result' if specified. + /// otherwise, call `callback` + pub(crate) fn scan<'a, F, I>( + &'a self, + pubkeys: I, + mut callback: F, + avoid_callback_result: Option, + ) where // params: // pubkey looked up // slots_refs is Option<(slot_list, ref_count)> // None if 'pubkey' is not in accounts index. // slot_list: comes from accounts index for 'pubkey' // ref_count: refcount of entry in index + // if 'avoid_callback_result' is Some(_), then callback is NOT called + // and _ is returned as if callback were called. F: FnMut(&'a Pubkey, Option<(&SlotList, RefCount)>) -> AccountsIndexScanResult, I: IntoIterator, { @@ -1367,8 +1375,12 @@ impl AccountsIndex { let mut cache = false; match entry { Some(locked_entry) => { - let slot_list = &locked_entry.slot_list.read().unwrap(); - let result = callback(pubkey, Some((slot_list, locked_entry.ref_count()))); + let result = if let Some(result) = avoid_callback_result.as_ref() { + *result + } else { + let slot_list = &locked_entry.slot_list.read().unwrap(); + callback(pubkey, Some((slot_list, locked_entry.ref_count()))) + }; cache = match result { AccountsIndexScanResult::Unref => { locked_entry.add_un_ref(false); @@ -1379,7 +1391,7 @@ impl AccountsIndex { }; } None => { - callback(pubkey, None); + avoid_callback_result.unwrap_or_else(|| callback(pubkey, None)); } } (cache, ())