diff --git a/bucket_map/src/bucket.rs b/bucket_map/src/bucket.rs index 6f812c07e..d0c78e538 100644 --- a/bucket_map/src/bucket.rs +++ b/bucket_map/src/bucket.rs @@ -3,7 +3,7 @@ use { bucket_item::BucketItem, bucket_map::BucketMapError, bucket_stats::BucketMapStats, - bucket_storage::{BucketStorage, Uid, DEFAULT_CAPACITY_POW2, UID_UNLOCKED}, + bucket_storage::{BucketStorage, Uid, DEFAULT_CAPACITY_POW2}, index_entry::IndexEntry, MaxSearch, RefCount, }, @@ -105,7 +105,7 @@ impl Bucket { pub fn keys(&self) -> Vec { let mut rv = vec![]; for i in 0..self.index.capacity() { - if self.index.uid(i) == UID_UNLOCKED { + if self.index.uid(i).is_none() { continue; } let ix: &IndexEntry = self.index.get(i); @@ -121,7 +121,7 @@ impl Bucket { let mut result = Vec::with_capacity(self.index.count.load(Ordering::Relaxed) as usize); for i in 0..self.index.capacity() { let ii = i % self.index.capacity(); - if self.index.uid(ii) == UID_UNLOCKED { + if self.index.uid(ii).is_none() { continue; } let ix: &IndexEntry = self.index.get(ii); @@ -154,7 +154,7 @@ impl Bucket { let ix = Self::bucket_index_ix(index, key, random); for i in ix..ix + index.max_search() { let ii = i % index.capacity(); - if index.uid(ii) == UID_UNLOCKED { + if index.uid(ii).is_none() { continue; } let elem: &mut IndexEntry = index.get_mut(ii); @@ -173,7 +173,7 @@ impl Bucket { let ix = Self::bucket_index_ix(index, key, random); for i in ix..ix + index.max_search() { let ii = i % index.capacity(); - if index.uid(ii) == UID_UNLOCKED { + if index.uid(ii).is_none() { continue; } let elem: &IndexEntry = index.get(ii); @@ -194,7 +194,7 @@ impl Bucket { let ix = Self::bucket_index_ix(index, key, random); for i in ix..ix + index.max_search() { let ii = i as u64 % index.capacity(); - if index.uid(ii) != UID_UNLOCKED { + if index.uid(ii).is_some() { continue; } index.allocate(ii, elem_uid, is_resizing).unwrap(); @@ -257,14 +257,14 @@ impl Bucket { Some(res) => res, }; elem.ref_count = ref_count; - let elem_uid = self.index.uid(elem_ix); + let elem_uid = self.index.uid_unchecked(elem_ix); let bucket_ix = elem.data_bucket_ix(); let current_bucket = &self.data[bucket_ix as usize]; if best_fit_bucket == bucket_ix && elem.num_slots > 0 { // in place update let elem_loc = elem.data_loc(current_bucket); let slice: &mut [T] = current_bucket.get_mut_cell_slice(elem_loc, data.len() as u64); - assert!(current_bucket.uid(elem_loc) == elem_uid); + assert!(current_bucket.uid(elem_loc) == Some(elem_uid)); elem.num_slots = data.len() as u64; slice.copy_from_slice(data); Ok(()) @@ -276,7 +276,7 @@ impl Bucket { let pos = thread_rng().gen_range(0, cap); for i in pos..pos + self.index.max_search() { let ix = i % cap; - if best_bucket.uid(ix) == UID_UNLOCKED { + if best_bucket.uid(ix).is_none() { let elem_loc = elem.data_loc(current_bucket); if elem.num_slots > 0 { current_bucket.free(elem_loc, elem_uid); @@ -299,7 +299,7 @@ impl Bucket { pub fn delete_key(&mut self, key: &Pubkey) { if let Some((elem, elem_ix)) = self.find_entry(key) { - let elem_uid = self.index.uid(elem_ix); + let elem_uid = self.index.uid_unchecked(elem_ix); if elem.num_slots > 0 { let data_bucket = &self.data[elem.data_bucket_ix() as usize]; let loc = elem.data_loc(data_bucket); @@ -334,7 +334,7 @@ impl Bucket { let mut valid = true; for ix in 0..self.index.capacity() { let uid = self.index.uid(ix); - if UID_UNLOCKED != uid { + if let Some(uid) = uid { let elem: &IndexEntry = self.index.get(ix); let new_ix = Self::bucket_create_key(&index, &elem.key, uid, random, true); if new_ix.is_err() { diff --git a/bucket_map/src/bucket_storage.rs b/bucket_map/src/bucket_storage.rs index da50bd8d8..99203bdf3 100644 --- a/bucket_map/src/bucket_storage.rs +++ b/bucket_map/src/bucket_storage.rs @@ -35,7 +35,7 @@ use { pub const DEFAULT_CAPACITY_POW2: u8 = 5; /// A Header UID of 0 indicates that the header is unlocked -pub(crate) const UID_UNLOCKED: Uid = 0; +const UID_UNLOCKED: Uid = 0; pub(crate) type Uid = u64; @@ -54,8 +54,13 @@ impl Header { fn unlock(&self) -> Uid { self.lock.swap(UID_UNLOCKED, Ordering::Release) } - fn uid(&self) -> Uid { - self.lock.load(Ordering::Acquire) + fn uid(&self) -> Option { + let result = self.lock.load(Ordering::Acquire); + if result == UID_UNLOCKED { + None + } else { + Some(result) + } } } @@ -136,11 +141,16 @@ impl BucketStorage { } } - pub fn uid(&self, ix: u64) -> Uid { + pub fn uid(&self, ix: u64) -> Option { assert!(ix < self.capacity(), "bad index size"); self.header_ptr(ix).uid() } + /// caller knows id is not empty + pub fn uid_unchecked(&self, ix: u64) -> Uid { + self.uid(ix).unwrap() + } + /// 'is_resizing' true if caller is resizing the index (so don't increment count) /// 'is_resizing' false if caller is adding an item to the index (so increment count) pub fn allocate(&self, ix: u64, uid: Uid, is_resizing: bool) -> Result<(), BucketStorageError> { diff --git a/bucket_map/src/index_entry.rs b/bucket_map/src/index_entry.rs index 201c56407..61df1f807 100644 --- a/bucket_map/src/index_entry.rs +++ b/bucket_map/src/index_entry.rs @@ -69,7 +69,7 @@ impl IndexEntry { let slice = if self.num_slots > 0 { let loc = self.data_loc(data_bucket); let uid = Self::key_uid(&self.key); - assert_eq!(uid, bucket.data[data_bucket_ix as usize].uid(loc)); + assert_eq!(Some(uid), bucket.data[data_bucket_ix as usize].uid(loc)); bucket.data[data_bucket_ix as usize].get_cell_slice(loc, self.num_slots) } else { // num_slots is 0. This means we don't have an actual allocation.