Skip to main content

noxu_tree/
child_reference.rs

1//! Reference from parent to child in the B-tree.
2//!
3//!
4//! A ChildReference contains the key, LSN, and state for a reference from
5//! a parent IN to a child node. This is primarily used for the tree root.
6
7use crate::entry_states::SlotState;
8use noxu_util::Lsn;
9
10/// A reference in the tree from parent to child.
11///
12/// Contains a key, LSN (on-disk location), and state byte for tracking
13/// deletion and dirty status. This structure is used primarily for the
14/// tree root reference, though in it's also used within IN slot arrays.
15///
16/// In the Noxu DB Rust port, individual IN/BIN slot storage is separate from
17/// ChildReference, but the concepts are similar.
18#[derive(Debug, Clone)]
19pub struct ChildReference {
20    /// The key identifying this child in the parent's key range.
21    pub key: Vec<u8>,
22
23    /// The LSN of the child node on disk, or NULL_LSN if not yet logged.
24    pub lsn: Lsn,
25
26    /// State flags for this reference (dirty, known-deleted, etc.).
27    pub state: SlotState,
28}
29
30impl ChildReference {
31    /// Creates a new ChildReference.
32    ///
33    /// # Arguments
34    /// * `key` - The key identifying this child
35    /// * `lsn` - The LSN of the child node on disk
36    /// * `state` - Initial state flags
37    pub fn new(key: Vec<u8>, lsn: Lsn, state: SlotState) -> Self {
38        ChildReference { key, lsn, state }
39    }
40
41    /// Creates a new ChildReference with empty state.
42    ///
43    /// # Arguments
44    /// * `key` - The key identifying this child
45    /// * `lsn` - The LSN of the child node on disk
46    pub fn new_with_key_and_lsn(key: Vec<u8>, lsn: Lsn) -> Self {
47        ChildReference { key, lsn, state: SlotState::new() }
48    }
49
50    /// Returns true if the known-deleted flag is set.
51    #[inline]
52    pub fn is_known_deleted(&self) -> bool {
53        self.state.is_known_deleted()
54    }
55
56    /// Sets the known-deleted flag.
57    #[inline]
58    pub fn set_known_deleted(&mut self) {
59        self.state.set_known_deleted();
60    }
61
62    /// Clears the known-deleted flag.
63    #[inline]
64    pub fn clear_known_deleted(&mut self) {
65        self.state.clear_known_deleted();
66    }
67
68    /// Returns true if the pending-deleted flag is set.
69    #[inline]
70    pub fn is_pending_deleted(&self) -> bool {
71        self.state.is_pending_deleted()
72    }
73
74    /// Sets the pending-deleted flag.
75    #[inline]
76    pub fn set_pending_deleted(&mut self) {
77        self.state.set_pending_deleted();
78    }
79
80    /// Clears the pending-deleted flag.
81    #[inline]
82    pub fn clear_pending_deleted(&mut self) {
83        self.state.clear_pending_deleted();
84    }
85
86    /// Returns true if the dirty flag is set.
87    #[inline]
88    pub fn is_dirty(&self) -> bool {
89        self.state.is_dirty()
90    }
91
92    /// Sets the dirty flag.
93    #[inline]
94    pub fn set_dirty(&mut self) {
95        self.state.set_dirty();
96    }
97
98    /// Clears the dirty flag.
99    #[inline]
100    pub fn clear_dirty(&mut self) {
101        self.state.clear_dirty();
102    }
103
104    /// Returns true if the embedded-LN flag is set.
105    #[inline]
106    pub fn is_embedded_ln(&self) -> bool {
107        self.state.is_embedded_ln()
108    }
109
110    /// Sets the embedded-LN flag.
111    #[inline]
112    pub fn set_embedded_ln(&mut self) {
113        self.state.set_embedded_ln();
114    }
115
116    /// Clears all transient state bits (not persisted to disk).
117    #[inline]
118    pub fn clear_transient_bits(&mut self) {
119        self.state.clear_transient_bits();
120    }
121}
122
123impl Default for ChildReference {
124    fn default() -> Self {
125        ChildReference {
126            key: Vec::new(),
127            lsn: noxu_util::NULL_LSN,
128            state: SlotState::new(),
129        }
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use noxu_util::{Lsn, NULL_LSN};
137
138    #[test]
139    fn test_new() {
140        let key = b"test_key".to_vec();
141        let lsn = Lsn::new(1, 1000);
142        let state = SlotState::new();
143
144        let child_ref = ChildReference::new(key.clone(), lsn, state);
145
146        assert_eq!(child_ref.key, key);
147        assert_eq!(child_ref.lsn, lsn);
148        assert!(!child_ref.is_dirty());
149    }
150
151    #[test]
152    fn test_new_with_key_and_lsn() {
153        let key = b"key".to_vec();
154        let lsn = Lsn::new(5, 5000);
155
156        let child_ref = ChildReference::new_with_key_and_lsn(key.clone(), lsn);
157
158        assert_eq!(child_ref.key, key);
159        assert_eq!(child_ref.lsn, lsn);
160        assert!(!child_ref.is_dirty());
161        assert!(!child_ref.is_known_deleted());
162    }
163
164    #[test]
165    fn test_default() {
166        let child_ref = ChildReference::default();
167
168        assert!(child_ref.key.is_empty());
169        assert_eq!(child_ref.lsn, NULL_LSN);
170        assert!(!child_ref.is_dirty());
171    }
172
173    #[test]
174    fn test_dirty_flag() {
175        let mut child_ref = ChildReference::default();
176
177        assert!(!child_ref.is_dirty());
178
179        child_ref.set_dirty();
180        assert!(child_ref.is_dirty());
181
182        child_ref.clear_dirty();
183        assert!(!child_ref.is_dirty());
184    }
185
186    #[test]
187    fn test_known_deleted_flag() {
188        let mut child_ref = ChildReference::default();
189
190        assert!(!child_ref.is_known_deleted());
191
192        child_ref.set_known_deleted();
193        assert!(child_ref.is_known_deleted());
194
195        child_ref.clear_known_deleted();
196        assert!(!child_ref.is_known_deleted());
197    }
198
199    #[test]
200    fn test_pending_deleted_flag() {
201        let mut child_ref = ChildReference::default();
202
203        assert!(!child_ref.is_pending_deleted());
204
205        child_ref.set_pending_deleted();
206        assert!(child_ref.is_pending_deleted());
207
208        child_ref.clear_pending_deleted();
209        assert!(!child_ref.is_pending_deleted());
210    }
211
212    #[test]
213    fn test_embedded_ln_flag() {
214        let mut child_ref = ChildReference::default();
215
216        assert!(!child_ref.is_embedded_ln());
217
218        child_ref.set_embedded_ln();
219        assert!(child_ref.is_embedded_ln());
220    }
221
222    #[test]
223    fn test_multiple_flags() {
224        let mut child_ref = ChildReference::default();
225
226        child_ref.set_dirty();
227        child_ref.set_pending_deleted();
228
229        assert!(child_ref.is_dirty());
230        assert!(child_ref.is_pending_deleted());
231        assert!(!child_ref.is_known_deleted());
232
233        child_ref.clear_dirty();
234        assert!(!child_ref.is_dirty());
235        assert!(child_ref.is_pending_deleted());
236    }
237
238    #[test]
239    fn test_clear_transient_bits() {
240        let mut child_ref = ChildReference::default();
241
242        child_ref.state.set_dirty();
243        child_ref.state.set_dirty();
244
245        assert!(child_ref.state.is_dirty());
246        assert!(child_ref.is_dirty());
247
248        child_ref.clear_transient_bits();
249
250        assert!(child_ref.state.is_dirty()); // dirty is not a transient bit
251        assert!(child_ref.is_dirty()); // Non-transient bit remains
252    }
253
254    #[test]
255    fn test_clone() {
256        let key = b"clone_key".to_vec();
257        let lsn = Lsn::new(10, 10000);
258        let mut child_ref = ChildReference::new_with_key_and_lsn(key, lsn);
259        child_ref.set_dirty();
260
261        let cloned = child_ref.clone();
262
263        assert_eq!(cloned.key, child_ref.key);
264        assert_eq!(cloned.lsn, child_ref.lsn);
265        assert_eq!(cloned.is_dirty(), child_ref.is_dirty());
266    }
267}