Skip to content

Commit 8c7ae80

Browse files
authored
Refactors get_snapshot_storages() (solana-labs#3760)
1 parent b543f25 commit 8c7ae80

File tree

2 files changed

+95
-37
lines changed

2 files changed

+95
-37
lines changed

accounts-db/src/account_storage.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,29 @@ impl AccountStorage {
200200
pub(crate) fn len(&self) -> usize {
201201
self.map.len()
202202
}
203+
204+
/// Returns the (slot, storage) tuples where `predicate` returns `true`
205+
///
206+
/// This function is useful when not all storages are desired,
207+
/// as storages are only Arc::cloned if they pass the predicate.
208+
///
209+
/// # Panics
210+
///
211+
/// Panics if `shrink` is in progress.
212+
pub fn get_if(
213+
&self,
214+
predicate: impl Fn(&Slot, &AccountStorageEntry) -> bool,
215+
) -> Box<[(Slot, Arc<AccountStorageEntry>)]> {
216+
assert!(self.no_shrink_in_progress());
217+
self.map
218+
.iter()
219+
.filter_map(|entry| {
220+
let slot = entry.key();
221+
let storage = &entry.value().storage;
222+
predicate(slot, storage).then(|| (*slot, Arc::clone(storage)))
223+
})
224+
.collect()
225+
}
203226
}
204227

205228
/// iterate contents of AccountStorage without exposing internals
@@ -291,7 +314,11 @@ impl Default for AccountStorageStatus {
291314

292315
#[cfg(test)]
293316
pub(crate) mod tests {
294-
use {super::*, crate::accounts_file::AccountsFileProvider, std::path::Path};
317+
use {
318+
super::*,
319+
crate::accounts_file::AccountsFileProvider,
320+
std::{iter, path::Path},
321+
};
295322

296323
#[test]
297324
fn test_shrink_in_progress() {
@@ -568,4 +595,52 @@ pub(crate) mod tests {
568595
.is_none());
569596
assert!(storage.get_account_storage_entry(slot, id).is_some());
570597
}
598+
599+
#[test]
600+
fn test_get_if() {
601+
let storage = AccountStorage::default();
602+
assert!(storage.get_if(|_, _| true).is_empty());
603+
604+
// add some entries
605+
let ids = [123, 456, 789];
606+
for id in ids {
607+
let slot = id as Slot;
608+
let entry = AccountStorageEntry::new(
609+
Path::new(""),
610+
slot,
611+
id,
612+
5000,
613+
AccountsFileProvider::AppendVec,
614+
);
615+
storage.map.insert(
616+
slot,
617+
AccountStorageReference {
618+
id,
619+
storage: entry.into(),
620+
},
621+
);
622+
}
623+
624+
// look 'em up
625+
for id in ids {
626+
let found = storage.get_if(|slot, _| *slot == id as Slot);
627+
assert!(found
628+
.iter()
629+
.map(|(slot, _)| *slot)
630+
.eq(iter::once(id as Slot)));
631+
}
632+
633+
assert!(storage.get_if(|_, _| false).is_empty());
634+
assert_eq!(storage.get_if(|_, _| true).len(), ids.len());
635+
}
636+
637+
#[test]
638+
#[should_panic(expected = "self.no_shrink_in_progress()")]
639+
fn test_get_if_fail() {
640+
let storage = AccountStorage::default();
641+
storage
642+
.shrink_in_progress_map
643+
.insert(0, storage.get_test_storage());
644+
storage.get_if(|_, _| true);
645+
}
571646
}

accounts-db/src/accounts_db.rs

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8474,44 +8474,27 @@ impl AccountsDb {
84748474
&self,
84758475
requested_slots: impl RangeBounds<Slot> + Sync,
84768476
) -> (Vec<Arc<AccountStorageEntry>>, Vec<Slot>) {
8477-
let mut m = Measure::start("get slots");
8478-
let mut slots_and_storages = self
8477+
let start = Instant::now();
8478+
let max_alive_root_exclusive = self
8479+
.accounts_index
8480+
.roots_tracker
8481+
.read()
8482+
.unwrap()
8483+
.alive_roots
8484+
.max_exclusive();
8485+
let (slots, storages) = self
84798486
.storage
8480-
.iter()
8481-
.filter_map(|(slot, store)| {
8482-
requested_slots
8483-
.contains(&slot)
8484-
.then_some((slot, Some(store)))
8487+
.get_if(|slot, storage| {
8488+
(*slot < max_alive_root_exclusive)
8489+
&& requested_slots.contains(slot)
8490+
&& storage.has_accounts()
84858491
})
8486-
.collect::<Vec<_>>();
8487-
m.stop();
8488-
let mut m2 = Measure::start("filter");
8489-
let chunk_size = 5_000;
8490-
let (result, slots): (Vec<_>, Vec<_>) = self.thread_pool_clean.install(|| {
8491-
slots_and_storages
8492-
.par_chunks_mut(chunk_size)
8493-
.map(|slots_and_storages| {
8494-
slots_and_storages
8495-
.iter_mut()
8496-
.filter(|(slot, _)| self.accounts_index.is_alive_root(*slot))
8497-
.filter_map(|(slot, store)| {
8498-
let store = std::mem::take(store).unwrap();
8499-
store.has_accounts().then_some((store, *slot))
8500-
})
8501-
.collect::<Vec<(Arc<AccountStorageEntry>, Slot)>>()
8502-
})
8503-
.flatten()
8504-
.unzip()
8505-
});
8506-
8507-
m2.stop();
8508-
8509-
debug!(
8510-
"hash_total: get slots: {}, filter: {}",
8511-
m.as_us(),
8512-
m2.as_us(),
8513-
);
8514-
(result, slots)
8492+
.into_vec()
8493+
.into_iter()
8494+
.unzip();
8495+
let duration = start.elapsed();
8496+
debug!("get_snapshot_storages: {duration:?}");
8497+
(storages, slots)
85158498
}
85168499

85178500
/// Returns the latest full snapshot slot

0 commit comments

Comments
 (0)