AcctIdx: hold range recognizes already held ranges (#21937)

This commit is contained in:
Jeff Washington (jwash) 2021-12-17 10:04:41 -06:00 committed by GitHub
parent 056f2e9e67
commit 8ed7ad5fa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 89 additions and 14 deletions

View File

@ -633,10 +633,45 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
} }
} }
pub fn just_set_hold_range_in_memory<R>(&self, range: &R, start_holding: bool) /// Look at the currently held ranges. If 'range' is already included in what is
/// being held, then add 'range' to the currently held list AND return true
/// If 'range' is NOT already included in what is being held, then return false
/// withOUT adding 'range' to the list of what is currently held
fn add_hold_range_in_memory_if_already_held<R>(&self, range: &R) -> bool
where where
R: RangeBounds<Pubkey>, R: RangeBounds<Pubkey>,
{ {
let start_holding = true;
let only_add_if_already_held = true;
self.just_set_hold_range_in_memory_internal(range, start_holding, only_add_if_already_held)
}
fn just_set_hold_range_in_memory<R>(&self, range: &R, start_holding: bool)
where
R: RangeBounds<Pubkey>,
{
let only_add_if_already_held = false;
let _ = self.just_set_hold_range_in_memory_internal(
range,
start_holding,
only_add_if_already_held,
);
}
/// if 'start_holding', then caller wants to add 'range' to the list of ranges being held
/// if !'start_holding', then caller wants to remove 'range' to the list
/// if 'only_add_if_already_held', caller intends to only add 'range' to the list if the range is already held
/// returns true iff start_holding=true and the range we're asked to hold was already being held
fn just_set_hold_range_in_memory_internal<R>(
&self,
range: &R,
start_holding: bool,
only_add_if_already_held: bool,
) -> bool
where
R: RangeBounds<Pubkey>,
{
assert!(!(only_add_if_already_held && !start_holding));
let start = match range.start_bound() { let start = match range.start_bound() {
Bound::Included(bound) | Bound::Excluded(bound) => *bound, Bound::Included(bound) | Bound::Excluded(bound) => *bound,
Bound::Unbounded => Pubkey::new(&[0; 32]), Bound::Unbounded => Pubkey::new(&[0; 32]),
@ -651,8 +686,19 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
// inclusive is bigger than exclusive so we may hold 1 extra item worst case // inclusive is bigger than exclusive so we may hold 1 extra item worst case
let inclusive_range = start..=end; let inclusive_range = start..=end;
let mut ranges = self.cache_ranges_held.write().unwrap(); let mut ranges = self.cache_ranges_held.write().unwrap();
let mut already_held = false;
if start_holding { if start_holding {
if only_add_if_already_held {
for r in ranges.iter() {
if r.contains(&start) && r.contains(&end) {
already_held = true;
break;
}
}
}
if already_held || !only_add_if_already_held {
ranges.push(inclusive_range); ranges.push(inclusive_range);
}
} else { } else {
// find the matching range and delete it since we don't want to hold it anymore // find the matching range and delete it since we don't want to hold it anymore
// search backwards, assuming LIFO ordering // search backwards, assuming LIFO ordering
@ -660,16 +706,16 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
if let (Bound::Included(start_found), Bound::Included(end_found)) = if let (Bound::Included(start_found), Bound::Included(end_found)) =
(r.start_bound(), r.end_bound()) (r.start_bound(), r.end_bound())
{ {
if start_found != &start || end_found != &end { if start_found == &start && end_found == &end {
continue;
}
}
// found a match. There may be dups, that's ok, we expect another call to remove the dup. // found a match. There may be dups, that's ok, we expect another call to remove the dup.
ranges.remove(i); ranges.remove(i);
break; break;
} }
} }
} }
}
already_held
}
fn start_stop_flush(&self, stop: bool) { fn start_stop_flush(&self, stop: bool) {
if stop { if stop {
@ -686,12 +732,14 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
{ {
self.start_stop_flush(true); self.start_stop_flush(true);
if !start_holding || !self.add_hold_range_in_memory_if_already_held(range) {
if start_holding { if start_holding {
// put everything in the cache and it will be held there // put everything in the cache and it will be held there
self.put_range_in_cache(&Some(range)); self.put_range_in_cache(&Some(range));
} }
// do this AFTER items have been put in cache - that way anyone who finds this range can know that the items are already in the cache // do this AFTER items have been put in cache - that way anyone who finds this range can know that the items are already in the cache
self.just_set_hold_range_in_memory(range, start_holding); self.just_set_hold_range_in_memory(range, start_holding);
}
self.start_stop_flush(false); self.start_stop_flush(false);
} }
@ -976,6 +1024,21 @@ mod tests {
InMemAccountsIndex::new(&holder, bin) InMemAccountsIndex::new(&holder, bin)
} }
fn new_disk_buckets_for_test<T: IndexValue>() -> InMemAccountsIndex<T> {
let holder = Arc::new(BucketMapHolder::new(
BINS_FOR_TESTING,
&Some(AccountsIndexConfig {
index_limit_mb: Some(1),
..AccountsIndexConfig::default()
}),
1,
));
let bin = 0;
let bucket = InMemAccountsIndex::new(&holder, bin);
assert!(bucket.storage.is_disk_index_enabled());
bucket
}
#[test] #[test]
fn test_should_remove_from_mem() { fn test_should_remove_from_mem() {
solana_logger::setup(); solana_logger::setup();
@ -1064,10 +1127,11 @@ mod tests {
#[test] #[test]
fn test_hold_range_in_memory() { fn test_hold_range_in_memory() {
let bucket = new_for_test::<u64>(); let bucket = new_disk_buckets_for_test::<u64>();
// 0x81 is just some other range // 0x81 is just some other range
let all = Pubkey::new(&[0; 32])..=Pubkey::new(&[0xff; 32]);
let ranges = [ let ranges = [
Pubkey::new(&[0; 32])..=Pubkey::new(&[0xff; 32]), all.clone(),
Pubkey::new(&[0x81; 32])..=Pubkey::new(&[0xff; 32]), Pubkey::new(&[0x81; 32])..=Pubkey::new(&[0xff; 32]),
]; ];
for range in ranges.clone() { for range in ranges.clone() {
@ -1077,6 +1141,10 @@ mod tests {
bucket.cache_ranges_held.read().unwrap().to_vec(), bucket.cache_ranges_held.read().unwrap().to_vec(),
vec![range.clone()] vec![range.clone()]
); );
{
assert!(bucket.add_hold_range_in_memory_if_already_held(&range));
bucket.hold_range_in_memory(&range, false);
}
bucket.hold_range_in_memory(&range, false); bucket.hold_range_in_memory(&range, false);
assert!(bucket.cache_ranges_held.read().unwrap().is_empty()); assert!(bucket.cache_ranges_held.read().unwrap().is_empty());
bucket.hold_range_in_memory(&range, true); bucket.hold_range_in_memory(&range, true);
@ -1106,6 +1174,13 @@ mod tests {
); );
bucket.hold_range_in_memory(&ranges[0].clone(), false); bucket.hold_range_in_memory(&ranges[0].clone(), false);
assert!(bucket.cache_ranges_held.read().unwrap().is_empty()); assert!(bucket.cache_ranges_held.read().unwrap().is_empty());
// hold all in mem first
assert!(bucket.cache_ranges_held.read().unwrap().is_empty());
bucket.hold_range_in_memory(&all, true);
assert!(bucket.add_hold_range_in_memory_if_already_held(&range));
bucket.hold_range_in_memory(&range, false);
bucket.hold_range_in_memory(&all, false);
} }
} }