Skip to main content

dsfb_database/residual/
cache_io.rs

1//! Cache / buffer collapse residuals.
2//!
3//! Two channels per source:
4//!   * **hit-ratio drop** — `expected_hit_ratio − observed_hit_ratio`,
5//!     positive when the cache is failing.
6//!   * **I/O wait amplification** — `observed_io_wait_seconds /
7//!     baseline_io_wait_seconds − 1.0`, positive when I/O is slower than
8//!     the rolling baseline.
9//!
10//! In PostgreSQL 16+ both are first-class via `pg_stat_io.hits` and
11//! `pg_stat_io.read_time` (fact #44). In SQL Server they are reachable via
12//! `sys.dm_os_buffer_descriptors` plus Query Store I/O wait stats. In Oracle
13//! they are in `V$SEGMENT_STATISTICS` plus `V$SYSTEM_EVENT`.
14
15use super::{ResidualClass, ResidualSample, ResidualStream};
16
17pub fn push_hit_ratio(
18    stream: &mut ResidualStream,
19    t: f64,
20    cache_id: &str,
21    expected: f64,
22    observed: f64,
23) {
24    let drop = expected - observed;
25    stream.push(ResidualSample::new(t, ResidualClass::CacheIo, drop).with_channel(cache_id));
26}
27
28pub fn push_io_amplification(
29    stream: &mut ResidualStream,
30    t: f64,
31    file_id: &str,
32    observed_seconds: f64,
33    baseline_seconds: f64,
34) {
35    let amp = if baseline_seconds > 0.0 {
36        observed_seconds / baseline_seconds - 1.0
37    } else {
38        0.0
39    };
40    stream.push(
41        ResidualSample::new(t, ResidualClass::CacheIo, amp).with_channel(format!("{file_id}#io")),
42    );
43}