Skip to main content

coven_database/
work_counts.rs

1//! Test-only accounting shared by a database's writer and readers.
2
3use coven_foundation::locks::lock_unpoisoned;
4use std::sync::{Arc, Mutex};
5
6/// Local database work observed at its execution boundaries.
7#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
8pub struct WorkCounts {
9    /// Successful acquisitions of the writer connection, including read-only work.
10    pub writer_holds: usize,
11    /// Successful durable transaction commits, including unchanged transactions.
12    pub commits: usize,
13    /// Snapshot bodies the loader parsed, for loading, verification or
14    /// file-reference checks.
15    pub snapshot_reads: usize,
16    /// Rows whose published state an applied slot kept or put back beside
17    /// this device's unsent writes (§6.2).
18    pub published_rows: usize,
19    /// Reads of what a transaction can't change: the schema version, SQLite's
20    /// schema cookie, and synced columns' and foreign keys' registered ids.
21    pub constant_reads: usize,
22    /// SQLite virtual machine steps the app's statements ran in `query` and
23    /// `query_row`, in reads, live queries' runs, writes and migrations.
24    pub app_read_steps: usize,
25    /// The app's statements that return rows, run in `query` and `query_row`,
26    /// one per run.
27    pub app_read_statements: usize,
28    /// SQLite virtual machine steps the app's statements ran in `execute` and
29    /// `execute_batch`, triggers' included, in writes and migrations.
30    pub app_write_steps: usize,
31    /// Steps of coven's lookups judging whether a write changed rows a live
32    /// query joins: each asks whether a partner row in its scope holds a
33    /// changed row's value (§4).
34    pub lookup_steps: usize,
35}
36
37/// Injected counter; clones observe the same database, never other test databases.
38#[derive(Clone)]
39pub struct WorkCounter(Arc<Mutex<WorkCounts>>);
40
41impl WorkCounter {
42    /// A counter no database has counted on yet, for a test to give one.
43    pub fn new() -> Self {
44        Self(Arc::new(Mutex::new(WorkCounts::default())))
45    }
46
47    /// Start another measurement after the preceding work has completed.
48    pub fn take(&self) -> WorkCounts {
49        std::mem::take(&mut lock_unpoisoned(&self.0))
50    }
51
52    pub(crate) fn record(&self, update: impl FnOnce(&mut WorkCounts)) {
53        update(&mut lock_unpoisoned(&self.0));
54    }
55}