open_wal/observer.rs
1//! Durability observation — the `DurabilityObserver` hook (§15.3).
2//!
3//! This lives in **core**, not in a separate "replication" module, because the
4//! §6 public API is generic over it: `Wal<O: DurabilityObserver = NullObserver>`.
5//! The observer publishes only the durable *watermark* (an [`Lsn`]); shipping
6//! actual record bytes is a downstream consumer's job (via a `Reader`), never
7//! the observer's.
8//!
9//! It fires on the writer thread at the end of [`commit`](crate::Wal::commit),
10//! **after** `durable_lsn` has advanced — strictly downstream of durability, so
11//! it can never affect the D1–D12 invariants. Its contract is "cheap,
12//! non-blocking, no I/O, must not panic"; it has no path to fail durability.
13
14use crate::Lsn;
15
16/// Notified after each successful durability advance, on the writer thread.
17///
18/// `on_durable` runs synchronously inside [`commit`](crate::Wal::commit) once
19/// the `fdatasync` has completed and `durable_lsn` has moved forward. It MUST be
20/// cheap and non-blocking (an atomic release-store or a queue push), and MUST
21/// NOT perform I/O, block, or panic. `durable_lsn` is monotonic across calls.
22pub trait DurabilityObserver {
23 /// `durable_lsn` is the new (monotonic) durable watermark.
24 fn on_durable(&mut self, durable_lsn: Lsn);
25}
26
27/// The default observer: a verified no-op that inlines to nothing.
28///
29/// Because `Wal` defaults its observer type parameter to `NullObserver`, the
30/// don't-ship case compiles away with no vtable call on the commit path
31/// (static dispatch). Use a real observer only when a downstream consumer needs
32/// the watermark.
33#[derive(Debug, Default, Clone, Copy)]
34pub struct NullObserver;
35
36impl DurabilityObserver for NullObserver {
37 #[inline]
38 fn on_durable(&mut self, _durable_lsn: Lsn) {}
39}