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}