AcctIdx: respect disk idx mem size param (#22050)
This commit is contained in:
parent
4d62f03297
commit
61cc7b10a9
|
@ -806,6 +806,13 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
thread_rng().gen_range(0, N) == 0
|
thread_rng().gen_range(0, N) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// assumes 1 entry in the slot list. Ignores overhead of the HashMap and such
|
||||||
|
fn approx_size_of_one_entry() -> usize {
|
||||||
|
std::mem::size_of::<T>()
|
||||||
|
+ std::mem::size_of::<Pubkey>()
|
||||||
|
+ std::mem::size_of::<AccountMapEntry<T>>()
|
||||||
|
}
|
||||||
|
|
||||||
/// return true if 'entry' should be removed from the in-mem index
|
/// return true if 'entry' should be removed from the in-mem index
|
||||||
fn should_remove_from_mem(
|
fn should_remove_from_mem(
|
||||||
&self,
|
&self,
|
||||||
|
@ -813,24 +820,30 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
entry: &AccountMapEntry<T>,
|
entry: &AccountMapEntry<T>,
|
||||||
startup: bool,
|
startup: bool,
|
||||||
update_stats: bool,
|
update_stats: bool,
|
||||||
|
exceeds_budget: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// 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()) {
|
||||||
// only read the slot list if we are planning to throw the item out
|
if exceeds_budget {
|
||||||
let slot_list = entry.slot_list.read().unwrap();
|
// if we are already holding too many items in-mem, then we need to be more aggressive at kicking things out
|
||||||
if slot_list.len() != 1 {
|
true
|
||||||
if update_stats {
|
|
||||||
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.
|
|
||||||
} else {
|
} else {
|
||||||
// keep items with slot lists that contained cached items
|
// only read the slot list if we are planning to throw the item out
|
||||||
let remove = !slot_list.iter().any(|(_, info)| info.is_cached());
|
let slot_list = entry.slot_list.read().unwrap();
|
||||||
if !remove && update_stats {
|
if slot_list.len() != 1 {
|
||||||
Self::update_stat(&self.stats().held_in_mem_slot_list_cached, 1);
|
if update_stats {
|
||||||
|
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.
|
||||||
|
} else {
|
||||||
|
// keep items with slot lists that contained cached items
|
||||||
|
let remove = !slot_list.iter().any(|(_, info)| info.is_cached());
|
||||||
|
if !remove && update_stats {
|
||||||
|
Self::update_stat(&self.stats().held_in_mem_slot_list_cached, 1);
|
||||||
|
}
|
||||||
|
remove
|
||||||
}
|
}
|
||||||
remove
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -848,6 +861,12 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let in_mem_count = self.stats().count_in_mem.load(Ordering::Relaxed);
|
||||||
|
let limit = self.storage.mem_budget_mb;
|
||||||
|
let exceeds_budget = limit
|
||||||
|
.map(|limit| in_mem_count * Self::approx_size_of_one_entry() >= limit * 1024 * 1024)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
// may have to loop if disk has to grow and we have to restart
|
// may have to loop if disk has to grow and we have to restart
|
||||||
loop {
|
loop {
|
||||||
let mut removes;
|
let mut removes;
|
||||||
|
@ -863,7 +882,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
removes = Vec::with_capacity(map.len());
|
removes = 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_remove_from_mem(current_age, v, startup, true) {
|
if self.should_remove_from_mem(current_age, v, startup, true, exceeds_budget) {
|
||||||
removes.push(*k);
|
removes.push(*k);
|
||||||
} else if Self::random_chance_of_eviction() {
|
} else if Self::random_chance_of_eviction() {
|
||||||
removes_random.push(*k);
|
removes_random.push(*k);
|
||||||
|
@ -902,9 +921,19 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
let m = Measure::start("flush_remove_or_grow");
|
let m = Measure::start("flush_remove_or_grow");
|
||||||
match disk_resize {
|
match disk_resize {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if !self.flush_remove_from_cache(removes, current_age, startup, false)
|
if !self.flush_remove_from_cache(
|
||||||
|| !self.flush_remove_from_cache(removes_random, current_age, startup, true)
|
removes,
|
||||||
{
|
current_age,
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
exceeds_budget,
|
||||||
|
) || !self.flush_remove_from_cache(
|
||||||
|
removes_random,
|
||||||
|
current_age,
|
||||||
|
startup,
|
||||||
|
true,
|
||||||
|
exceeds_budget,
|
||||||
|
) {
|
||||||
iterate_for_age = false; // did not make it all the way through this bucket, so didn't handle age completely
|
iterate_for_age = false; // did not make it all the way through this bucket, so didn't handle age completely
|
||||||
}
|
}
|
||||||
Self::update_time_stat(&self.stats().flush_remove_us, m);
|
Self::update_time_stat(&self.stats().flush_remove_us, m);
|
||||||
|
@ -934,6 +963,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
current_age: Age,
|
current_age: Age,
|
||||||
startup: bool,
|
startup: bool,
|
||||||
randomly_evicted: bool,
|
randomly_evicted: bool,
|
||||||
|
exceeds_budget: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut completed_scan = true;
|
let mut completed_scan = true;
|
||||||
if removes.is_empty() {
|
if removes.is_empty() {
|
||||||
|
@ -956,7 +986,13 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
|
|
||||||
if v.dirty()
|
if v.dirty()
|
||||||
|| (!randomly_evicted
|
|| (!randomly_evicted
|
||||||
&& !self.should_remove_from_mem(current_age, v, startup, false))
|
&& !self.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
v,
|
||||||
|
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
|
||||||
|
@ -1053,6 +1089,18 @@ mod tests {
|
||||||
AccountMapEntryMeta::default(),
|
AccountMapEntryMeta::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// exceeded budget
|
||||||
|
assert!(bucket.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
&Arc::new(AccountMapEntryInner::new(
|
||||||
|
vec![],
|
||||||
|
ref_count,
|
||||||
|
AccountMapEntryMeta::default()
|
||||||
|
)),
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
));
|
||||||
// empty slot list
|
// empty slot list
|
||||||
assert!(!bucket.should_remove_from_mem(
|
assert!(!bucket.should_remove_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
|
@ -1063,6 +1111,7 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
// 1 element slot list
|
// 1 element slot list
|
||||||
assert!(bucket.should_remove_from_mem(
|
assert!(bucket.should_remove_from_mem(
|
||||||
|
@ -1070,6 +1119,7 @@ mod tests {
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
// 2 element slot list
|
// 2 element slot list
|
||||||
assert!(!bucket.should_remove_from_mem(
|
assert!(!bucket.should_remove_from_mem(
|
||||||
|
@ -1081,6 +1131,7 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1095,6 +1146,7 @@ mod tests {
|
||||||
)),
|
)),
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,6 +1156,7 @@ mod tests {
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
// 1 element slot list, but not current age
|
// 1 element slot list, but not current age
|
||||||
|
@ -1113,6 +1166,7 @@ mod tests {
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
// 1 element slot list, but at startup and age not current
|
// 1 element slot list, but at startup and age not current
|
||||||
|
@ -1122,6 +1176,7 @@ mod tests {
|
||||||
&one_element_slot_list_entry,
|
&one_element_slot_list_entry,
|
||||||
startup,
|
startup,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue