Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

disk index: include T on a few structs #30983

Merged
merged 1 commit into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions bucket_map/src/bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,18 @@ impl<I: BucketOccupied, D: BucketOccupied> Reallocated<I, D> {
}

// >= 2 instances of BucketStorage per 'bucket' in the bucket map. 1 for index, >= 1 for data
pub struct Bucket<T> {
pub struct Bucket<T: 'static> {
drives: Arc<Vec<PathBuf>>,
//index
pub index: BucketStorage<IndexBucket>,
pub index: BucketStorage<IndexBucket<T>>,
brooksprumo marked this conversation as resolved.
Show resolved Hide resolved
//random offset for the index
random: u64,
//storage buckets to store SlotSlice up to a power of 2 in len
pub data: Vec<BucketStorage<DataBucket>>,
_phantom: PhantomData<T>,
stats: Arc<BucketMapStats>,

pub reallocated: Reallocated<IndexBucket, DataBucket>,
pub reallocated: Reallocated<IndexBucket<T>, DataBucket>,
}

impl<'b, T: Clone + Copy + 'static> Bucket<T> {
Expand Down Expand Up @@ -156,7 +156,7 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
result
}

pub fn find_index_entry(&self, key: &Pubkey) -> Option<(IndexEntryPlaceInBucket, u64)> {
pub fn find_index_entry(&self, key: &Pubkey) -> Option<(IndexEntryPlaceInBucket<T>, u64)> {
Self::bucket_find_index_entry(&self.index, key, self.random)
}

Expand All @@ -165,10 +165,10 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
/// if entry does not exist, return just the index of an empty entry appropriate for this key
/// returns (existing entry, index of the found or empty entry)
fn find_index_entry_mut(
index: &mut BucketStorage<IndexBucket>,
index: &mut BucketStorage<IndexBucket<T>>,
key: &Pubkey,
random: u64,
) -> Result<(Option<IndexEntryPlaceInBucket>, u64), BucketMapError> {
) -> Result<(Option<IndexEntryPlaceInBucket<T>>, u64), BucketMapError> {
let ix = Self::bucket_index_ix(index, key, random);
let mut first_free = None;
let mut m = Measure::start("bucket_find_index_entry_mut");
Expand Down Expand Up @@ -204,10 +204,10 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
}

fn bucket_find_index_entry(
index: &BucketStorage<IndexBucket>,
index: &BucketStorage<IndexBucket<T>>,
key: &Pubkey,
random: u64,
) -> Option<(IndexEntryPlaceInBucket, u64)> {
) -> Option<(IndexEntryPlaceInBucket<T>, u64)> {
let ix = Self::bucket_index_ix(index, key, random);
for i in ix..ix + index.max_search() {
let ii = i % index.capacity();
Expand All @@ -223,7 +223,7 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
}

fn bucket_create_key(
index: &mut BucketStorage<IndexBucket>,
index: &mut BucketStorage<IndexBucket<T>>,
key: &Pubkey,
random: u64,
is_resizing: bool,
Expand Down Expand Up @@ -420,7 +420,7 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
}
}

pub fn apply_grow_index(&mut self, random: u64, index: BucketStorage<IndexBucket>) {
pub fn apply_grow_index(&mut self, random: u64, index: BucketStorage<IndexBucket<T>>) {
self.stats
.index
.resize_grow(self.index.capacity_bytes(), index.capacity_bytes());
Expand Down Expand Up @@ -479,7 +479,7 @@ impl<'b, T: Clone + Copy + 'static> Bucket<T> {
items.data = Some((data_index, new_bucket));
}

fn bucket_index_ix(index: &BucketStorage<IndexBucket>, key: &Pubkey, random: u64) -> u64 {
fn bucket_index_ix(index: &BucketStorage<IndexBucket<T>>, key: &Pubkey, random: u64) -> u64 {
let mut s = DefaultHasher::new();
key.hash(&mut s);
//the locally generated random will make it hard for an attacker
Expand Down
2 changes: 1 addition & 1 deletion bucket_map/src/bucket_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ mod test {
let paths: Vec<PathBuf> = vec![tmpdir.path().to_path_buf()];
assert!(!paths.is_empty());

let mut storage = BucketStorage::<IndexBucket>::new(
let mut storage = BucketStorage::<IndexBucket<u64>>::new(
Arc::new(paths),
1,
1,
Expand Down
62 changes: 37 additions & 25 deletions bucket_map/src/index_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
bv::BitVec,
modular_bitfield::prelude::*,
solana_sdk::{clock::Slot, pubkey::Pubkey},
std::fmt::Debug,
std::{fmt::Debug, marker::PhantomData},
};

/// in use/occupied
Expand All @@ -25,11 +25,12 @@ struct OccupiedHeader {
}

/// allocated in `contents` in a BucketStorage
pub struct BucketWithBitVec {
pub struct BucketWithBitVec<T: 'static> {
pub occupied: BitVec,
_phantom: PhantomData<&'static T>,
}

impl BucketOccupied for BucketWithBitVec {
impl<T> BucketOccupied for BucketWithBitVec<T> {
fn occupy(&mut self, element: &mut [u8], ix: usize) {
assert!(self.is_free(element, ix));
self.occupied.set(ix as u64, true);
Expand All @@ -48,17 +49,19 @@ impl BucketOccupied for BucketWithBitVec {
fn new(num_elements: usize) -> Self {
Self {
occupied: BitVec::new_fill(false, num_elements as u64),
_phantom: PhantomData,
}
}
}

pub type DataBucket = BucketWithBitVec;
pub type IndexBucket = BucketWithBitVec;
pub type DataBucket = BucketWithBitVec<()>;
pub type IndexBucket<T> = BucketWithBitVec<T>;

/// contains the index of an entry in the index bucket.
/// This type allows us to call methods to interact with the index entry on this type.
pub struct IndexEntryPlaceInBucket {
pub struct IndexEntryPlaceInBucket<T: 'static> {
pub ix: u64,
_phantom: PhantomData<&'static T>,
brooksprumo marked this conversation as resolved.
Show resolved Hide resolved
}

#[repr(C)]
Expand Down Expand Up @@ -98,8 +101,8 @@ impl IndexEntry {
}
}

impl IndexEntryPlaceInBucket {
pub fn init(&self, index_bucket: &mut BucketStorage<IndexBucket>, pubkey: &Pubkey) {
impl<T> IndexEntryPlaceInBucket<T> {
pub fn init(&self, index_bucket: &mut BucketStorage<IndexBucket<T>>, pubkey: &Pubkey) {
let index_entry = index_bucket.get_mut::<IndexEntry>(self.ix);
index_entry.key = *pubkey;
index_entry.ref_count = 0;
Expand All @@ -109,7 +112,7 @@ impl IndexEntryPlaceInBucket {

pub fn set_storage_capacity_when_created_pow2(
&self,
index_bucket: &mut BucketStorage<IndexBucket>,
index_bucket: &mut BucketStorage<IndexBucket<T>>,
storage_capacity_when_created_pow2: u8,
) {
index_bucket
Expand All @@ -120,7 +123,7 @@ impl IndexEntryPlaceInBucket {

pub fn set_storage_offset(
&self,
index_bucket: &mut BucketStorage<IndexBucket>,
index_bucket: &mut BucketStorage<IndexBucket<T>>,
storage_offset: u64,
) {
index_bucket
Expand All @@ -130,23 +133,26 @@ impl IndexEntryPlaceInBucket {
.expect("New storage offset must fit into 7 bytes!");
}

pub fn data_bucket_ix(&self, index_bucket: &BucketStorage<IndexBucket>) -> u64 {
pub fn data_bucket_ix(&self, index_bucket: &BucketStorage<IndexBucket<T>>) -> u64 {
IndexEntry::data_bucket_from_num_slots(self.num_slots(index_bucket))
}

pub fn ref_count(&self, index_bucket: &BucketStorage<IndexBucket>) -> RefCount {
pub fn ref_count(&self, index_bucket: &BucketStorage<IndexBucket<T>>) -> RefCount {
let index_entry = index_bucket.get::<IndexEntry>(self.ix);
index_entry.ref_count
}

fn storage_capacity_when_created_pow2(&self, index_bucket: &BucketStorage<IndexBucket>) -> u8 {
fn storage_capacity_when_created_pow2(
&self,
index_bucket: &BucketStorage<IndexBucket<T>>,
) -> u8 {
let index_entry = index_bucket.get::<IndexEntry>(self.ix);
index_entry
.storage_cap_and_offset
.capacity_when_created_pow2()
}

pub fn storage_offset(&self, index_bucket: &BucketStorage<IndexBucket>) -> u64 {
pub fn storage_offset(&self, index_bucket: &BucketStorage<IndexBucket<T>>) -> u64 {
index_bucket
.get::<IndexEntry>(self.ix)
.storage_cap_and_offset
Expand All @@ -157,7 +163,7 @@ impl IndexEntryPlaceInBucket {
/// This is coupled with how we resize bucket storages.
pub fn data_loc(
&self,
index_bucket: &BucketStorage<IndexBucket>,
index_bucket: &BucketStorage<IndexBucket<T>>,
storage: &BucketStorage<DataBucket>,
) -> u64 {
let index_entry = index_bucket.get::<IndexEntry>(self.ix);
Expand All @@ -168,9 +174,9 @@ impl IndexEntryPlaceInBucket {
.capacity_when_created_pow2())
}

pub fn read_value<'a, T>(
pub fn read_value<'a>(
&self,
index_bucket: &BucketStorage<IndexBucket>,
index_bucket: &BucketStorage<IndexBucket<T>>,
data_buckets: &'a [BucketStorage<DataBucket>],
) -> Option<(&'a [T], RefCount)> {
let num_slots = self.num_slots(index_bucket);
Expand All @@ -188,28 +194,31 @@ impl IndexEntryPlaceInBucket {
}

pub fn new(ix: u64) -> Self {
Self { ix }
Self {
ix,
_phantom: PhantomData,
}
}

pub fn key<'a>(&self, index_bucket: &'a BucketStorage<IndexBucket>) -> &'a Pubkey {
pub fn key<'a>(&self, index_bucket: &'a BucketStorage<IndexBucket<T>>) -> &'a Pubkey {
let entry: &IndexEntry = index_bucket.get(self.ix);
&entry.key
}

pub fn set_ref_count(
&self,
index_bucket: &mut BucketStorage<IndexBucket>,
index_bucket: &mut BucketStorage<IndexBucket<T>>,
ref_count: RefCount,
) {
let index_entry = index_bucket.get_mut::<IndexEntry>(self.ix);
index_entry.ref_count = ref_count;
}

pub fn num_slots(&self, index_bucket: &BucketStorage<IndexBucket>) -> Slot {
pub fn num_slots(&self, index_bucket: &BucketStorage<IndexBucket<T>>) -> Slot {
index_bucket.get::<IndexEntry>(self.ix).num_slots
}

pub fn set_num_slots(&self, index_bucket: &mut BucketStorage<IndexBucket>, num_slots: Slot) {
pub fn set_num_slots(&self, index_bucket: &mut BucketStorage<IndexBucket<T>>, num_slots: Slot) {
index_bucket.get_mut::<IndexEntry>(self.ix).num_slots = num_slots;
}
}
Expand Down Expand Up @@ -261,13 +270,13 @@ mod tests {
assert_eq!(std::mem::size_of::<IndexEntry>(), 32 + 8 + 8 + 8);
}

fn index_bucket_for_testing() -> BucketStorage<IndexBucket> {
fn index_bucket_for_testing() -> BucketStorage<IndexBucket<u64>> {
let tmpdir = tempdir().unwrap();
let paths: Vec<PathBuf> = vec![tmpdir.path().to_path_buf()];
assert!(!paths.is_empty());

// `new` here creates a file in `tmpdir`. Once the file is created, `tmpdir` can be dropped without issue.
BucketStorage::<IndexBucket>::new(
BucketStorage::<IndexBucket<u64>>::new(
Arc::new(paths),
1,
std::mem::size_of::<IndexEntry>() as u64,
Expand All @@ -277,7 +286,10 @@ mod tests {
)
}

fn index_entry_for_testing() -> (BucketStorage<IndexBucket>, IndexEntryPlaceInBucket) {
fn index_entry_for_testing() -> (
BucketStorage<IndexBucket<u64>>,
IndexEntryPlaceInBucket<u64>,
) {
(index_bucket_for_testing(), IndexEntryPlaceInBucket::new(0))
}

Expand Down