Skip to main content

spacedb_consistency/
outcome.rs

1//! The honesty contract โ€” every op reports the consistency it *actually* achieved.
2//!
3//! SpaceDB never presents stale-as-fresh or partition-blocked-as-committed. An
4//! [`Outcome`] tells the caller exactly what happened, so an app can show
5//! "saved locally ยท syncing" vs "saved", or refuse to oversell a seat, truthfully.
6
7use crate::tier::Tier;
8
9/// Why a (strong) op could not be served.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum UnavailableReason {
12    /// The network is partitioned.
13    Partition,
14    /// A quorum could not be reached (too few members responded).
15    QuorumUnreachable,
16}
17
18/// The consistency a read or write actually achieved.
19#[derive(Clone, Debug, PartialEq, Eq)]
20pub enum Outcome {
21    /// The op was committed at this tier (a strong commit, or a causal/convergent
22    /// read that is up to date with what the session has observed).
23    Committed(Tier),
24    /// Written locally and offline-durable, but not yet propagated to peers.
25    Local,
26    /// Served from a replica that is behind the session's frontier by `lag_ops`
27    /// operations โ€” honestly stale, not silently so.
28    Stale { lag_ops: usize },
29    /// A strong op could not be served and was **not** committed divergently.
30    Unavailable(UnavailableReason),
31}
32
33impl Outcome {
34    /// Whether the op committed at some tier.
35    pub fn is_committed(&self) -> bool {
36        matches!(self, Outcome::Committed(_))
37    }
38
39    /// Whether the op was served at all (anything but `Unavailable`).
40    pub fn is_available(&self) -> bool {
41        !matches!(self, Outcome::Unavailable(_))
42    }
43
44    /// The tier committed at, if any.
45    pub fn tier(&self) -> Option<Tier> {
46        match self {
47            Outcome::Committed(tier) => Some(*tier),
48            _ => None,
49        }
50    }
51}