SortedStorages holds HashMap instead of Vec (#29632)

* SortedStorages holds HashMap instead of Vec

* add comment
This commit is contained in:
Jeff Washington (jwash) 2023-01-11 16:20:43 -06:00 committed by GitHub
parent 4b93fa85c2
commit 0e19b9c849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 26 additions and 43 deletions

View File

@ -3,17 +3,20 @@ use {
log::*, log::*,
solana_measure::measure::Measure, solana_measure::measure::Measure,
solana_sdk::clock::Slot, solana_sdk::clock::Slot,
std::ops::{Bound, Range, RangeBounds}, std::{
collections::HashMap,
ops::{Bound, Range, RangeBounds},
},
}; };
/// Provide access to SnapshotStorages sorted by slot /// Provide access to SnapshotStorageOnes sorted by slot
pub struct SortedStorages<'a> { pub struct SortedStorages<'a> {
/// range of slots where storages exist (likely sparse) /// range of slots where storages exist (likely sparse)
range: Range<Slot>, range: Range<Slot>,
/// the actual storages. index is (slot - range.start) /// the actual storages
storages: Vec<Option<&'a SnapshotStorageOne>>, /// A HashMap allows sparse storage and fast lookup of Slot -> Storage.
slot_count: usize, /// We expect ~432k slots.
storage_count: usize, storages: HashMap<Slot, &'a SnapshotStorageOne>,
} }
impl<'a> SortedStorages<'a> { impl<'a> SortedStorages<'a> {
@ -21,9 +24,7 @@ impl<'a> SortedStorages<'a> {
pub fn empty() -> Self { pub fn empty() -> Self {
SortedStorages { SortedStorages {
range: Range::default(), range: Range::default(),
storages: Vec::default(), storages: HashMap::default(),
slot_count: 0,
storage_count: 0,
} }
} }
@ -36,12 +37,7 @@ impl<'a> SortedStorages<'a> {
} }
fn get(&self, slot: Slot) -> Option<&SnapshotStorageOne> { fn get(&self, slot: Slot) -> Option<&SnapshotStorageOne> {
if !self.range.contains(&slot) { self.storages.get(&slot).copied()
None
} else {
let index = (slot - self.range.start) as usize;
self.storages[index]
}
} }
pub fn range_width(&self) -> Slot { pub fn range_width(&self) -> Slot {
@ -57,11 +53,11 @@ impl<'a> SortedStorages<'a> {
} }
pub fn slot_count(&self) -> usize { pub fn slot_count(&self) -> usize {
self.slot_count self.storages.len()
} }
pub fn storage_count(&self) -> usize { pub fn storage_count(&self) -> usize {
self.storage_count self.storages.len()
} }
// assumptions: // assumptions:
@ -113,31 +109,24 @@ impl<'a> SortedStorages<'a> {
time.stop(); time.stop();
let mut time2 = Measure::start("sort"); let mut time2 = Measure::start("sort");
let range; let range;
let mut storages; let mut storages = HashMap::default();
if min > max { if min > max {
range = Range::default(); range = Range::default();
storages = vec![];
} else { } else {
range = Range { range = Range {
start: min, start: min,
end: max, end: max,
}; };
let len = max - min;
storages = vec![None; len as usize];
source.for_each(|(original_storages, slot)| { source.for_each(|(original_storages, slot)| {
let index = (slot - min) as usize; assert!(
assert!(storages[index].is_none(), "slots are not unique"); // we should not encounter the same slot twice storages.insert(slot, original_storages).is_none(),
storages[index] = Some(original_storages); "slots are not unique"
); // we should not encounter the same slot twice
}); });
} }
time2.stop(); time2.stop();
debug!("SortedStorages, times: {}, {}", time.as_us(), time2.as_us()); debug!("SortedStorages, times: {}, {}", time.as_us(), time2.as_us());
Self { Self { range, storages }
range,
storages,
slot_count,
storage_count,
}
} }
} }
@ -213,22 +202,16 @@ pub mod tests {
}; };
impl<'a> SortedStorages<'a> { impl<'a> SortedStorages<'a> {
pub fn new_debug(source: &[(&'a SnapshotStorageOne, Slot)], min: Slot, len: usize) -> Self { pub fn new_debug(source: &[(&'a SnapshotStorageOne, Slot)], min: Slot, len: usize) -> Self {
let mut storages = vec![None; len]; let mut storages = HashMap::default();
let range = Range { let range = Range {
start: min, start: min,
end: min + len as Slot, end: min + len as Slot,
}; };
let slot_count = source.len();
for (storage, slot) in source { for (storage, slot) in source {
storages[*slot as usize] = Some(*storage); storages.insert(*slot, *storage);
} }
Self { Self { range, storages }
range,
storages,
slot_count,
storage_count: 0,
}
} }
pub fn new_for_tests(storages: &[&'a SnapshotStorageOne], slots: &[Slot]) -> Self { pub fn new_for_tests(storages: &[&'a SnapshotStorageOne], slots: &[Slot]) -> Self {
@ -350,7 +333,7 @@ pub mod tests {
fn test_sorted_storages_none() { fn test_sorted_storages_none() {
let result = SortedStorages::empty(); let result = SortedStorages::empty();
assert_eq!(result.range, Range::default()); assert_eq!(result.range, Range::default());
assert_eq!(result.slot_count, 0); assert_eq!(result.slot_count(), 0);
assert_eq!(result.storages.len(), 0); assert_eq!(result.storages.len(), 0);
assert!(result.get(0).is_none()); assert!(result.get(0).is_none());
} }
@ -368,7 +351,7 @@ pub mod tests {
end: slot + 1 end: slot + 1
} }
); );
assert_eq!(result.slot_count, 1); assert_eq!(result.slot_count(), 1);
assert_eq!(result.storages.len(), 1); assert_eq!(result.storages.len(), 1);
assert_eq!( assert_eq!(
result.get(slot).unwrap().append_vec_id(), result.get(slot).unwrap().append_vec_id(),
@ -402,8 +385,8 @@ pub mod tests {
end: slots[1] + 1, end: slots[1] + 1,
} }
); );
assert_eq!(result.slot_count, 2); assert_eq!(result.slot_count(), 2);
assert_eq!(result.storages.len() as Slot, slots[1] - slots[0] + 1); assert_eq!(result.storages.len(), 2);
assert!(result.get(0).is_none()); assert!(result.get(0).is_none());
assert!(result.get(3).is_none()); assert!(result.get(3).is_none());
assert!(result.get(5).is_none()); assert!(result.get(5).is_none());