Skip to main content

kaizen/store/sqlite/
samples.rs

1use super::*;
2
3impl Store {
4    pub fn append_session_sample(
5        &self,
6        session_id: &str,
7        ts_ms: u64,
8        pid: u32,
9        cpu_percent: Option<f64>,
10        rss_bytes: Option<u64>,
11    ) -> Result<()> {
12        self.conn.execute(
13            "INSERT OR REPLACE INTO session_samples (session_id, ts_ms, pid, cpu_percent, rss_bytes)
14             VALUES (?1, ?2, ?3, ?4, ?5)",
15            params![
16                session_id,
17                ts_ms as i64,
18                pid as i64,
19                cpu_percent,
20                rss_bytes.map(|b| b as i64)
21            ],
22        )?;
23        Ok(())
24    }
25
26    /// Per-session maxima for retro heuristics.
27    pub fn list_session_sample_aggs_in_window(
28        &self,
29        workspace: &str,
30        start_ms: u64,
31        end_ms: u64,
32    ) -> Result<Vec<SessionSampleAgg>> {
33        let mut stmt = self.conn.prepare(
34            "SELECT ss.session_id, COUNT(*) AS n,
35                    MAX(ss.cpu_percent), MAX(ss.rss_bytes)
36             FROM session_samples ss
37             JOIN sessions s ON s.id = ss.session_id
38             WHERE s.workspace = ?1 AND s.started_at_ms >= ?2 AND s.started_at_ms <= ?3
39             GROUP BY ss.session_id",
40        )?;
41        let rows = stmt.query_map(params![workspace, start_ms as i64, end_ms as i64], |r| {
42            let sid: String = r.get(0)?;
43            let n: i64 = r.get(1)?;
44            let max_cpu: Option<f64> = r.get(2)?;
45            let max_rss: Option<i64> = r.get(3)?;
46            Ok(SessionSampleAgg {
47                session_id: sid,
48                sample_count: n as u64,
49                max_cpu_percent: max_cpu.unwrap_or(0.0),
50                max_rss_bytes: max_rss.map(|x| x as u64).unwrap_or(0),
51            })
52        })?;
53        rows.map(|r| r.map_err(anyhow::Error::from)).collect()
54    }
55}