sweep_bptree/tree/
cursor.rs

1use crate::tree::{LeafNode, LeafNodeId};
2use crate::BPlusTree;
3use crate::Key;
4use crate::NodeStore;
5
6/// `Cursor` points to a key value pair in the tree. Not like Iterator, it can move to next or prev.
7#[derive(Debug, Clone, Copy)]
8pub struct Cursor<K: Key> {
9    /// The key this cursor points to. It is possible the `k` doesn't exist in the tree.
10    k: K,
11    /// The leaf node id this cursor points to. This is a hint, which means it is possible the leaf
12    /// for `k` is changed. In that case, the cursor will do a lookup first.
13    leaf_id_hint: LeafNodeId,
14    /// The offset this cursor points to inside the leaf. This is a hint, if the underlying tree is
15    /// modified, then the offset may be invalid.
16    offset_hint: usize,
17}
18
19impl<'k, K: Key + 'k> Cursor<K> {
20    /// Create a new cursor
21    #[inline(always)]
22    pub(crate) fn new(k: K, leaf_id: LeafNodeId, offset: usize) -> Self {
23        Self {
24            k,
25            leaf_id_hint: leaf_id,
26            offset_hint: offset,
27        }
28    }
29
30    /// Get the key of the cursor.
31    #[inline(always)]
32    pub fn key(&self) -> &K {
33        &self.k
34    }
35
36    /// Create a `Cursor` pointing to the first key-value pair in the tree.
37    pub fn first<'b, S: NodeStore<K = K>>(tree: &'b BPlusTree<S>) -> Option<(Self, &'b S::V)>
38    where
39        'k: 'b,
40    {
41        let leaf_id = tree.first_leaf()?;
42        let leaf = tree.node_store.get_leaf(leaf_id);
43
44        let kv = leaf.data_at(0);
45
46        Some((
47            Self {
48                k: kv.0.clone(),
49                leaf_id_hint: leaf_id,
50                offset_hint: 0,
51            },
52            &kv.1,
53        ))
54    }
55
56    /// Create a `Cursor` pointing to the last key-value pair in the tree. If the key for `self` is deleted, then
57    /// this returns the cursor for the key value pair just larger than the deleted key.
58    pub fn last<'b, S: NodeStore<K = K>>(tree: &'b BPlusTree<S>) -> Option<(Self, &'b S::V)>
59    where
60        'k: 'b,
61    {
62        let leaf_id = tree.last_leaf()?;
63        let leaf = tree.node_store.get_leaf(leaf_id);
64        let kv = leaf.data_at(leaf.len() - 1);
65
66        Some((
67            Self {
68                k: kv.0.clone(),
69                leaf_id_hint: leaf_id,
70                offset_hint: leaf.len() - 1,
71            },
72            &kv.1,
73        ))
74    }
75
76    /// Get the `Cursor` points to the prev key-value pair. If the key for `self` is deleted, then
77    /// this returns the cursor for the key value pair just under the deleted key.
78    pub fn prev<'a, 'b, S: NodeStore<K = K>>(&'a self, tree: &'b BPlusTree<S>) -> Option<Self> {
79        self.prev_with_value(tree).map(|x| x.0)
80    }
81
82    /// Get the `Cursor` points to the prev key-value pair, also with a reference to the value.
83    /// This is faster than first `prev`, then `value`.
84    pub fn prev_with_value<'a, 'b, S: NodeStore<K = K>>(
85        &'a self,
86        tree: &'b BPlusTree<S>,
87    ) -> Option<(Self, &'b S::V)>
88    where
89        'k: 'b,
90    {
91        let (leaf_id, leaf) = self.locate_leaf(tree)?;
92
93        let (offset, leaf) = match leaf.try_data_at(self.offset_hint) {
94            Some(kv) if kv.0.eq(&self.k) => {
95                if self.offset_hint > 0 {
96                    (self.offset_hint - 1, leaf)
97                } else if let Some(prev_id) = leaf.prev() {
98                    let prev = tree.node_store.get_leaf(prev_id);
99                    (prev.len() - 1, prev)
100                } else {
101                    return None;
102                }
103            }
104            _ => {
105                let offset = match leaf.locate_slot(&self.k) {
106                    Ok(offset) => offset,
107                    Err(offset) => offset,
108                };
109
110                if offset > 0 {
111                    (offset - 1, leaf)
112                } else if let Some(prev_id) = leaf.prev() {
113                    let prev = tree.node_store.get_leaf(prev_id);
114                    (prev.len() - 1, prev)
115                } else {
116                    return None;
117                }
118            }
119        };
120
121        let kv = leaf.data_at(offset);
122        Some((
123            Self {
124                k: kv.0.clone(),
125                leaf_id_hint: leaf_id,
126                offset_hint: offset,
127            },
128            &kv.1,
129        ))
130    }
131
132    /// Get the `Cursor` points to the next key-value pair. If the key for `self` is deleted, then
133    /// this returns the cursor for the key value pair just larger than the deleted key.
134    pub fn next<'a, 'b, S: NodeStore<K = K>>(&'a self, tree: &'b BPlusTree<S>) -> Option<Self> {
135        self.next_with_value(tree).map(|x| x.0)
136    }
137
138    /// Get the `Cursor` points to the next key-value pair, also with a reference to the value.
139    pub fn next_with_value<'a, 'b, S: NodeStore<K = K>>(
140        &'a self,
141        tree: &'b BPlusTree<S>,
142    ) -> Option<(Self, &'b S::V)>
143    where
144        'k: 'b,
145    {
146        let (leaf_id, leaf) = self.locate_leaf(tree)?;
147
148        let next_offset = match leaf.try_data_at(self.offset_hint) {
149            Some(kv) if kv.0.eq(&self.k) => self.offset_hint + 1,
150            _ => {
151                let (offset, value) = leaf.locate_slot_with_value(&self.k);
152                match value {
153                    Some(_) => offset + 1,
154                    None => offset,
155                }
156            }
157        };
158
159        if next_offset < leaf.len() {
160            let kv = leaf.data_at(next_offset);
161            Some((
162                Self {
163                    k: kv.0.clone(),
164                    leaf_id_hint: leaf_id,
165                    offset_hint: next_offset,
166                },
167                &kv.1,
168            ))
169        } else {
170            let leaf_id = leaf.next()?;
171            let leaf = tree.node_store.get_leaf(leaf_id);
172            let kv = leaf.data_at(0);
173
174            Some((
175                Self {
176                    k: kv.0.clone(),
177                    leaf_id_hint: leaf_id,
178                    offset_hint: 0,
179                },
180                &kv.1,
181            ))
182        }
183    }
184
185    /// whether current cursor is still valid
186    pub fn exists<'a, 'b, S: NodeStore<K = K>>(&'a self, tree: &'b BPlusTree<S>) -> bool {
187        self.value(tree).is_some()
188    }
189
190    /// get the value attached to cursor, if the underlying key is deleted, this returns None
191    pub fn value<'a, 'b, S: NodeStore<K = K>>(&'a self, tree: &'b BPlusTree<S>) -> Option<&'b S::V>
192    where
193        'k: 'b,
194    {
195        let (_, leaf) = self.locate_leaf(tree)?;
196
197        match leaf.try_data_at(self.offset_hint) {
198            Some(kv) if kv.0.eq(&self.k) => Some(&kv.1),
199            _ => {
200                // todo: consider update self?
201                let (_, value) = leaf.locate_slot_with_value(&self.k);
202                value
203            }
204        }
205    }
206
207    #[inline]
208    fn locate_leaf<'a, 'b, S: NodeStore<K = K>>(
209        &'a self,
210        tree: &'b BPlusTree<S>,
211    ) -> Option<(LeafNodeId, &'b LeafNode<S::K, S::V>)> {
212        let leaf_id = self.leaf_id_hint;
213        if let Some(leaf) = tree.node_store.try_get_leaf(leaf_id) {
214            if leaf.in_range(&self.k) {
215                return Some((leaf_id, leaf));
216            }
217        }
218
219        // no hint or hint outdated, need to do a search by key
220        let leaf_id = tree.locate_leaf(&self.k)?;
221
222        Some((leaf_id, tree.node_store.get_leaf(leaf_id)))
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229    use crate::{tree::tests, *};
230    use rand::seq::SliceRandom;
231    use std::collections::BTreeSet;
232
233    #[test]
234    fn test_cursor_next() {
235        let (mut tree, mut keys) = tests::create_test_tree::<2000>();
236        let mut expected_count = keys.len();
237
238        keys.shuffle(&mut rand::thread_rng());
239
240        tree.node_store.debug();
241
242        let mut keys = keys.into_iter();
243
244        let (mut cursor_0, v_0) = Cursor::first(&tree).unwrap();
245
246        let (cursor_1, _) = Cursor::first(&tree).unwrap();
247
248        assert_eq!(cursor_0.k, 0);
249
250        let mut value = vec![v_0.clone()];
251        let mut keys_deleted = BTreeSet::new();
252        while let Some((c, v)) = cursor_0.next_with_value(&tree) {
253            println!("\n-------------------");
254            println!("cursor {:?}", c);
255            tree.node_store.debug();
256            assert!(!keys_deleted.contains(&c.k));
257
258            assert_eq!(c.value(&tree).unwrap(), v);
259            value.push(v.clone());
260
261            cursor_0 = c;
262
263            // asserting that existing cursor's query also works
264            if keys_deleted.contains(&cursor_1.k) {
265                assert!(cursor_1.value(&tree).is_none());
266            } else {
267                assert!(cursor_1.value(&tree).is_some());
268            }
269
270            // just delete the key just passed, it should not affect the cursor
271            let k = keys.next().unwrap();
272            keys_deleted.insert(k);
273            tree.remove(&k);
274            if cursor_0.k < k {
275                expected_count -= 1;
276            }
277        }
278
279        assert_eq!(value.len(), expected_count);
280        // cursor_1 still valid
281        assert_eq!(cursor_1.k, 0);
282    }
283
284    #[test]
285    fn test_cursor_prev() {
286        let (mut tree, mut keys) = tests::create_test_tree::<500>();
287        let mut expected_count = keys.len();
288
289        keys.shuffle(&mut rand::thread_rng());
290        // println!("{keys:?}");
291
292        let mut keys = keys.into_iter();
293
294        let mut values: Vec<i64> = vec![];
295        let (mut cursor, _v) = Cursor::last(&tree).unwrap();
296        values.push(cursor.k);
297
298        while let Some((c, _v)) = cursor.prev_with_value(&tree) {
299            values.push(c.k);
300            cursor = c;
301            let key = keys.next().unwrap();
302
303            tree.remove(&key);
304            if key < cursor.k {
305                expected_count -= 1;
306            }
307        }
308
309        assert_eq!(values.len(), expected_count);
310    }
311}