noxu_rep/commit_token.rs
1//! Commit tokens for commit-point read consistency.
2//!
3//! Port of `com.sleepycat.je.CommitToken` and `MasterTxn.getCommitToken`.
4//!
5//! A `CommitToken` is a bookmark into the master's serialized transaction
6//! schedule: the VLSN of a committed transaction, tagged with the identity of
7//! the replication environment that produced it. A client that performs a
8//! write on the master receives the token (`Transaction.getCommitToken`) and
9//! can hand it to a replica read via
10//! [`crate::ConsistencyPolicy::CommitPointConsistency`]; the replica then
11//! blocks the read until it has replayed up to that VLSN (see
12//! [`crate::ConsistencyTracker`]).
13//!
14//! JE keys the token on the replication-environment UUID
15//! (`CommitToken.repenvUUID`) so a token minted by one group is rejected by
16//! another. We use the replication *group name* as the stable rep-env
17//! identity for that same mismatch check (Noxu identifies a group by name; it
18//! has no per-env UUID).
19
20/// A bookmark identifying a specific committed transaction in the master's
21/// replication stream.
22///
23/// Port of `com.sleepycat.je.CommitToken` (`{ repenvUUID, vlsn }`).
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct CommitToken {
26 /// Identity of the replication environment that produced this token.
27 ///
28 /// Port of `CommitToken.repenvUUID`; here the replication group name.
29 group: String,
30 /// The commit VLSN this token marks.
31 ///
32 /// Port of `CommitToken.vlsn`.
33 vlsn: u64,
34}
35
36impl CommitToken {
37 /// Create a commit token for `vlsn` produced by replication `group`.
38 ///
39 /// Port of `new CommitToken(envUUID, commitVLSN.getSequence())`
40 /// (`MasterTxn.getCommitToken`). Mirrors JE's invariant that the VLSN
41 /// must not be NULL (0): a token with no commit VLSN is meaningless, so
42 /// returns `None` rather than minting a bogus bookmark.
43 pub fn new(group: impl Into<String>, vlsn: u64) -> Option<Self> {
44 if vlsn == 0 {
45 // CommitToken ctor: "the vlsn must not be null".
46 return None;
47 }
48 Some(Self { group: group.into(), vlsn })
49 }
50
51 /// The replication-group identity that produced this token.
52 ///
53 /// Port of `CommitToken.getRepenvUUID`.
54 pub fn group(&self) -> &str {
55 &self.group
56 }
57
58 /// The commit VLSN this token marks.
59 ///
60 /// Port of `CommitToken.getVLSN`.
61 pub fn vlsn(&self) -> u64 {
62 self.vlsn
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_new_token() {
72 let t = CommitToken::new("g1", 42).unwrap();
73 assert_eq!(t.group(), "g1");
74 assert_eq!(t.vlsn(), 42);
75 }
76
77 #[test]
78 fn test_null_vlsn_rejected() {
79 // CommitToken ctor rejects a NULL (0) VLSN.
80 assert!(CommitToken::new("g1", 0).is_none());
81 }
82
83 #[test]
84 fn test_eq_and_clone() {
85 let a = CommitToken::new("g1", 7).unwrap();
86 let b = a.clone();
87 assert_eq!(a, b);
88 let c = CommitToken::new("g2", 7).unwrap();
89 assert_ne!(a, c);
90 }
91}