Skip to main content

noxu_db/
durability.rs

1//! Durability and sync policies for transactions.
2//!
3
4use noxu_dbi::ReplicaAckPolicyKind;
5
6/// Sync policy for local commit synchronization.
7///
8/// Determines how transaction commits are synchronized to stable storage.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
10pub enum SyncPolicy {
11    /// Write and fsync to disk on commit.
12    ///
13    /// Maximum durability, but slowest performance. Guarantees that committed
14    /// data is written to stable storage.
15    #[default]
16    Sync,
17
18    /// Write to OS buffers on commit (no fsync).
19    ///
20    /// Data is written to OS buffers but not necessarily to disk. Faster than
21    /// Sync but less durable in case of OS crash.
22    WriteNoSync,
23
24    /// No write or fsync on commit (OS buffers only).
25    ///
26    /// Maximum performance, minimum durability. Data remains in application
27    /// buffers until background writer flushes it. Not durable in case of
28    /// application crash.
29    NoSync,
30}
31
32/// Acknowledgment policy for replicated environments.
33///
34/// Determines how many replicas must acknowledge a transaction before
35/// the commit returns to the application.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
37pub enum ReplicaAckPolicy {
38    /// All replicas must acknowledge.
39    All,
40
41    /// No acknowledgment required.
42    None,
43
44    /// Simple majority must acknowledge.
45    #[default]
46    SimpleMajority,
47}
48
49/// Durability characteristics for a transaction.
50///
51/// Specifies the durability guarantees associated with a transaction when
52/// it's committed. The durability policy consists of:
53/// - Local sync policy: how the master node synchronizes
54/// - Replica sync policy: how replica nodes synchronize
55/// - Replica acknowledgment policy: how many replicas must acknowledge
56///
57///
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct Durability {
60    /// Sync policy for the local (master) node.
61    pub local_sync: SyncPolicy,
62
63    /// Sync policy for replica nodes.
64    pub replica_sync: SyncPolicy,
65
66    /// Acknowledgment policy for replicas.
67    pub replica_ack: ReplicaAckPolicy,
68}
69
70impl ReplicaAckPolicy {
71    /// Convert this policy to the dependency-free `ReplicaAckPolicyKind`
72    /// used by the `ReplicaAckCoordinator` trait in `noxu-dbi`.
73    pub fn as_kind(self) -> ReplicaAckPolicyKind {
74        match self {
75            ReplicaAckPolicy::All => ReplicaAckPolicyKind::All,
76            ReplicaAckPolicy::SimpleMajority => {
77                ReplicaAckPolicyKind::SimpleMajority
78            }
79            ReplicaAckPolicy::None => ReplicaAckPolicyKind::None,
80        }
81    }
82}
83
84impl Durability {
85    /// Creates a new Durability with the specified policies.
86    pub fn new(
87        local_sync: SyncPolicy,
88        replica_sync: SyncPolicy,
89        replica_ack: ReplicaAckPolicy,
90    ) -> Self {
91        Self { local_sync, replica_sync, replica_ack }
92    }
93
94    /// Maximum durability: Sync on master and replicas, all replicas acknowledge.
95    pub const COMMIT_SYNC: Self = Self {
96        local_sync: SyncPolicy::Sync,
97        replica_sync: SyncPolicy::Sync,
98        replica_ack: ReplicaAckPolicy::SimpleMajority,
99    };
100
101    /// No sync on commit, maximum performance.
102    pub const COMMIT_NO_SYNC: Self = Self {
103        local_sync: SyncPolicy::NoSync,
104        replica_sync: SyncPolicy::NoSync,
105        replica_ack: ReplicaAckPolicy::None,
106    };
107
108    /// Write but no sync on commit, good balance of performance and durability.
109    pub const COMMIT_WRITE_NO_SYNC: Self = Self {
110        local_sync: SyncPolicy::WriteNoSync,
111        replica_sync: SyncPolicy::WriteNoSync,
112        replica_ack: ReplicaAckPolicy::SimpleMajority,
113    };
114}
115
116impl Default for Durability {
117    fn default() -> Self {
118        Self::COMMIT_SYNC
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_sync_policy_default() {
128        assert_eq!(SyncPolicy::default(), SyncPolicy::Sync);
129    }
130
131    #[test]
132    fn test_sync_policy_equality() {
133        assert_eq!(SyncPolicy::Sync, SyncPolicy::Sync);
134        assert_ne!(SyncPolicy::Sync, SyncPolicy::NoSync);
135    }
136
137    #[test]
138    fn test_replica_ack_policy_default() {
139        assert_eq!(
140            ReplicaAckPolicy::default(),
141            ReplicaAckPolicy::SimpleMajority
142        );
143    }
144
145    #[test]
146    fn test_replica_ack_policy_equality() {
147        assert_eq!(ReplicaAckPolicy::All, ReplicaAckPolicy::All);
148        assert_ne!(ReplicaAckPolicy::All, ReplicaAckPolicy::None);
149    }
150
151    #[test]
152    fn test_durability_new() {
153        let d = Durability::new(
154            SyncPolicy::Sync,
155            SyncPolicy::WriteNoSync,
156            ReplicaAckPolicy::All,
157        );
158        assert_eq!(d.local_sync, SyncPolicy::Sync);
159        assert_eq!(d.replica_sync, SyncPolicy::WriteNoSync);
160        assert_eq!(d.replica_ack, ReplicaAckPolicy::All);
161    }
162
163    #[test]
164    fn test_durability_commit_sync() {
165        let d = Durability::COMMIT_SYNC;
166        assert_eq!(d.local_sync, SyncPolicy::Sync);
167        assert_eq!(d.replica_sync, SyncPolicy::Sync);
168        assert_eq!(d.replica_ack, ReplicaAckPolicy::SimpleMajority);
169    }
170
171    #[test]
172    fn test_durability_commit_no_sync() {
173        let d = Durability::COMMIT_NO_SYNC;
174        assert_eq!(d.local_sync, SyncPolicy::NoSync);
175        assert_eq!(d.replica_sync, SyncPolicy::NoSync);
176        assert_eq!(d.replica_ack, ReplicaAckPolicy::None);
177    }
178
179    #[test]
180    fn test_durability_commit_write_no_sync() {
181        let d = Durability::COMMIT_WRITE_NO_SYNC;
182        assert_eq!(d.local_sync, SyncPolicy::WriteNoSync);
183        assert_eq!(d.replica_sync, SyncPolicy::WriteNoSync);
184        assert_eq!(d.replica_ack, ReplicaAckPolicy::SimpleMajority);
185    }
186
187    #[test]
188    fn test_durability_default() {
189        let d = Durability::default();
190        assert_eq!(d, Durability::COMMIT_SYNC);
191    }
192
193    #[test]
194    fn test_durability_equality() {
195        let d1 = Durability::new(
196            SyncPolicy::Sync,
197            SyncPolicy::Sync,
198            ReplicaAckPolicy::SimpleMajority,
199        );
200        let d2 = Durability::COMMIT_SYNC;
201        assert_eq!(d1, d2);
202    }
203
204    #[test]
205    fn test_durability_clone() {
206        let d1 = Durability::COMMIT_SYNC;
207        let d2 = d1;
208        assert_eq!(d1, d2);
209    }
210
211    #[test]
212    fn test_sync_policy_copy() {
213        let s1 = SyncPolicy::Sync;
214        let s2 = s1;
215        assert_eq!(s1, s2);
216    }
217
218    #[test]
219    fn test_replica_ack_policy_copy() {
220        let r1 = ReplicaAckPolicy::All;
221        let r2 = r1;
222        assert_eq!(r1, r2);
223    }
224}