unconscious: move health refresh outside lock too

refresh_health() was doing Store::load() + compute_graph_health()
while holding the Unconscious lock, causing 12 second stalls.

Split into needs_health_refresh() (quick check) and set_health()
(quick store), with the slow I/O happening outside the lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-12 20:37:54 -04:00
parent f40d8cfa9d
commit ac6f1e9294
2 changed files with 18 additions and 14 deletions

View file

@ -346,6 +346,14 @@ impl Mind {
s.unc_idle = true; s.unc_idle = true;
} }
loop { loop {
// Phase 0: health check outside lock (slow I/O)
let needs_health = unc.lock().await.needs_health_refresh();
if needs_health {
if let Ok(store) = crate::store::Store::load() {
let health = crate::subconscious::daemon::compute_graph_health(&store);
unc.lock().await.set_health(health);
}
}
// Phase 1: quick work under lock // Phase 1: quick work under lock
let to_spawn = { let to_spawn = {
let mut guard = unc.lock().await; let mut guard = unc.lock().await;

View file

@ -166,25 +166,21 @@ impl Unconscious {
}).collect() }).collect()
} }
fn refresh_health(&mut self) { /// Check if health refresh is due (quick check, no I/O).
let store = match crate::store::Store::load() { pub fn needs_health_refresh(&self) -> bool {
Ok(s) => s, self.last_health_check
Err(_) => return, .map(|t| t.elapsed() > std::time::Duration::from_secs(600))
}; .unwrap_or(true)
self.graph_health = Some(crate::subconscious::daemon::compute_graph_health(&store)); }
/// Store computed health (quick, just assignment).
pub fn set_health(&mut self, health: crate::subconscious::daemon::GraphHealth) {
self.graph_health = Some(health);
self.last_health_check = Some(Instant::now()); self.last_health_check = Some(Instant::now());
} }
/// Reap finished agents (quick, hold lock briefly). /// Reap finished agents (quick, hold lock briefly).
pub fn reap_finished(&mut self) { pub fn reap_finished(&mut self) {
// Periodic graph health refresh (also on first call)
if self.last_health_check
.map(|t| t.elapsed() > std::time::Duration::from_secs(600))
.unwrap_or(true)
{
self.refresh_health();
}
for agent in &mut self.agents { for agent in &mut self.agents {
if agent.handle.as_ref().is_some_and(|h| h.is_finished()) { if agent.handle.as_ref().is_some_and(|h| h.is_finished()) {
let handle = agent.handle.take().unwrap(); let handle = agent.handle.take().unwrap();