From 2cafd641fe2e0b995d2014480a62c03b0d4bcb25 Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" Date: Thu, 30 Mar 2023 13:27:45 -0500 Subject: [PATCH] disk index: introduce MultipleSlots (#30988) * disk index: introduce MultipleSlots * pr feedback --- bucket_map/src/index_entry.rs | 93 +++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/bucket_map/src/index_entry.rs b/bucket_map/src/index_entry.rs index 9d9daba31..13d1f9f59 100644 --- a/bucket_map/src/index_entry.rs +++ b/bucket_map/src/index_entry.rs @@ -65,18 +65,47 @@ pub struct IndexEntryPlaceInBucket { } #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone)] // one instance of this per item in the index // stored in the index bucket pub struct IndexEntry { pub key: Pubkey, // can this be smaller if we have reduced the keys into buckets already? ref_count: RefCount, // can this be smaller? Do we ever need more than 4B refcounts? - storage_cap_and_offset: PackedStorage, - // if the bucket doubled, the index can be recomputed using create_bucket_capacity_pow2 - num_slots: Slot, // can this be smaller? epoch size should ~ be the max len. this is the num elements in the slot list + multiple_slots: MultipleSlots, _phantom: PhantomData<&'static T>, } +/// required fields when an index element references the data file +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +struct MultipleSlots { + // if the bucket doubled, the index can be recomputed using storage_cap_and_offset.create_bucket_capacity_pow2 + storage_cap_and_offset: PackedStorage, + /// num elements in the slot list + num_slots: Slot, // can this be smaller? epoch size should ~ be the max len. this is the num elements in the slot list +} + +impl MultipleSlots { + fn set_storage_capacity_when_created_pow2(&mut self, storage_capacity_when_created_pow2: u8) { + self.storage_cap_and_offset + .set_capacity_when_created_pow2(storage_capacity_when_created_pow2) + } + + fn set_storage_offset(&mut self, storage_offset: u64) { + self.storage_cap_and_offset + .set_offset_checked(storage_offset) + .expect("New storage offset must fit into 7 bytes!") + } + + fn storage_capacity_when_created_pow2(&self) -> u8 { + self.storage_cap_and_offset.capacity_when_created_pow2() + } + + fn storage_offset(&self) -> u64 { + self.storage_cap_and_offset.offset() + } +} + /// Pack the storage offset and capacity-when-crated-pow2 fields into a single u64 #[bitfield(bits = 64)] #[repr(C)] @@ -107,8 +136,7 @@ impl IndexEntryPlaceInBucket { let index_entry = index_bucket.get_mut::>(self.ix); index_entry.key = *pubkey; index_entry.ref_count = 0; - index_entry.storage_cap_and_offset = PackedStorage::default(); - index_entry.num_slots = 0; + index_entry.multiple_slots = MultipleSlots::default(); } pub fn set_storage_capacity_when_created_pow2( @@ -116,10 +144,8 @@ impl IndexEntryPlaceInBucket { index_bucket: &mut BucketStorage>, storage_capacity_when_created_pow2: u8, ) { - index_bucket - .get_mut::>(self.ix) - .storage_cap_and_offset - .set_capacity_when_created_pow2(storage_capacity_when_created_pow2) + self.get_multiple_slots_mut(index_bucket) + .set_storage_capacity_when_created_pow2(storage_capacity_when_created_pow2); } pub fn set_storage_offset( @@ -127,17 +153,30 @@ impl IndexEntryPlaceInBucket { index_bucket: &mut BucketStorage>, storage_offset: u64, ) { - index_bucket - .get_mut::>(self.ix) - .storage_cap_and_offset - .set_offset_checked(storage_offset) - .expect("New storage offset must fit into 7 bytes!"); + self.get_multiple_slots_mut(index_bucket) + .set_storage_offset(storage_offset); } pub fn data_bucket_ix(&self, index_bucket: &BucketStorage>) -> u64 { IndexEntry::::data_bucket_from_num_slots(self.num_slots(index_bucket)) } + fn get_multiple_slots<'a>( + &self, + index_bucket: &'a BucketStorage>, + ) -> &'a MultipleSlots { + &index_bucket.get::>(self.ix).multiple_slots + } + + fn get_multiple_slots_mut<'a>( + &self, + index_bucket: &'a mut BucketStorage>, + ) -> &'a mut MultipleSlots { + &mut index_bucket + .get_mut::>(self.ix) + .multiple_slots + } + pub fn ref_count(&self, index_bucket: &BucketStorage>) -> RefCount { let index_entry = index_bucket.get::>(self.ix); index_entry.ref_count @@ -147,17 +186,12 @@ impl IndexEntryPlaceInBucket { &self, index_bucket: &BucketStorage>, ) -> u8 { - let index_entry = index_bucket.get::>(self.ix); - index_entry - .storage_cap_and_offset - .capacity_when_created_pow2() + self.get_multiple_slots(index_bucket) + .storage_capacity_when_created_pow2() } pub fn storage_offset(&self, index_bucket: &BucketStorage>) -> u64 { - index_bucket - .get::>(self.ix) - .storage_cap_and_offset - .offset() + self.get_multiple_slots(index_bucket).storage_offset() } /// This function maps the original data location into an index in the current bucket storage. @@ -167,12 +201,8 @@ impl IndexEntryPlaceInBucket { index_bucket: &BucketStorage>, storage: &BucketStorage, ) -> u64 { - let index_entry = index_bucket.get::>(self.ix); self.storage_offset(index_bucket) - << (storage.capacity_pow2 - - index_entry - .storage_cap_and_offset - .capacity_when_created_pow2()) + << (storage.capacity_pow2 - self.storage_capacity_when_created_pow2(index_bucket)) } pub fn read_value<'a>( @@ -216,11 +246,11 @@ impl IndexEntryPlaceInBucket { } pub fn num_slots(&self, index_bucket: &BucketStorage>) -> Slot { - index_bucket.get::>(self.ix).num_slots + self.get_multiple_slots(index_bucket).num_slots } pub fn set_num_slots(&self, index_bucket: &mut BucketStorage>, num_slots: Slot) { - index_bucket.get_mut::>(self.ix).num_slots = num_slots; + self.get_multiple_slots_mut(index_bucket).num_slots = num_slots; } } @@ -237,8 +267,7 @@ mod tests { IndexEntry { key, ref_count: 0, - storage_cap_and_offset: PackedStorage::default(), - num_slots: 0, + multiple_slots: MultipleSlots::default(), _phantom: PhantomData, } }