acct idx flush keeps slot_list read lock open (#23704)
This commit is contained in:
committed by
GitHub
parent
18bddbc730
commit
caddb851be
@ -892,20 +892,20 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return true if 'entry' should be evicted from the in-mem index
|
/// return true if 'entry' should be evicted from the in-mem index
|
||||||
fn should_evict_from_mem(
|
fn should_evict_from_mem<'a>(
|
||||||
&self,
|
&self,
|
||||||
current_age: Age,
|
current_age: Age,
|
||||||
entry: &AccountMapEntry<T>,
|
entry: &'a AccountMapEntry<T>,
|
||||||
startup: bool,
|
startup: bool,
|
||||||
update_stats: bool,
|
update_stats: bool,
|
||||||
exceeds_budget: bool,
|
exceeds_budget: bool,
|
||||||
) -> bool {
|
) -> (bool, Option<std::sync::RwLockReadGuard<'a, SlotList<T>>>) {
|
||||||
// this could be tunable dynamically based on memory pressure
|
// this could be tunable dynamically based on memory pressure
|
||||||
// we could look at more ages or we could throw out more items we are choosing to keep in the cache
|
// we could look at more ages or we could throw out more items we are choosing to keep in the cache
|
||||||
if startup || (current_age == entry.age()) {
|
if startup || (current_age == entry.age()) {
|
||||||
if exceeds_budget {
|
if exceeds_budget {
|
||||||
// if we are already holding too many items in-mem, then we need to be more aggressive at kicking things out
|
// if we are already holding too many items in-mem, then we need to be more aggressive at kicking things out
|
||||||
true
|
(true, None)
|
||||||
} else {
|
} else {
|
||||||
// only read the slot list if we are planning to throw the item out
|
// only read the slot list if we are planning to throw the item out
|
||||||
let slot_list = entry.slot_list.read().unwrap();
|
let slot_list = entry.slot_list.read().unwrap();
|
||||||
@ -913,18 +913,18 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
if update_stats {
|
if update_stats {
|
||||||
Self::update_stat(&self.stats().held_in_mem_slot_list_len, 1);
|
Self::update_stat(&self.stats().held_in_mem_slot_list_len, 1);
|
||||||
}
|
}
|
||||||
false // keep 0 and > 1 slot lists in mem. They will be cleaned or shrunk soon.
|
(false, None) // keep 0 and > 1 slot lists in mem. They will be cleaned or shrunk soon.
|
||||||
} else {
|
} else {
|
||||||
// keep items with slot lists that contained cached items
|
// keep items with slot lists that contained cached items
|
||||||
let evict = !slot_list.iter().any(|(_, info)| info.is_cached());
|
let evict = !slot_list.iter().any(|(_, info)| info.is_cached());
|
||||||
if !evict && update_stats {
|
if !evict && update_stats {
|
||||||
Self::update_stat(&self.stats().held_in_mem_slot_list_cached, 1);
|
Self::update_stat(&self.stats().held_in_mem_slot_list_cached, 1);
|
||||||
}
|
}
|
||||||
evict
|
(evict, if evict { Some(slot_list) } else { None })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
(false, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -960,11 +960,9 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
evictions = Vec::with_capacity(map.len());
|
evictions = Vec::with_capacity(map.len());
|
||||||
let m = Measure::start("flush_scan_and_update"); // we don't care about lock time in this metric - bg threads can wait
|
let m = Measure::start("flush_scan_and_update"); // we don't care about lock time in this metric - bg threads can wait
|
||||||
for (k, v) in map.iter() {
|
for (k, v) in map.iter() {
|
||||||
if self.should_evict_from_mem(current_age, v, startup, true, exceeds_budget) {
|
let (evict_for_age, slot_list) =
|
||||||
evictions.push(*k);
|
self.should_evict_from_mem(current_age, v, startup, true, exceeds_budget);
|
||||||
} else if Self::random_chance_of_eviction() {
|
if !evict_for_age && !Self::random_chance_of_eviction() {
|
||||||
evictions_random.push(*k);
|
|
||||||
} else {
|
|
||||||
// not planning to remove this item from memory now, so don't write it to disk yet
|
// not planning to remove this item from memory now, so don't write it to disk yet
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -978,8 +976,11 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
// That prevents dropping an item from cache before disk is updated to latest in mem.
|
// That prevents dropping an item from cache before disk is updated to latest in mem.
|
||||||
// happens inside of lock on in-mem cache. This is because of deleting items
|
// happens inside of lock on in-mem cache. This is because of deleting items
|
||||||
// it is possible that the item in the cache is marked as dirty while these updates are happening. That is ok.
|
// it is possible that the item in the cache is marked as dirty while these updates are happening. That is ok.
|
||||||
disk_resize =
|
{
|
||||||
disk.try_write(k, (&v.slot_list.read().unwrap(), v.ref_count()));
|
let slot_list =
|
||||||
|
slot_list.unwrap_or_else(|| v.slot_list.read().unwrap());
|
||||||
|
disk_resize = disk.try_write(k, (&slot_list, v.ref_count()));
|
||||||
|
}
|
||||||
if disk_resize.is_ok() {
|
if disk_resize.is_ok() {
|
||||||
flush_entries_updated_on_disk += 1;
|
flush_entries_updated_on_disk += 1;
|
||||||
} else {
|
} else {
|
||||||
@ -987,6 +988,13 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
v.set_dirty(true);
|
v.set_dirty(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
drop(slot_list);
|
||||||
|
}
|
||||||
|
if evict_for_age {
|
||||||
|
evictions.push(*k);
|
||||||
|
} else {
|
||||||
|
evictions_random.push(*k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::update_time_stat(&self.stats().flush_scan_update_us, m);
|
Self::update_time_stat(&self.stats().flush_scan_update_us, m);
|
||||||
@ -1068,13 +1076,9 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
|||||||
|
|
||||||
if v.dirty()
|
if v.dirty()
|
||||||
|| (!randomly_evicted
|
|| (!randomly_evicted
|
||||||
&& !self.should_evict_from_mem(
|
&& !self
|
||||||
current_age,
|
.should_evict_from_mem(current_age, v, startup, false, exceeds_budget)
|
||||||
v,
|
.0)
|
||||||
startup,
|
|
||||||
false,
|
|
||||||
exceeds_budget,
|
|
||||||
))
|
|
||||||
{
|
{
|
||||||
// marked dirty or bumped in age after we looked above
|
// marked dirty or bumped in age after we looked above
|
||||||
// these will be handled in later passes
|
// these will be handled in later passes
|
||||||
@ -1200,7 +1204,9 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// exceeded budget
|
// exceeded budget
|
||||||
assert!(bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&Arc::new(AccountMapEntryInner::new(
|
&Arc::new(AccountMapEntryInner::new(
|
||||||
vec![],
|
vec![],
|
||||||
@ -1210,9 +1216,13 @@ mod tests {
|
|||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
// empty slot list
|
// empty slot list
|
||||||
assert!(!bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
!bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&Arc::new(AccountMapEntryInner::new(
|
&Arc::new(AccountMapEntryInner::new(
|
||||||
vec![],
|
vec![],
|
||||||
@ -1222,17 +1232,25 @@ mod tests {
|
|||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
// 1 element slot list
|
// 1 element slot list
|
||||||
assert!(bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
// 2 element slot list
|
// 2 element slot list
|
||||||
assert!(!bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
!bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&Arc::new(AccountMapEntryInner::new(
|
&Arc::new(AccountMapEntryInner::new(
|
||||||
vec![(0, 0), (1, 1)],
|
vec![(0, 0), (1, 1)],
|
||||||
@ -1242,12 +1260,16 @@ mod tests {
|
|||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
let bucket = new_for_test::<f64>();
|
let bucket = new_for_test::<f64>();
|
||||||
// 1 element slot list with a CACHED item - f64 acts like cached
|
// 1 element slot list with a CACHED item - f64 acts like cached
|
||||||
assert!(!bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
!bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&Arc::new(AccountMapEntryInner::new(
|
&Arc::new(AccountMapEntryInner::new(
|
||||||
vec![(0, 0.0)],
|
vec![(0, 0.0)],
|
||||||
@ -1257,37 +1279,51 @@ mod tests {
|
|||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 element slot list, age is now
|
// 1 element slot list, age is now
|
||||||
assert!(bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
|
|
||||||
// 1 element slot list, but not current age
|
// 1 element slot list, but not current age
|
||||||
current_age = 1;
|
current_age = 1;
|
||||||
assert!(!bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
!bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
|
|
||||||
// 1 element slot list, but at startup and age not current
|
// 1 element slot list, but at startup and age not current
|
||||||
startup = true;
|
startup = true;
|
||||||
assert!(bucket.should_evict_from_mem(
|
assert!(
|
||||||
|
bucket
|
||||||
|
.should_evict_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
));
|
)
|
||||||
|
.0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Reference in New Issue
Block a user