fix(watcher): refresh planner stats on full scans to stop write-lock starvation
sqlite_stat1 was last gathered by a migration while image_exif had 402 rows and an all-NULL content_hash, so the planner treated the hash index as non-selective and scanned it for every row in the back-ref refresh's correlated subqueries. The face_detections pass took ~20s per watcher tick while holding the write lock, so chat/persona-chat persistence blew past busy_timeout and returned 500s. With fresh stats the three refreshes drop from ~22s to ~0.1s. - library_maintenance: add refresh_planner_stats (plain ANALYZE; PRAGMA optimize doesn't catch this on SQLite 3.45), run on full-scan ticks ahead of reconcile / back-ref refresh. - utils: retry backoff used 1_u32.pow(..), a flat ~100ms; make it the documented exponential 100/200/400ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
33fe7ce77c
commit
23371ad0bc
3 files changed
+24
-2
No files matched your search
+2
-2
@@ -27,7 +27,7 @@ where
|
||||
Err(e) => e,
|
||||
};
|
||||
for attempt in 1..=max_retries {
|
||||
let base = Duration::from_millis(100).saturating_mul(1_u32.pow(attempt - 1));
|
||||
let base = Duration::from_millis(100).saturating_mul(2_u32.pow(attempt - 1));
|
||||
let jitter_range = base.as_millis() as f64 * 0.25;
|
||||
let jitter = rand::thread_rng().gen_range(-jitter_range..=jitter_range) as u128;
|
||||
let delay = base.as_millis() as i128 + jitter as i128;
|
||||
@@ -92,7 +92,7 @@ where
|
||||
);
|
||||
break;
|
||||
}
|
||||
let base = Duration::from_millis(100).saturating_mul(1_u32.pow(attempt - 1));
|
||||
let base = Duration::from_millis(100).saturating_mul(2_u32.pow(attempt - 1));
|
||||
let jitter_range = base.as_millis() as f64 * 0.25;
|
||||
let jitter = rand::thread_rng().gen_range(-jitter_range..=jitter_range) as u128;
|
||||
let delay = base.as_millis() as i128 + jitter as i128;
|
||||
|
||||
Reference in new issue
Block a user