AcctIdx: write disk only when removing from mem (#20578)
This commit is contained in:
parent
1417c1456d
commit
0da677e213
|
@ -9,6 +9,8 @@ const STATS_INTERVAL_MS: u64 = 10_000;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct BucketMapHolderStats {
|
pub struct BucketMapHolderStats {
|
||||||
|
pub held_in_mem_slot_list_len: AtomicU64,
|
||||||
|
pub held_in_mem_slot_list_cached: AtomicU64,
|
||||||
pub get_mem_us: AtomicU64,
|
pub get_mem_us: AtomicU64,
|
||||||
pub gets_from_mem: AtomicU64,
|
pub gets_from_mem: AtomicU64,
|
||||||
pub get_missing_us: AtomicU64,
|
pub get_missing_us: AtomicU64,
|
||||||
|
@ -161,6 +163,16 @@ impl BucketMapHolderStats {
|
||||||
self.bg_throttling_wait_us.swap(0, Ordering::Relaxed),
|
self.bg_throttling_wait_us.swap(0, Ordering::Relaxed),
|
||||||
i64
|
i64
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"held_in_mem_slot_list_len",
|
||||||
|
self.held_in_mem_slot_list_len.swap(0, Ordering::Relaxed),
|
||||||
|
i64
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"held_in_mem_slot_list_cached",
|
||||||
|
self.held_in_mem_slot_list_cached.swap(0, Ordering::Relaxed),
|
||||||
|
i64
|
||||||
|
),
|
||||||
("min_in_bin_mem", in_mem_stats.0, i64),
|
("min_in_bin_mem", in_mem_stats.0, i64),
|
||||||
("max_in_bin_mem", in_mem_stats.1, i64),
|
("max_in_bin_mem", in_mem_stats.1, i64),
|
||||||
("count_from_bins_mem", in_mem_stats.2, i64),
|
("count_from_bins_mem", in_mem_stats.2, i64),
|
||||||
|
|
|
@ -645,6 +645,7 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
current_age: Age,
|
current_age: Age,
|
||||||
entry: &AccountMapEntry<T>,
|
entry: &AccountMapEntry<T>,
|
||||||
startup: bool,
|
startup: bool,
|
||||||
|
update_stats: 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
|
||||||
|
@ -652,10 +653,17 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
// 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();
|
||||||
if slot_list.len() != 1 {
|
if slot_list.len() != 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.
|
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
|
// keep items with slot lists that contained cached items
|
||||||
!slot_list.iter().any(|(_, info)| info.is_cached())
|
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
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -688,6 +696,16 @@ 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) {
|
||||||
|
removes.push(*k);
|
||||||
|
} else if Self::random_chance_of_eviction() {
|
||||||
|
removes_random.push(*k);
|
||||||
|
} else {
|
||||||
|
// not planning to remove this item from memory now, so don't write it to disk yet
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are removing it, then we need to update disk if we're dirty
|
||||||
if v.clear_dirty() {
|
if v.clear_dirty() {
|
||||||
// step 1: clear the dirty flag
|
// step 1: clear the dirty flag
|
||||||
// step 2: perform the update on disk based on the fields in the entry
|
// step 2: perform the update on disk based on the fields in the entry
|
||||||
|
@ -706,12 +724,6 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.should_remove_from_mem(current_age, v, startup) {
|
|
||||||
removes.push(*k);
|
|
||||||
} else if Self::random_chance_of_eviction() {
|
|
||||||
removes_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);
|
||||||
}
|
}
|
||||||
|
@ -778,7 +790,8 @@ impl<T: IndexValue> InMemAccountsIndex<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.dirty()
|
if v.dirty()
|
||||||
|| (!randomly_evicted && !self.should_remove_from_mem(current_age, v, startup))
|
|| (!randomly_evicted
|
||||||
|
&& !self.should_remove_from_mem(current_age, v, startup, false))
|
||||||
{
|
{
|
||||||
// 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
|
||||||
|
@ -863,10 +876,16 @@ mod tests {
|
||||||
ref_count,
|
ref_count,
|
||||||
AccountMapEntryMeta::default()
|
AccountMapEntryMeta::default()
|
||||||
)),
|
)),
|
||||||
startup
|
startup,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
// 1 element slot list
|
// 1 element slot list
|
||||||
assert!(bucket.should_remove_from_mem(current_age, &one_element_slot_list_entry, startup));
|
assert!(bucket.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
&one_element_slot_list_entry,
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
));
|
||||||
// 2 element slot list
|
// 2 element slot list
|
||||||
assert!(!bucket.should_remove_from_mem(
|
assert!(!bucket.should_remove_from_mem(
|
||||||
current_age,
|
current_age,
|
||||||
|
@ -875,7 +894,8 @@ mod tests {
|
||||||
ref_count,
|
ref_count,
|
||||||
AccountMapEntryMeta::default()
|
AccountMapEntryMeta::default()
|
||||||
)),
|
)),
|
||||||
startup
|
startup,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -888,20 +908,36 @@ mod tests {
|
||||||
ref_count,
|
ref_count,
|
||||||
AccountMapEntryMeta::default()
|
AccountMapEntryMeta::default()
|
||||||
)),
|
)),
|
||||||
startup
|
startup,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 element slot list, age is now
|
// 1 element slot list, age is now
|
||||||
assert!(bucket.should_remove_from_mem(current_age, &one_element_slot_list_entry, startup));
|
assert!(bucket.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
&one_element_slot_list_entry,
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
// 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_remove_from_mem(current_age, &one_element_slot_list_entry, startup));
|
assert!(!bucket.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
&one_element_slot_list_entry,
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
// 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_remove_from_mem(current_age, &one_element_slot_list_entry, startup));
|
assert!(bucket.should_remove_from_mem(
|
||||||
|
current_age,
|
||||||
|
&one_element_slot_list_entry,
|
||||||
|
startup,
|
||||||
|
false,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue