AcctIdx: hold range recognizes already held ranges (#21937)
This commit is contained in:
parent
056f2e9e67
commit
8ed7ad5fa7
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue