2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
bucket_item::BucketItem,
|
|
|
|
bucket_map::BucketMapError,
|
|
|
|
bucket_stats::BucketMapStats,
|
2021-12-21 12:51:38 -08:00
|
|
|
bucket_storage::{BucketStorage, Uid, DEFAULT_CAPACITY_POW2},
|
2021-12-03 09:00:31 -08:00
|
|
|
index_entry::IndexEntry,
|
|
|
|
MaxSearch, RefCount,
|
|
|
|
},
|
|
|
|
rand::{thread_rng, Rng},
|
|
|
|
solana_measure::measure::Measure,
|
|
|
|
solana_sdk::pubkey::Pubkey,
|
|
|
|
std::{
|
|
|
|
collections::hash_map::DefaultHasher,
|
|
|
|
hash::{Hash, Hasher},
|
|
|
|
marker::PhantomData,
|
|
|
|
ops::RangeBounds,
|
|
|
|
path::PathBuf,
|
|
|
|
sync::{
|
2021-12-16 19:25:54 -08:00
|
|
|
atomic::{AtomicU64, AtomicUsize, Ordering},
|
2021-12-03 09:00:31 -08:00
|
|
|
Arc, Mutex,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2021-10-05 07:59:17 -07:00
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct ReallocatedItems {
|
|
|
|
// Some if the index was reallocated
|
|
|
|
// u64 is random associated with the new index
|
|
|
|
pub index: Option<(u64, BucketStorage)>,
|
|
|
|
// Some for a data bucket reallocation
|
|
|
|
// u64 is data bucket index
|
|
|
|
pub data: Option<(u64, BucketStorage)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct Reallocated {
|
|
|
|
/// > 0 if reallocations are encoded
|
|
|
|
pub active_reallocations: AtomicUsize,
|
|
|
|
|
|
|
|
/// actual reallocated bucket
|
|
|
|
/// mutex because bucket grow code runs with a read lock
|
|
|
|
pub items: Mutex<ReallocatedItems>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Reallocated {
|
|
|
|
/// specify that a reallocation has occurred
|
|
|
|
pub fn add_reallocation(&self) {
|
|
|
|
assert_eq!(
|
|
|
|
0,
|
|
|
|
self.active_reallocations.fetch_add(1, Ordering::Relaxed),
|
|
|
|
"Only 1 reallocation can occur at a time"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
/// Return true IFF a reallocation has occurred.
|
|
|
|
/// Calling this takes conceptual ownership of the reallocation encoded in the struct.
|
|
|
|
pub fn get_reallocated(&self) -> bool {
|
|
|
|
self.active_reallocations
|
|
|
|
.compare_exchange(1, 0, Ordering::Acquire, Ordering::Relaxed)
|
|
|
|
.is_ok()
|
|
|
|
}
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
|
|
|
|
// >= 2 instances of BucketStorage per 'bucket' in the bucket map. 1 for index, >= 1 for data
|
|
|
|
pub struct Bucket<T> {
|
|
|
|
drives: Arc<Vec<PathBuf>>,
|
|
|
|
//index
|
2021-10-05 07:59:17 -07:00
|
|
|
pub index: BucketStorage,
|
2021-09-17 13:11:27 -07:00
|
|
|
//random offset for the index
|
|
|
|
random: u64,
|
|
|
|
//storage buckets to store SlotSlice up to a power of 2 in len
|
|
|
|
pub data: Vec<BucketStorage>,
|
|
|
|
_phantom: PhantomData<T>,
|
|
|
|
stats: Arc<BucketMapStats>,
|
2021-10-05 07:59:17 -07:00
|
|
|
|
|
|
|
pub reallocated: Reallocated,
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
2023-02-22 14:43:10 -08:00
|
|
|
impl<'b, T: Clone + Copy + 'b> Bucket<T> {
|
2021-09-17 13:11:27 -07:00
|
|
|
pub fn new(
|
|
|
|
drives: Arc<Vec<PathBuf>>,
|
|
|
|
max_search: MaxSearch,
|
|
|
|
stats: Arc<BucketMapStats>,
|
2021-12-16 19:25:54 -08:00
|
|
|
count: Arc<AtomicU64>,
|
2021-09-17 13:11:27 -07:00
|
|
|
) -> Self {
|
|
|
|
let index = BucketStorage::new(
|
|
|
|
Arc::clone(&drives),
|
|
|
|
1,
|
|
|
|
std::mem::size_of::<IndexEntry>() as u64,
|
|
|
|
max_search,
|
|
|
|
Arc::clone(&stats.index),
|
2021-12-16 19:25:54 -08:00
|
|
|
count,
|
2021-09-17 13:11:27 -07:00
|
|
|
);
|
|
|
|
Self {
|
|
|
|
random: thread_rng().gen(),
|
|
|
|
drives,
|
|
|
|
index,
|
|
|
|
data: vec![],
|
2023-02-23 14:59:08 -08:00
|
|
|
_phantom: PhantomData,
|
2021-09-17 13:11:27 -07:00
|
|
|
stats,
|
2021-10-05 07:59:17 -07:00
|
|
|
reallocated: Reallocated::default(),
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn keys(&self) -> Vec<Pubkey> {
|
|
|
|
let mut rv = vec![];
|
2021-09-23 18:08:06 -07:00
|
|
|
for i in 0..self.index.capacity() {
|
2021-12-22 13:12:34 -08:00
|
|
|
if self.index.is_free(i) {
|
2021-09-17 13:11:27 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let ix: &IndexEntry = self.index.get(i);
|
|
|
|
rv.push(ix.key);
|
|
|
|
}
|
|
|
|
rv
|
|
|
|
}
|
|
|
|
|
2021-09-23 11:57:56 -07:00
|
|
|
pub fn items_in_range<R>(&self, range: &Option<&R>) -> Vec<BucketItem<T>>
|
2021-09-17 13:11:27 -07:00
|
|
|
where
|
|
|
|
R: RangeBounds<Pubkey>,
|
|
|
|
{
|
2021-12-16 19:25:54 -08:00
|
|
|
let mut result = Vec::with_capacity(self.index.count.load(Ordering::Relaxed) as usize);
|
2021-09-23 18:08:06 -07:00
|
|
|
for i in 0..self.index.capacity() {
|
|
|
|
let ii = i % self.index.capacity();
|
2021-12-22 13:12:34 -08:00
|
|
|
if self.index.is_free(ii) {
|
2021-09-17 13:11:27 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let ix: &IndexEntry = self.index.get(ii);
|
|
|
|
let key = ix.key;
|
|
|
|
if range.map(|r| r.contains(&key)).unwrap_or(true) {
|
|
|
|
let val = ix.read_value(self);
|
|
|
|
result.push(BucketItem {
|
|
|
|
pubkey: key,
|
|
|
|
ref_count: ix.ref_count(),
|
|
|
|
slot_list: val.map(|(v, _ref_count)| v.to_vec()).unwrap_or_default(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn find_entry(&self, key: &Pubkey) -> Option<(&IndexEntry, u64)> {
|
|
|
|
Self::bucket_find_entry(&self.index, key, self.random)
|
|
|
|
}
|
|
|
|
|
2022-07-29 11:58:05 -07:00
|
|
|
fn find_entry_mut<'a>(
|
|
|
|
&'a self,
|
2021-09-17 13:11:27 -07:00
|
|
|
key: &Pubkey,
|
2022-07-29 11:58:05 -07:00
|
|
|
) -> Result<(bool, &'a mut IndexEntry, u64), BucketMapError> {
|
|
|
|
let ix = Self::bucket_index_ix(&self.index, key, self.random);
|
|
|
|
let mut first_free = None;
|
2022-07-25 12:47:17 -07:00
|
|
|
let mut m = Measure::start("bucket_find_entry_mut");
|
2022-07-29 11:58:05 -07:00
|
|
|
for i in ix..ix + self.index.max_search() {
|
|
|
|
let ii = i % self.index.capacity();
|
|
|
|
if self.index.is_free(ii) {
|
|
|
|
if first_free.is_none() {
|
|
|
|
first_free = Some(ii);
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
continue;
|
|
|
|
}
|
2022-07-29 11:58:05 -07:00
|
|
|
let elem: &mut IndexEntry = self.index.get_mut(ii);
|
2021-09-17 13:11:27 -07:00
|
|
|
if elem.key == *key {
|
2022-07-25 12:47:17 -07:00
|
|
|
m.stop();
|
2022-07-29 11:58:05 -07:00
|
|
|
self.stats
|
|
|
|
.index
|
2022-07-25 12:47:17 -07:00
|
|
|
.find_entry_mut_us
|
|
|
|
.fetch_add(m.as_us(), Ordering::Relaxed);
|
2022-07-29 11:58:05 -07:00
|
|
|
return Ok((true, elem, ii));
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
}
|
2022-07-25 12:47:17 -07:00
|
|
|
m.stop();
|
2022-07-29 11:58:05 -07:00
|
|
|
self.stats
|
|
|
|
.index
|
2022-07-25 12:47:17 -07:00
|
|
|
.find_entry_mut_us
|
|
|
|
.fetch_add(m.as_us(), Ordering::Relaxed);
|
2022-07-29 11:58:05 -07:00
|
|
|
match first_free {
|
|
|
|
Some(ii) => {
|
|
|
|
let elem: &mut IndexEntry = self.index.get_mut(ii);
|
|
|
|
Ok((false, elem, ii))
|
|
|
|
}
|
|
|
|
None => Err(self.index_no_space()),
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn bucket_find_entry<'a>(
|
|
|
|
index: &'a BucketStorage,
|
|
|
|
key: &Pubkey,
|
|
|
|
random: u64,
|
|
|
|
) -> Option<(&'a IndexEntry, u64)> {
|
|
|
|
let ix = Self::bucket_index_ix(index, key, random);
|
|
|
|
for i in ix..ix + index.max_search() {
|
2021-09-23 18:08:06 -07:00
|
|
|
let ii = i % index.capacity();
|
2021-12-22 13:12:34 -08:00
|
|
|
if index.is_free(ii) {
|
2021-09-17 13:11:27 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let elem: &IndexEntry = index.get(ii);
|
|
|
|
if elem.key == *key {
|
|
|
|
return Some((elem, ii));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bucket_create_key(
|
2021-12-21 13:50:39 -08:00
|
|
|
index: &mut BucketStorage,
|
2021-09-17 13:11:27 -07:00
|
|
|
key: &Pubkey,
|
2021-09-21 13:09:04 -07:00
|
|
|
elem_uid: Uid,
|
2021-09-17 13:11:27 -07:00
|
|
|
random: u64,
|
2021-12-16 19:25:54 -08:00
|
|
|
is_resizing: bool,
|
2021-09-17 13:11:27 -07:00
|
|
|
) -> Result<u64, BucketMapError> {
|
2022-07-25 12:47:17 -07:00
|
|
|
let mut m = Measure::start("bucket_create_key");
|
2021-09-17 13:11:27 -07:00
|
|
|
let ix = Self::bucket_index_ix(index, key, random);
|
|
|
|
for i in ix..ix + index.max_search() {
|
2022-11-09 11:39:38 -08:00
|
|
|
let ii = i % index.capacity();
|
2021-12-22 13:12:34 -08:00
|
|
|
if !index.is_free(ii) {
|
2021-09-17 13:11:27 -07:00
|
|
|
continue;
|
|
|
|
}
|
2021-12-16 19:25:54 -08:00
|
|
|
index.allocate(ii, elem_uid, is_resizing).unwrap();
|
2021-12-17 08:16:34 -08:00
|
|
|
let elem: &mut IndexEntry = index.get_mut(ii);
|
|
|
|
// These fields will be overwritten after allocation by callers.
|
2021-12-01 10:17:32 -08:00
|
|
|
// Since this part of the mmapped file could have previously been used by someone else, there can be garbage here.
|
2021-12-17 08:16:34 -08:00
|
|
|
elem.init(key);
|
2021-09-17 13:11:27 -07:00
|
|
|
//debug!( "INDEX ALLOC {:?} {} {} {}", key, ii, index.capacity, elem_uid );
|
2022-07-25 12:47:17 -07:00
|
|
|
m.stop();
|
|
|
|
index
|
|
|
|
.stats
|
|
|
|
.find_entry_mut_us
|
|
|
|
.fetch_add(m.as_us(), Ordering::Relaxed);
|
2021-09-17 13:11:27 -07:00
|
|
|
return Ok(ii);
|
|
|
|
}
|
2022-07-25 12:47:17 -07:00
|
|
|
m.stop();
|
|
|
|
index
|
|
|
|
.stats
|
|
|
|
.find_entry_mut_us
|
|
|
|
.fetch_add(m.as_us(), Ordering::Relaxed);
|
2021-09-17 13:11:27 -07:00
|
|
|
Err(BucketMapError::IndexNoSpace(index.capacity_pow2))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn addref(&mut self, key: &Pubkey) -> Option<RefCount> {
|
2022-07-29 11:58:05 -07:00
|
|
|
if let Ok((found, elem, _)) = self.find_entry_mut(key) {
|
|
|
|
if found {
|
|
|
|
elem.ref_count += 1;
|
|
|
|
return Some(elem.ref_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unref(&mut self, key: &Pubkey) -> Option<RefCount> {
|
2022-07-29 11:58:05 -07:00
|
|
|
if let Ok((found, elem, _)) = self.find_entry_mut(key) {
|
|
|
|
if found {
|
|
|
|
elem.ref_count -= 1;
|
|
|
|
return Some(elem.ref_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_value(&self, key: &Pubkey) -> Option<(&[T], RefCount)> {
|
|
|
|
//debug!("READ_VALUE: {:?}", key);
|
|
|
|
let (elem, _) = self.find_entry(key)?;
|
|
|
|
elem.read_value(self)
|
|
|
|
}
|
|
|
|
|
2022-07-29 11:58:05 -07:00
|
|
|
fn index_no_space(&self) -> BucketMapError {
|
|
|
|
BucketMapError::IndexNoSpace(self.index.capacity_pow2)
|
|
|
|
}
|
|
|
|
|
2021-09-17 13:11:27 -07:00
|
|
|
pub fn try_write(
|
|
|
|
&mut self,
|
|
|
|
key: &Pubkey,
|
2023-02-22 14:43:10 -08:00
|
|
|
data: impl Iterator<Item = &'b T>,
|
|
|
|
data_len: usize,
|
2022-07-08 11:51:16 -07:00
|
|
|
ref_count: RefCount,
|
2021-09-17 13:11:27 -07:00
|
|
|
) -> Result<(), BucketMapError> {
|
2023-02-22 14:43:10 -08:00
|
|
|
let best_fit_bucket = IndexEntry::data_bucket_from_num_slots(data_len as u64);
|
2021-09-29 18:53:26 -07:00
|
|
|
if self.data.get(best_fit_bucket as usize).is_none() {
|
|
|
|
// fail early if the data bucket we need doesn't exist - we don't want the index entry partially allocated
|
|
|
|
return Err(BucketMapError::DataNoSpace((best_fit_bucket, 0)));
|
|
|
|
}
|
2022-07-29 11:58:05 -07:00
|
|
|
let (found, elem, elem_ix) = self.find_entry_mut(key)?;
|
|
|
|
if !found {
|
|
|
|
let is_resizing = false;
|
|
|
|
let elem_uid = IndexEntry::key_uid(key);
|
|
|
|
self.index.allocate(elem_ix, elem_uid, is_resizing).unwrap();
|
|
|
|
// These fields will be overwritten after allocation by callers.
|
|
|
|
// Since this part of the mmapped file could have previously been used by someone else, there can be garbage here.
|
|
|
|
elem.init(key);
|
|
|
|
}
|
2021-12-01 10:17:32 -08:00
|
|
|
elem.ref_count = ref_count;
|
2021-12-21 12:51:38 -08:00
|
|
|
let elem_uid = self.index.uid_unchecked(elem_ix);
|
2021-09-17 13:11:27 -07:00
|
|
|
let bucket_ix = elem.data_bucket_ix();
|
|
|
|
let current_bucket = &self.data[bucket_ix as usize];
|
2023-02-22 14:43:10 -08:00
|
|
|
let num_slots = data_len as u64;
|
2021-09-17 13:11:27 -07:00
|
|
|
if best_fit_bucket == bucket_ix && elem.num_slots > 0 {
|
2021-12-01 10:17:32 -08:00
|
|
|
// in place update
|
2021-09-17 13:11:27 -07:00
|
|
|
let elem_loc = elem.data_loc(current_bucket);
|
2023-02-22 14:43:10 -08:00
|
|
|
let slice: &mut [T] = current_bucket.get_mut_cell_slice(elem_loc, data_len as u64);
|
2021-12-21 13:50:39 -08:00
|
|
|
assert_eq!(current_bucket.uid(elem_loc), Some(elem_uid));
|
|
|
|
elem.num_slots = num_slots;
|
2023-02-22 14:43:10 -08:00
|
|
|
|
|
|
|
slice.iter_mut().zip(data).for_each(|(dest, src)| {
|
|
|
|
*dest = *src;
|
|
|
|
});
|
2021-09-17 13:11:27 -07:00
|
|
|
Ok(())
|
|
|
|
} else {
|
2021-12-01 10:17:32 -08:00
|
|
|
// need to move the allocation to a best fit spot
|
2021-09-17 13:11:27 -07:00
|
|
|
let best_bucket = &self.data[best_fit_bucket as usize];
|
|
|
|
let cap_power = best_bucket.capacity_pow2;
|
2021-09-23 18:08:06 -07:00
|
|
|
let cap = best_bucket.capacity();
|
2021-09-17 13:11:27 -07:00
|
|
|
let pos = thread_rng().gen_range(0, cap);
|
|
|
|
for i in pos..pos + self.index.max_search() {
|
|
|
|
let ix = i % cap;
|
2021-12-22 13:12:34 -08:00
|
|
|
if best_bucket.is_free(ix) {
|
2021-09-17 13:11:27 -07:00
|
|
|
let elem_loc = elem.data_loc(current_bucket);
|
2021-12-21 13:50:39 -08:00
|
|
|
let old_slots = elem.num_slots;
|
2021-12-17 08:16:34 -08:00
|
|
|
elem.set_storage_offset(ix);
|
|
|
|
elem.set_storage_capacity_when_created_pow2(best_bucket.capacity_pow2);
|
2021-12-21 13:50:39 -08:00
|
|
|
elem.num_slots = num_slots;
|
|
|
|
if old_slots > 0 {
|
|
|
|
let current_bucket = &mut self.data[bucket_ix as usize];
|
|
|
|
current_bucket.free(elem_loc, elem_uid);
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
//debug!( "DATA ALLOC {:?} {} {} {}", key, elem.data_location, best_bucket.capacity, elem_uid );
|
2021-12-21 13:50:39 -08:00
|
|
|
if num_slots > 0 {
|
|
|
|
let best_bucket = &mut self.data[best_fit_bucket as usize];
|
2021-12-16 19:25:54 -08:00
|
|
|
best_bucket.allocate(ix, elem_uid, false).unwrap();
|
2021-12-21 13:50:39 -08:00
|
|
|
let slice = best_bucket.get_mut_cell_slice(ix, num_slots);
|
2023-02-22 14:43:10 -08:00
|
|
|
slice.iter_mut().zip(data).for_each(|(dest, src)| {
|
|
|
|
*dest = *src;
|
|
|
|
});
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(BucketMapError::DataNoSpace((best_fit_bucket, cap_power)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn delete_key(&mut self, key: &Pubkey) {
|
|
|
|
if let Some((elem, elem_ix)) = self.find_entry(key) {
|
2021-12-21 12:51:38 -08:00
|
|
|
let elem_uid = self.index.uid_unchecked(elem_ix);
|
2021-09-17 13:11:27 -07:00
|
|
|
if elem.num_slots > 0 {
|
2021-12-21 13:50:39 -08:00
|
|
|
let ix = elem.data_bucket_ix() as usize;
|
|
|
|
let data_bucket = &self.data[ix];
|
2021-09-17 13:11:27 -07:00
|
|
|
let loc = elem.data_loc(data_bucket);
|
2021-12-21 13:50:39 -08:00
|
|
|
let data_bucket = &mut self.data[ix];
|
2021-09-17 13:11:27 -07:00
|
|
|
//debug!( "DATA FREE {:?} {} {} {}", key, elem.data_location, data_bucket.capacity, elem_uid );
|
2021-09-20 19:59:41 -07:00
|
|
|
data_bucket.free(loc, elem_uid);
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
//debug!("INDEX FREE {:?} {}", key, elem_uid);
|
2021-09-20 19:59:41 -07:00
|
|
|
self.index.free(elem_ix, elem_uid);
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 12:59:08 -07:00
|
|
|
pub fn grow_index(&self, current_capacity_pow2: u8) {
|
|
|
|
if self.index.capacity_pow2 == current_capacity_pow2 {
|
2021-10-04 09:49:20 -07:00
|
|
|
let mut m = Measure::start("grow_index");
|
2021-10-05 12:59:08 -07:00
|
|
|
//debug!("GROW_INDEX: {}", current_capacity_pow2);
|
2021-09-17 13:11:27 -07:00
|
|
|
let increment = 1;
|
|
|
|
for i in increment.. {
|
|
|
|
//increasing the capacity by ^4 reduces the
|
2023-01-03 11:32:45 -08:00
|
|
|
//likelihood of a re-index collision of 2^(max_search)^2
|
2021-09-17 13:11:27 -07:00
|
|
|
//1 in 2^32
|
2021-12-21 13:50:39 -08:00
|
|
|
let mut index = BucketStorage::new_with_capacity(
|
2021-09-17 13:11:27 -07:00
|
|
|
Arc::clone(&self.drives),
|
|
|
|
1,
|
|
|
|
std::mem::size_of::<IndexEntry>() as u64,
|
2021-10-05 07:59:17 -07:00
|
|
|
// *2 causes rapid growth of index buckets
|
2021-09-17 13:11:27 -07:00
|
|
|
self.index.capacity_pow2 + i, // * 2,
|
|
|
|
self.index.max_search,
|
|
|
|
Arc::clone(&self.stats.index),
|
2021-12-16 19:25:54 -08:00
|
|
|
Arc::clone(&self.index.count),
|
2021-09-17 13:11:27 -07:00
|
|
|
);
|
|
|
|
let random = thread_rng().gen();
|
|
|
|
let mut valid = true;
|
2021-09-23 18:08:06 -07:00
|
|
|
for ix in 0..self.index.capacity() {
|
2021-09-17 13:11:27 -07:00
|
|
|
let uid = self.index.uid(ix);
|
2021-12-21 12:51:38 -08:00
|
|
|
if let Some(uid) = uid {
|
2021-09-17 13:11:27 -07:00
|
|
|
let elem: &IndexEntry = self.index.get(ix);
|
2021-12-21 13:50:39 -08:00
|
|
|
let new_ix =
|
|
|
|
Self::bucket_create_key(&mut index, &elem.key, uid, random, true);
|
2021-09-17 13:11:27 -07:00
|
|
|
if new_ix.is_err() {
|
|
|
|
valid = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
let new_ix = new_ix.unwrap();
|
|
|
|
let new_elem: &mut IndexEntry = index.get_mut(new_ix);
|
|
|
|
*new_elem = *elem;
|
|
|
|
/*
|
|
|
|
let dbg_elem: IndexEntry = *new_elem;
|
|
|
|
assert_eq!(
|
|
|
|
Self::bucket_find_entry(&index, &elem.key, random).unwrap(),
|
|
|
|
(&dbg_elem, new_ix)
|
|
|
|
);
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if valid {
|
2023-01-07 07:25:04 -08:00
|
|
|
self.stats.index.update_max_size(index.capacity());
|
2021-10-05 07:59:17 -07:00
|
|
|
let mut items = self.reallocated.items.lock().unwrap();
|
|
|
|
items.index = Some((random, index));
|
|
|
|
self.reallocated.add_reallocation();
|
2021-09-17 13:11:27 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m.stop();
|
|
|
|
self.stats.index.resizes.fetch_add(1, Ordering::Relaxed);
|
|
|
|
self.stats
|
|
|
|
.index
|
|
|
|
.resize_us
|
|
|
|
.fetch_add(m.as_us(), Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 07:59:17 -07:00
|
|
|
pub fn apply_grow_index(&mut self, random: u64, index: BucketStorage) {
|
|
|
|
self.random = random;
|
|
|
|
self.index = index;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn elem_size() -> u64 {
|
|
|
|
std::mem::size_of::<T>() as u64
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn apply_grow_data(&mut self, ix: usize, bucket: BucketStorage) {
|
|
|
|
if self.data.get(ix).is_none() {
|
|
|
|
for i in self.data.len()..ix {
|
|
|
|
// insert empty data buckets
|
2021-09-17 13:11:27 -07:00
|
|
|
self.data.push(BucketStorage::new(
|
|
|
|
Arc::clone(&self.drives),
|
|
|
|
1 << i,
|
2021-10-05 07:59:17 -07:00
|
|
|
Self::elem_size(),
|
2021-09-17 13:11:27 -07:00
|
|
|
self.index.max_search,
|
|
|
|
Arc::clone(&self.stats.data),
|
2021-12-16 19:25:54 -08:00
|
|
|
Arc::default(),
|
2021-09-17 13:11:27 -07:00
|
|
|
))
|
|
|
|
}
|
2021-10-05 07:59:17 -07:00
|
|
|
self.data.push(bucket);
|
|
|
|
} else {
|
|
|
|
self.data[ix] = bucket;
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
2021-10-05 07:59:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// grow a data bucket
|
|
|
|
/// The application of the new bucket is deferred until the next write lock.
|
2021-10-05 12:59:08 -07:00
|
|
|
pub fn grow_data(&self, data_index: u64, current_capacity_pow2: u8) {
|
2021-10-05 15:26:29 -07:00
|
|
|
let new_bucket = BucketStorage::new_resized(
|
|
|
|
&self.drives,
|
|
|
|
self.index.max_search,
|
2021-10-05 07:59:17 -07:00
|
|
|
self.data.get(data_index as usize),
|
2021-10-05 17:16:02 -07:00
|
|
|
std::cmp::max(current_capacity_pow2 + 1, DEFAULT_CAPACITY_POW2),
|
2021-10-05 07:59:17 -07:00
|
|
|
1 << data_index,
|
|
|
|
Self::elem_size(),
|
2021-10-05 15:26:29 -07:00
|
|
|
&self.stats.data,
|
2021-10-05 07:59:17 -07:00
|
|
|
);
|
|
|
|
self.reallocated.add_reallocation();
|
|
|
|
let mut items = self.reallocated.items.lock().unwrap();
|
|
|
|
items.data = Some((data_index, new_bucket));
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn bucket_index_ix(index: &BucketStorage, key: &Pubkey, random: u64) -> u64 {
|
|
|
|
let uid = IndexEntry::key_uid(key);
|
|
|
|
let mut s = DefaultHasher::new();
|
|
|
|
uid.hash(&mut s);
|
|
|
|
//the locally generated random will make it hard for an attacker
|
|
|
|
//to deterministically cause all the pubkeys to land in the same
|
|
|
|
//location in any bucket on all validators
|
|
|
|
random.hash(&mut s);
|
|
|
|
let ix = s.finish();
|
2021-09-23 18:08:06 -07:00
|
|
|
ix % index.capacity()
|
|
|
|
//debug!( "INDEX_IX: {:?} uid:{} loc: {} cap:{}", key, uid, location, index.capacity() );
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
|
2021-10-05 07:59:17 -07:00
|
|
|
/// grow the appropriate piece. Note this takes an immutable ref.
|
|
|
|
/// The actual grow is set into self.reallocated and applied later on a write lock
|
|
|
|
pub fn grow(&self, err: BucketMapError) {
|
2021-09-29 18:53:26 -07:00
|
|
|
match err {
|
2021-10-05 12:59:08 -07:00
|
|
|
BucketMapError::DataNoSpace((data_index, current_capacity_pow2)) => {
|
|
|
|
//debug!("GROWING SPACE {:?}", (data_index, current_capacity_pow2));
|
|
|
|
self.grow_data(data_index, current_capacity_pow2);
|
2021-09-29 18:53:26 -07:00
|
|
|
}
|
2021-10-05 12:59:08 -07:00
|
|
|
BucketMapError::IndexNoSpace(current_capacity_pow2) => {
|
2021-09-29 18:53:26 -07:00
|
|
|
//debug!("GROWING INDEX {}", sz);
|
2021-10-05 12:59:08 -07:00
|
|
|
self.grow_index(current_capacity_pow2);
|
2021-10-05 07:59:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// if a bucket was resized previously with a read lock, then apply that resize now
|
|
|
|
pub fn handle_delayed_grows(&mut self) {
|
|
|
|
if self.reallocated.get_reallocated() {
|
|
|
|
// swap out the bucket that was resized previously with a read lock
|
2022-07-11 04:33:15 -07:00
|
|
|
let mut items = std::mem::take(&mut *self.reallocated.items.lock().unwrap());
|
2021-10-05 07:59:17 -07:00
|
|
|
|
|
|
|
if let Some((random, bucket)) = items.index.take() {
|
|
|
|
self.apply_grow_index(random, bucket);
|
|
|
|
} else {
|
|
|
|
// data bucket
|
|
|
|
let (i, new_bucket) = items.data.take().unwrap();
|
|
|
|
self.apply_grow_data(i as usize, new_bucket);
|
2021-09-29 18:53:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-20 08:36:48 -07:00
|
|
|
pub fn insert(&mut self, key: &Pubkey, value: (&[T], RefCount)) {
|
|
|
|
let (new, refct) = value;
|
2021-09-17 13:11:27 -07:00
|
|
|
loop {
|
2023-02-22 14:43:10 -08:00
|
|
|
let rv = self.try_write(key, new.iter(), new.len(), refct);
|
2021-09-17 13:11:27 -07:00
|
|
|
match rv {
|
2021-09-29 18:53:26 -07:00
|
|
|
Ok(_) => return,
|
2021-10-05 07:59:17 -07:00
|
|
|
Err(err) => {
|
|
|
|
self.grow(err);
|
|
|
|
self.handle_delayed_grows();
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-20 08:36:48 -07:00
|
|
|
|
2021-11-19 15:17:07 -08:00
|
|
|
pub fn update<F>(&mut self, key: &Pubkey, mut updatefn: F)
|
2021-09-20 08:36:48 -07:00
|
|
|
where
|
2021-11-19 15:17:07 -08:00
|
|
|
F: FnMut(Option<(&[T], RefCount)>) -> Option<(Vec<T>, RefCount)>,
|
2021-09-20 08:36:48 -07:00
|
|
|
{
|
|
|
|
let current = self.read_value(key);
|
|
|
|
let new = updatefn(current);
|
|
|
|
if new.is_none() {
|
|
|
|
self.delete_key(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let (new, refct) = new.unwrap();
|
|
|
|
self.insert(key, (&new, refct));
|
|
|
|
}
|
2021-09-17 13:11:27 -07:00
|
|
|
}
|