Skip to main content

noxu_tree/
tree_location.rs

1//! Recovery cursor-like position tracker.
2//!
3//!
4//! Tracks a location in a tree during recovery operations. This is similar
5//! to a cursor but is used specifically for recovery processing.
6
7use noxu_util::{Lsn, NULL_LSN};
8
9/// Cursor-like object tracking a location in a tree.
10///
11/// Used during recovery to track the position being processed and maintain
12/// context about the current entry's attributes.
13#[derive(Debug, Clone)]
14pub struct TreeLocation {
15    /// Index within the current BIN.
16    pub index: i32,
17
18    /// The key at this location (if known).
19    pub ln_key: Option<Vec<u8>>,
20
21    /// LSN of the child at this location.
22    pub child_lsn: Lsn,
23
24    /// Logged size of the child entry.
25    pub child_logged_size: i32,
26
27    /// True if this entry is known deleted.
28    pub is_kd: bool,
29
30    /// True if this is an embedded LN.
31    pub is_embedded: bool,
32}
33
34impl TreeLocation {
35    /// Creates a new TreeLocation with default values.
36    pub fn new() -> Self {
37        TreeLocation {
38            index: -1,
39            ln_key: None,
40            child_lsn: NULL_LSN,
41            child_logged_size: 0,
42            is_kd: false,
43            is_embedded: false,
44        }
45    }
46
47    /// Creates a TreeLocation with specific index and key.
48    ///
49    /// # Arguments
50    /// * `index` - The slot index in the BIN
51    /// * `ln_key` - The key at this location
52    pub fn with_index_and_key(index: i32, ln_key: Vec<u8>) -> Self {
53        TreeLocation {
54            index,
55            ln_key: Some(ln_key),
56            child_lsn: NULL_LSN,
57            child_logged_size: 0,
58            is_kd: false,
59            is_embedded: false,
60        }
61    }
62
63    /// Resets all fields to their default values.
64    ///
65    /// This allows reusing a TreeLocation instance.
66    pub fn reset(&mut self) {
67        self.index = -1;
68        self.ln_key = None;
69        self.child_lsn = NULL_LSN;
70        self.child_logged_size = 0;
71        self.is_kd = false;
72        self.is_embedded = false;
73    }
74
75    /// Returns true if this location has a valid index.
76    #[inline]
77    pub fn has_valid_index(&self) -> bool {
78        self.index >= 0
79    }
80
81    /// Returns true if a key is present at this location.
82    #[inline]
83    pub fn has_key(&self) -> bool {
84        self.ln_key.is_some()
85    }
86
87    /// Returns the key as a slice, if present.
88    #[inline]
89    pub fn key_as_slice(&self) -> Option<&[u8]> {
90        self.ln_key.as_deref()
91    }
92
93    /// Sets the key at this location.
94    pub fn set_key(&mut self, key: Vec<u8>) {
95        self.ln_key = Some(key);
96    }
97
98    /// Clears the key at this location.
99    pub fn clear_key(&mut self) {
100        self.ln_key = None;
101    }
102}
103
104impl Default for TreeLocation {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use noxu_util::Lsn;
114
115    #[test]
116    fn test_new() {
117        let loc = TreeLocation::new();
118
119        assert_eq!(loc.index, -1);
120        assert!(loc.ln_key.is_none());
121        assert_eq!(loc.child_lsn, NULL_LSN);
122        assert_eq!(loc.child_logged_size, 0);
123        assert!(!loc.is_kd);
124        assert!(!loc.is_embedded);
125    }
126
127    #[test]
128    fn test_default() {
129        let loc = TreeLocation::default();
130
131        assert_eq!(loc.index, -1);
132        assert!(loc.ln_key.is_none());
133    }
134
135    #[test]
136    fn test_with_index_and_key() {
137        let key = b"test_key".to_vec();
138        let loc = TreeLocation::with_index_and_key(5, key.clone());
139
140        assert_eq!(loc.index, 5);
141        assert_eq!(loc.ln_key, Some(key));
142        assert_eq!(loc.child_lsn, NULL_LSN);
143    }
144
145    #[test]
146    fn test_reset() {
147        let mut loc = TreeLocation::with_index_and_key(10, b"key".to_vec());
148        loc.child_lsn = Lsn::new(1, 1000);
149        loc.child_logged_size = 100;
150        loc.is_kd = true;
151        loc.is_embedded = true;
152
153        loc.reset();
154
155        assert_eq!(loc.index, -1);
156        assert!(loc.ln_key.is_none());
157        assert_eq!(loc.child_lsn, NULL_LSN);
158        assert_eq!(loc.child_logged_size, 0);
159        assert!(!loc.is_kd);
160        assert!(!loc.is_embedded);
161    }
162
163    #[test]
164    fn test_has_valid_index() {
165        let mut loc = TreeLocation::new();
166        assert!(!loc.has_valid_index());
167
168        loc.index = 0;
169        assert!(loc.has_valid_index());
170
171        loc.index = 42;
172        assert!(loc.has_valid_index());
173
174        loc.index = -1;
175        assert!(!loc.has_valid_index());
176    }
177
178    #[test]
179    fn test_has_key() {
180        let mut loc = TreeLocation::new();
181        assert!(!loc.has_key());
182
183        loc.set_key(b"key".to_vec());
184        assert!(loc.has_key());
185
186        loc.clear_key();
187        assert!(!loc.has_key());
188    }
189
190    #[test]
191    fn test_key_as_slice() {
192        let mut loc = TreeLocation::new();
193        assert!(loc.key_as_slice().is_none());
194
195        let key = b"test_key".to_vec();
196        loc.set_key(key.clone());
197
198        assert_eq!(loc.key_as_slice(), Some(key.as_slice()));
199    }
200
201    #[test]
202    fn test_set_and_clear_key() {
203        let mut loc = TreeLocation::new();
204
205        let key1 = b"key1".to_vec();
206        loc.set_key(key1.clone());
207        assert_eq!(loc.ln_key, Some(key1));
208
209        let key2 = b"key2".to_vec();
210        loc.set_key(key2.clone());
211        assert_eq!(loc.ln_key, Some(key2));
212
213        loc.clear_key();
214        assert!(loc.ln_key.is_none());
215    }
216
217    #[test]
218    fn test_clone() {
219        let mut loc1 = TreeLocation::with_index_and_key(5, b"key".to_vec());
220        loc1.child_lsn = Lsn::new(2, 2000);
221        loc1.is_kd = true;
222
223        let loc2 = loc1.clone();
224
225        assert_eq!(loc2.index, loc1.index);
226        assert_eq!(loc2.ln_key, loc1.ln_key);
227        assert_eq!(loc2.child_lsn, loc1.child_lsn);
228        assert_eq!(loc2.is_kd, loc1.is_kd);
229    }
230
231    #[test]
232    fn test_mutable_fields() {
233        let mut loc = TreeLocation::new();
234
235        loc.index = 10;
236        loc.child_lsn = Lsn::new(5, 5000);
237        loc.child_logged_size = 256;
238        loc.is_kd = true;
239        loc.is_embedded = true;
240
241        assert_eq!(loc.index, 10);
242        assert_eq!(loc.child_lsn, Lsn::new(5, 5000));
243        assert_eq!(loc.child_logged_size, 256);
244        assert!(loc.is_kd);
245        assert!(loc.is_embedded);
246    }
247}