Refactor cache

This commit is contained in:
Marco De Araujo 2026-01-15 08:23:20 -04:00
parent 512f597a0f
commit 70a70af859

View file

@ -1,7 +1,10 @@
use std::borrow::Cow; use std::{
use std::cmp::min; borrow::Cow,
use std::collections::HashMap; cmp::min,
use std::sync::OnceLock; collections::{HashMap, hash_map::DefaultHasher},
hash::{Hash, Hasher},
sync::{OnceLock, RwLock},
};
use crate::i18n::t; use crate::i18n::t;
use crate::ui::dashboard::{ use crate::ui::dashboard::{
@ -19,6 +22,7 @@ use ratatui::{
const STATUS_LINE_LENGTH: usize = 100; const STATUS_LINE_LENGTH: usize = 100;
const MAX_NAME_LENGTH: usize = 30; const MAX_NAME_LENGTH: usize = 30;
static STATUS_SPANS: OnceLock<HashMap<MonitorStatus, Span<'static>>> = OnceLock::new(); static STATUS_SPANS: OnceLock<HashMap<MonitorStatus, Span<'static>>> = OnceLock::new();
static STATUS_LINE_CACHE: OnceLock<RwLock<HashMap<u64, Vec<Span<'static>>>>> = OnceLock::new();
pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) { pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) {
let available_height = area.height as usize; let available_height = area.height as usize;
@ -185,7 +189,7 @@ fn create_monitor_item(monitor: &MonitorViewState) -> Row<'_> {
let response_text = format!("{:>7}ms", monitor.response_time); let response_text = format!("{:>7}ms", monitor.response_time);
let uptime_text = format!("{:>7}%", monitor.uptime_24h); let uptime_text = format!("{:>7}%", monitor.uptime_24h);
let status_line_spans = create_status_line_spans(&monitor.status_history); let status_line_spans = get_cached_status_line(&monitor.status_history);
Row::new(vec![ Row::new(vec![
get_formated_line(format!("{} ", status_icon), status_color, Modifier::empty()), get_formated_line(format!("{} ", status_icon), status_color, Modifier::empty()),
@ -225,18 +229,50 @@ fn get_cached_status_span(status: &MonitorStatus) -> Span<'static> {
cache.get(status).cloned().unwrap_or_default() cache.get(status).cloned().unwrap_or_default()
} }
fn create_status_line_spans(status_history: &[MonitorStatus]) -> Line<'_> {
let spans: Vec<_> = status_history
.iter()
.rev()
.take(STATUS_LINE_LENGTH)
.map(|status| get_cached_status_span(status))
.collect();
Line::from(spans)
}
fn title_style() -> Style { fn title_style() -> Style {
Style::default() Style::default()
.fg(Color::Yellow) .fg(Color::Yellow)
.add_modifier(Modifier::BOLD) .add_modifier(Modifier::BOLD)
} }
fn calculate_history_hash(status_history: &[MonitorStatus]) -> u64 {
let mut hasher = DefaultHasher::new();
status_history
.iter()
.take(STATUS_LINE_LENGTH)
.for_each(|status| {
status.hash(&mut hasher);
});
hasher.finish()
}
fn get_cached_status_line(status_history: &[MonitorStatus]) -> Line<'static> {
let hash = calculate_history_hash(status_history);
let cache = STATUS_LINE_CACHE.get_or_init(|| RwLock::new(HashMap::new()));
{
let read = cache.read().unwrap();
if let Some(spans) = read.get(&hash) {
return Line::from(spans.clone());
}
}
let spans: Vec<Span<'static>> = status_history
.iter()
.rev()
.take(STATUS_LINE_LENGTH)
.map(|status| get_cached_status_span(status))
.collect();
let mut write = cache.write().unwrap();
if write.len() > 1000 {
let keys_to_remove: Vec<_> = write.keys().take(250).copied().collect();
for key in keys_to_remove {
write.remove(&key);
}
}
write.insert(hash, spans.clone());
Line::from(spans)
}