sanakirja_core/btree/
cursor.rs

1use super::*;
2use crate::{CowPage, LoadPage};
3use core::mem::MaybeUninit;
4
5#[derive(Debug)]
6pub(super) struct PageCursor<K: ?Sized, V: ?Sized, P: BTreePage<K, V>> {
7    pub page: CowPage,
8    pub cursor: P::Cursor,
9}
10
11// This is 1 + the maximal depth of a tree.
12//
13// Since pages are of size 2^12, there are at most 2^52 addressable
14// pages (potentially less depending on the platform). Since each page
15// of a B tree below the root has at least 2 elements (because each
16// page is at least half-full, and elements are at most 1/4th of a
17// page), the arity is at least 3, except for the root. Since 3^33 is
18// the smallest power of 3 larger than 2^52, the maximum depth is 33.
19pub(crate) const N_CURSORS: usize = 33;
20
21#[derive(Debug)]
22/// A position in a B tree.
23pub struct Cursor<K: ?Sized, V: ?Sized, P: BTreePage<K, V>> {
24    /// Invariant: the first `len` items are initialised.
25    stack: [core::mem::MaybeUninit<PageCursor<K, V, P>>; N_CURSORS],
26    /// The length of the stack at the position of the first page
27    /// shared with another tree. This definition is a little bit
28    /// convoluted, but allows for efficient comparisons between
29    /// `first_rc_len` and `len` to check whether a page is shared
30    /// with another tree.
31    first_rc_len: usize,
32    /// Number of initialised items on the stack.
33    len: usize,
34}
35
36impl<K: ?Sized + Storable, V: ?Sized + Storable, P: BTreePage<K, V>> Cursor<K, V, P> {
37    /// Create a new cursor, initialised to the first entry of the B tree.
38    pub fn new<T: LoadPage>(txn: &T, db: &Db_<K, V, P>) -> Result<Self, T::Error> {
39        // Looking forward to getting array initialisation stabilised :)
40        let mut stack = [
41            core::mem::MaybeUninit::uninit(),
42            core::mem::MaybeUninit::uninit(),
43            core::mem::MaybeUninit::uninit(),
44            core::mem::MaybeUninit::uninit(),
45            core::mem::MaybeUninit::uninit(),
46            core::mem::MaybeUninit::uninit(),
47            core::mem::MaybeUninit::uninit(),
48            core::mem::MaybeUninit::uninit(),
49            core::mem::MaybeUninit::uninit(),
50            core::mem::MaybeUninit::uninit(),
51            core::mem::MaybeUninit::uninit(),
52            core::mem::MaybeUninit::uninit(),
53            core::mem::MaybeUninit::uninit(),
54            core::mem::MaybeUninit::uninit(),
55            core::mem::MaybeUninit::uninit(),
56            core::mem::MaybeUninit::uninit(),
57            core::mem::MaybeUninit::uninit(),
58            core::mem::MaybeUninit::uninit(),
59            core::mem::MaybeUninit::uninit(),
60            core::mem::MaybeUninit::uninit(),
61            core::mem::MaybeUninit::uninit(),
62            core::mem::MaybeUninit::uninit(),
63            core::mem::MaybeUninit::uninit(),
64            core::mem::MaybeUninit::uninit(),
65            core::mem::MaybeUninit::uninit(),
66            core::mem::MaybeUninit::uninit(),
67            core::mem::MaybeUninit::uninit(),
68            core::mem::MaybeUninit::uninit(),
69            core::mem::MaybeUninit::uninit(),
70            core::mem::MaybeUninit::uninit(),
71            core::mem::MaybeUninit::uninit(),
72            core::mem::MaybeUninit::uninit(),
73            core::mem::MaybeUninit::uninit(),
74        ];
75        let page = unsafe { txn.load_page(db.db.into())? };
76        if page.offset == 0 {
77            return Ok(Cursor {
78                stack,
79                first_rc_len: N_CURSORS,
80                len: 0,
81            });
82        }
83        stack[0] = MaybeUninit::new(PageCursor {
84            cursor: P::cursor_before(&page),
85            page,
86        });
87        Ok(Cursor {
88            stack,
89            first_rc_len: N_CURSORS,
90            len: 1,
91        })
92    }
93
94    pub(super) fn push(&mut self, p: PageCursor<K, V, P>) {
95        self.stack[self.len] = MaybeUninit::new(p);
96        self.len += 1;
97    }
98
99    pub(super) fn cur(&self) -> &PageCursor<K, V, P> {
100        assert!(self.len > 0);
101        unsafe { &*self.stack[self.len - 1].as_ptr() }
102    }
103
104    pub(super) fn len(&self) -> usize {
105        self.len
106    }
107
108    pub(super) fn first_rc_len(&self) -> usize {
109        self.first_rc_len
110    }
111
112    pub(super) fn pop(&mut self) -> Option<PageCursor<K, V, P>> {
113        if self.len > 0 {
114            self.len -= 1;
115            let result = core::mem::replace(&mut self.stack[self.len], MaybeUninit::uninit());
116            Some(unsafe { result.assume_init() })
117        } else {
118            None
119        }
120    }
121
122    pub(super) fn current_mut(&mut self) -> &mut PageCursor<K, V, P> {
123        assert!(self.len > 0);
124        unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() }
125    }
126
127    /// Push the leftmost path starting at page `left_page` onto the
128    /// stack.
129    pub(super) fn set_first_leaf<T: LoadPage>(
130        &mut self,
131        txn: &T,
132        mut left_page: u64,
133    ) -> Result<(), T::Error> {
134        while left_page > 0 {
135            if self.first_rc_len >= N_CURSORS && txn.rc(left_page)? >= 2 {
136                self.first_rc_len = self.len + 1
137            }
138            let page = unsafe { txn.load_page(left_page)? };
139            if page.offset == 0 {
140                break;
141            }
142            let curs = P::cursor_first(&page);
143            left_page = P::left_child(page.as_page(), &curs);
144            self.push(PageCursor { page, cursor: curs });
145        }
146        Ok(())
147    }
148
149    /// Reset the cursor to the first element of the database.
150    pub fn reset<'a, T: LoadPage>(&mut self) {
151        self.len = 1;
152        let init = unsafe { &mut *self.stack[0].as_mut_ptr() };
153        init.cursor = P::cursor_before(&init.page);
154    }
155
156    // An invariant of cursors, fundamental to understanding the
157    // `next` and `prev` functions below, is that the lower levels (in
158    // the tree, upper levels on the stack) are the left children of
159    // the cursor's position on a page.
160
161    /// Set the cursor to the first position larger than or equal to
162    /// the specified key and value.
163    pub fn set<'a, T: LoadPage>(
164        &mut self,
165        txn: &'a T,
166        k: &K,
167        v: Option<&V>,
168    ) -> Result<Option<(&'a K, &'a V)>, T::Error> {
169        // Set the "cursor stack" by setting a cursor in each page
170        // on a path from the root to the appropriate leaf.
171
172        // Start from the bottom of the stack, which is also the root
173        // of the tree.
174        self.len = 1;
175        self.first_rc_len = N_CURSORS;
176        let init = unsafe { &mut *self.stack[0].as_mut_ptr() };
177        init.cursor = P::cursor_before(&init.page);
178
179        let mut last_matching_page = N_CURSORS;
180        let mut last_match = None;
181        while self.len < N_CURSORS {
182            let current = unsafe { &mut *self.stack.get_unchecked_mut(self.len - 1).as_mut_ptr() };
183            if self.first_rc_len >= N_CURSORS && txn.rc(current.page.offset)? >= 2 {
184                self.first_rc_len = self.len
185            }
186            let ref mut cursor = current.cursor;
187            if let Ok((kk, vv, _)) = P::set_cursor(txn, current.page.as_page(), cursor, k, v) {
188                if v.is_some() {
189                    return Ok(Some((kk, vv)));
190                }
191                last_match = Some((kk, vv));
192                last_matching_page = self.len
193            }
194            let next_page = P::left_child(current.page.as_page(), cursor);
195            if next_page > 0 {
196                let page = unsafe { txn.load_page(next_page)? };
197                if page.offset == 0 {
198                    break;
199                }
200                self.push(PageCursor {
201                    cursor: P::cursor_before(&page),
202                    page,
203                });
204            } else {
205                break;
206            }
207        }
208        if last_matching_page < N_CURSORS {
209            self.len = last_matching_page;
210            Ok(last_match)
211        } else {
212            Ok(None)
213        }
214    }
215
216    /// Set the cursor after the last element, so that [`Self::next`]
217    /// returns `None`, and [`Self::prev`] returns the last element.
218    pub fn set_last<'a, T: LoadPage>(&mut self, txn: &'a T) -> Result<(), T::Error> {
219        self.len = 1;
220        self.first_rc_len = N_CURSORS;
221        let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
222        current.cursor = P::cursor_after(&current.page);
223        loop {
224            let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
225            if self.first_rc_len >= N_CURSORS && txn.rc(current.page.offset)? >= 2 {
226                self.first_rc_len = self.len
227            }
228            let l = P::left_child(current.page.as_page(), &current.cursor);
229            if l > 0 {
230                let page = unsafe { txn.load_page(l)? };
231                if page.offset == 0 {
232                    break;
233                }
234                self.push(PageCursor {
235                    cursor: P::cursor_after(&page),
236                    page,
237                })
238            } else {
239                break;
240            }
241        }
242        Ok(())
243    }
244
245    /// Return the current position of the cursor.
246    pub fn current<'a, T: LoadPage>(
247        &mut self,
248        txn: &'a T,
249    ) -> Result<Option<(&'a K, &'a V)>, T::Error> {
250        loop {
251            let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
252            if P::is_init(&current.cursor) {
253                // The cursor hasn't been set.
254                return Ok(None);
255            } else if let Some((k, v, _)) = P::current(txn, current.page.as_page(), &current.cursor)
256            {
257                unsafe {
258                    return Ok(Some((core::mem::transmute(k), core::mem::transmute(v))));
259                }
260            } else if self.len > 1 {
261                self.len -= 1
262            } else {
263                // We're past the last element at the root.
264                return Ok(None);
265            }
266        }
267    }
268
269    /// Return the current position of the cursor, and move the cursor
270    /// to the next position.
271    pub fn next<'a, T: LoadPage>(
272        &mut self,
273        txn: &'a T,
274    ) -> Result<Option<(&'a K, &'a V)>, T::Error> {
275        loop {
276            let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
277            if P::is_empty(&current.cursor) {
278                if self.len > 1 {
279                    if self.first_rc_len == self.len {
280                        self.first_rc_len = N_CURSORS
281                    }
282                    self.len -= 1
283                } else {
284                    return Ok(None);
285                }
286            } else {
287                let (cur_entry, r) = if let Some((k, v, r)) =
288                    P::current(txn, current.page.as_page(), &current.cursor)
289                {
290                    (Some((k, v)), r)
291                } else {
292                    (
293                        None,
294                        P::right_child(current.page.as_page(), &current.cursor),
295                    )
296                };
297                P::move_next(&mut current.cursor);
298                if r != 0 {
299                    let page = unsafe { txn.load_page(r)? };
300                    if page.offset == 0 {
301                        return Ok(None);
302                    }
303                    self.push(PageCursor {
304                        cursor: P::cursor_before(&page),
305                        page,
306                    });
307                    if self.first_rc_len >= N_CURSORS && txn.rc(r)? >= 2 {
308                        self.first_rc_len = self.len
309                    }
310                }
311                if let Some((k, v)) = cur_entry {
312                    unsafe {
313                        return Ok(Some((core::mem::transmute(k), core::mem::transmute(v))));
314                    }
315                }
316            }
317        }
318    }
319
320    /// Move the cursor to the previous entry, and return the entry
321    /// that was current before the move. If the cursor is initially
322    /// after all the entries, this moves it back by two steps.
323    pub fn prev<'a, T: LoadPage>(
324        &mut self,
325        txn: &'a T,
326    ) -> Result<Option<(&'a K, &'a V)>, T::Error> {
327        loop {
328            let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
329
330            if P::is_init(&current.cursor) {
331                if self.len > 1 {
332                    if self.first_rc_len == self.len {
333                        self.first_rc_len = N_CURSORS
334                    }
335                    self.len -= 1;
336                    let current = unsafe { &mut *self.stack[self.len - 1].as_mut_ptr() };
337                    P::move_prev(&mut current.cursor);
338                } else {
339                    return Ok(None);
340                }
341            } else {
342                let cur_entry = P::current(txn, current.page.as_page(), &current.cursor);
343                let left = P::left_child(current.page.as_page(), &current.cursor);
344                if left != 0 {
345                    let page = unsafe { txn.load_page(left)? };
346                    if page.offset == 0 {
347                        return Ok(None);
348                    }
349                    self.push(PageCursor {
350                        cursor: P::cursor_after(&page),
351                        page,
352                    });
353                    if self.first_rc_len >= N_CURSORS && txn.rc(left)? >= 2 {
354                        self.first_rc_len = self.len
355                    }
356                } else {
357                    // We are at a leaf.
358                    P::move_prev(&mut current.cursor);
359                }
360                if let Some((k, v, _)) = cur_entry {
361                    unsafe {
362                        return Ok(Some((core::mem::transmute(k), core::mem::transmute(v))));
363                    }
364                }
365            }
366        }
367    }
368}
369
370pub struct Iter<'a, T: LoadPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>> {
371    txn: &'a T,
372    cursor: Cursor<K, V, P>,
373}
374
375pub fn iter<'a, T, K, V, P>(
376    txn: &'a T,
377    db: &super::Db_<K, V, P>,
378    origin: Option<(&K, Option<&V>)>,
379) -> Result<Iter<'a, T, K, V, P>, T::Error>
380where
381    T: LoadPage,
382    K: Storable + ?Sized,
383    V: Storable + ?Sized,
384    P: BTreePage<K, V>,
385{
386    let mut cursor = Cursor::new(txn, db)?;
387    if let Some((k, v)) = origin {
388        cursor.set(txn, k, v)?;
389    }
390    Ok(Iter { cursor, txn })
391}
392
393impl<
394        'a,
395        T: LoadPage,
396        K: Storable + ?Sized + 'a,
397        V: Storable + ?Sized + 'a,
398        P: BTreePage<K, V> + 'a,
399    > Iterator for Iter<'a, T, K, V, P>
400{
401    type Item = Result<(&'a K, &'a V), T::Error>;
402    fn next(&mut self) -> Option<Self::Item> {
403        self.cursor.next(self.txn).transpose()
404    }
405}
406
407pub struct RevIter<'a, T: LoadPage, K: Storable + ?Sized, V: Storable + ?Sized, P: BTreePage<K, V>>
408{
409    txn: &'a T,
410    cursor: Cursor<K, V, P>,
411}
412
413pub fn rev_iter<'a, T, K, V, P>(
414    txn: &'a T,
415    db: &super::Db_<K, V, P>,
416    origin: Option<(&K, Option<&V>)>,
417) -> Result<RevIter<'a, T, K, V, P>, T::Error>
418where
419    T: LoadPage,
420    K: Storable + ?Sized,
421    V: Storable + ?Sized,
422    P: BTreePage<K, V>,
423{
424    let mut cursor = Cursor::new(txn, db)?;
425    if let Some((k, v)) = origin {
426        cursor.set(txn, k, v)?;
427    } else {
428        cursor.set_last(txn)?;
429    }
430    Ok(RevIter { cursor, txn })
431}
432
433impl<
434        'a,
435        T: LoadPage,
436        K: Storable + ?Sized + 'a,
437        V: Storable + ?Sized + 'a,
438        P: BTreePage<K, V> + 'a,
439    > Iterator for RevIter<'a, T, K, V, P>
440{
441    type Item = Result<(&'a K, &'a V), T::Error>;
442    fn next(&mut self) -> Option<Self::Item> {
443        self.cursor.prev(self.txn).transpose()
444    }
445}