merkle_search_tree/
page.rs

1use std::{cmp::Ordering, hash::Hasher, ops::DerefMut};
2
3use siphasher::sip128::{Hasher128, SipHasher24};
4
5use crate::{
6    digest::{Digest, PageDigest, ValueDigest},
7    node::Node,
8    visitor::Visitor,
9};
10
11#[derive(Debug)]
12pub(crate) enum UpsertResult<K> {
13    /// The key & value hash were successfully upserted.
14    Complete,
15
16    /// An intermediate page must be inserted between the caller and the callee.
17    InsertIntermediate(K),
18}
19
20/// A group of [`Node`] instances at the same location within the tree.
21///
22/// A page within an MST is a probabilistically sized structure, with varying
23/// numbers of [`Node`] within. A page has a min/max key range defined by the
24/// nodes within it, and the page hash acts as a content hash, describing the
25/// state of the page and the nodes within it.
26#[derive(Debug, PartialEq, Eq, Clone)]
27pub struct Page<const N: usize, K> {
28    level: u8,
29
30    /// The cached hash in this page; the cumulation of the hashes of the
31    /// sub-tree rooted at this page.
32    tree_hash: Option<PageDigest>,
33
34    /// A vector of nodes in this page, ordered min to max by key.
35    nodes: Vec<Node<N, K>>,
36
37    /// The page for keys greater-than all keys in nodes.
38    high_page: Option<Box<Page<N, K>>>,
39}
40
41impl<const N: usize, K> Page<N, K> {
42    pub(super) const fn new(level: u8, nodes: Vec<Node<N, K>>) -> Self {
43        Self {
44            level,
45            tree_hash: None,
46            nodes,
47            high_page: None,
48        }
49    }
50
51    /// Returns the the [`Node`] in this page.
52    pub fn nodes(&self) -> &[Node<N, K>] {
53        &self.nodes
54    }
55
56    /// Returns the tree level / deterministic / logical hight of this page in
57    /// the tree.
58    pub const fn level(&self) -> u8 {
59        self.level
60    }
61
62    /// Return the cached hash of this page if any, covering the nodes and the
63    /// sub-tree rooted at `self`.
64    pub fn hash(&self) -> Option<&PageDigest> {
65        self.tree_hash.as_ref()
66    }
67
68    /// Set the high page pointer for this page.
69    ///
70    /// # Panics
71    ///
72    /// Panics if this page already has a high page linked, or `p` contains no
73    /// nodes.
74    pub(crate) fn insert_high_page(&mut self, p: Box<Self>) {
75        debug_assert!(self.high_page.is_none());
76        debug_assert!(!p.nodes().is_empty());
77
78        // Invalidate the hash of this page.
79        self.tree_hash = None;
80        self.high_page = Some(p)
81    }
82
83    /// Return a pointer to the linked high page, if any.
84    pub(crate) fn high_page(&self) -> Option<&Self> {
85        self.high_page.as_deref()
86    }
87
88    /// Perform a depth-first, in-order traversal, yielding each [`Page`] and
89    /// [`Node`] to `visitor`.
90    ///
91    /// If `high_page` is true, this page was linked to from the parent via a
92    /// high page pointer.
93    pub(crate) fn in_order_traversal<'a, T>(&'a self, visitor: &mut T, high_page: bool) -> bool
94    where
95        T: Visitor<'a, N, K>,
96    {
97        if !visitor.visit_page(self, high_page) {
98            return false;
99        }
100
101        for node in &self.nodes {
102            if !node.depth_first(visitor) {
103                return false;
104            }
105        }
106
107        if !visitor.post_visit_page(self) {
108            return false;
109        }
110
111        if let Some(h) = &self.high_page {
112            if !h.in_order_traversal(visitor, true) {
113                return false;
114            }
115        }
116
117        true
118    }
119
120    /// Return the minimum key stored in this page.
121    ///
122    /// This is an `O(1)` operation.
123    ///
124    /// # Panics
125    ///
126    /// Panics if there are no nodes in this page.
127    #[inline]
128    pub(crate) fn min_key(&self) -> &K {
129        self.nodes.first().unwrap().key()
130    }
131
132    /// Return the maximum key stored in this page.
133    ///
134    /// This is an `O(1)` operation.
135    ///
136    /// # Panics
137    ///
138    /// Panics if there are no nodes in this page.
139    #[inline]
140    pub(crate) fn max_key(&self) -> &K {
141        self.nodes.last().unwrap().key()
142    }
143
144    /// Descend down the minimum (left most) path (if any) and return the
145    /// minimum key in the subtree rooted at `p`.
146    ///
147    /// This is an `O(logN)` operation.
148    #[inline]
149    pub(crate) fn min_subtree_key(&self) -> &K {
150        // This is mildly faster than the iterator chain approach.
151        let v = self.nodes().first().and_then(|v| v.lt_pointer());
152        if let Some(v) = v {
153            return v.min_subtree_key();
154        }
155
156        self.min_key()
157    }
158
159    /// Chase the high page pointers to the maximum page value of the subtree
160    /// rooted at `p`.
161    ///
162    /// This is an `O(logN)` operation.
163    #[inline]
164    pub(crate) fn max_subtree_key(&self) -> &K {
165        self.high_page()
166            .map(|v| v.max_subtree_key())
167            .unwrap_or_else(|| self.max_key())
168    }
169}
170
171impl<const N: usize, K> Page<N, K>
172where
173    K: AsRef<[u8]>,
174{
175    /// Generate the page hash and cache the value, covering the nodes and the
176    /// sub-tree rooted at `self`.
177    pub(crate) fn maybe_generate_hash(&mut self, hasher: &SipHasher24) {
178        if self.tree_hash.is_some() {
179            return;
180        }
181
182        let mut h = *hasher;
183
184        // NOTE: changing the ordering of the hashed elements is a breaking
185        // change.
186        //
187        // This order may be changed only if releasing a new major version, as
188        // it invalidates existing hashes.
189
190        // Hash all nodes & their child pages
191        for n in &mut self.nodes {
192            // Hash the lt child page of this node, if any
193            if let Some(child_hash) = n.lt_pointer_mut().as_deref_mut().map(|v| {
194                v.maybe_generate_hash(hasher);
195                v.hash().unwrap()
196            }) {
197                h.write(child_hash.as_ref());
198            }
199
200            // Hash the node value itself
201            h.write(n.key().as_ref());
202            h.write(n.value_hash().as_ref());
203        }
204
205        // Hash the high page, if any
206        if let Some(high_hash) = self.high_page.as_deref_mut().map(|v| {
207            v.maybe_generate_hash(hasher);
208            v.hash().unwrap()
209        }) {
210            h.write(high_hash.as_ref());
211        }
212
213        self.tree_hash = Some(PageDigest::from(Digest::new(h.finish128().as_bytes())));
214    }
215}
216
217impl<const N: usize, K> Page<N, K>
218where
219    K: PartialOrd,
220{
221    /// Insert or update the value hash of `key`, setting it to `value`, found
222    /// at tree `level`.
223    ///
224    /// Returns true if the key was found, or false otherwise.
225    ///
226    /// If the key is found/modified, the cached page hash is invalidated.
227    pub(crate) fn upsert(&mut self, key: K, level: u8, value: ValueDigest<N>) -> UpsertResult<K> {
228        match level.cmp(&self.level) {
229            // Level is less than this page's level - descend down the tree.
230            Ordering::Less => {
231                // A non-zero page can never be empty, and level is less than
232                // this page, which means this page must be non-zero.
233                debug_assert_ne!(!self.level, 0);
234                debug_assert!(!self.nodes.is_empty());
235
236                // Find the node that is greater-than-or-equal-to key to descend
237                // into.
238                //
239                // Otherwise insert this node into the high page.
240                let ptr = find_idx(&self.nodes, &key);
241
242                let page = match self.nodes.get_mut(ptr) {
243                    Some(v) => {
244                        debug_assert!(*v.key() > key);
245                        v.lt_pointer_mut()
246                    }
247                    None => &mut self.high_page,
248                };
249
250                let page = page.get_or_insert_with(|| Box::new(Self::new(level, vec![])));
251                if let UpsertResult::InsertIntermediate(key) =
252                    page.upsert(key, level, value.clone())
253                {
254                    insert_intermediate_page(page, key, level, value);
255                }
256            }
257            Ordering::Equal => self.upsert_node(key, value),
258            // Level is more than this page's level
259            Ordering::Greater => {
260                // This level is lower than the desired level, the parent is
261                // higher than the desired level.
262                //
263                // Returning false will case the parent will insert a new page.
264                return UpsertResult::InsertIntermediate(key); // No need to
265                                                              // update the hash
266                                                              // of this subtree
267            }
268        }
269
270        // This page, or one below it was modified. Invalidate the pre-computed
271        // page hash, if any.
272        //
273        // This marks the page as "dirty" causing the hash to be recomputed on
274        // demand, coalescing multiple updates instead of hashing for each.
275        self.tree_hash = None;
276
277        UpsertResult::Complete
278    }
279
280    /// Insert a node into this page, splitting any child pages as necessary.
281    pub(crate) fn upsert_node(&mut self, key: K, value: ValueDigest<N>) {
282        // Find the appropriate child pointer to follow.
283        let idx = find_idx(&self.nodes, &key);
284
285        // At this point the new key should be inserted has been identified -
286        // node_idx points to the first node greater-than-or-equal to key.
287        //
288        // In this example, we're inserting the key "C":
289        //
290        //                                      node_idx
291        //                                          ║
292        //                                          ║
293        //                                          ▼
294        //                         ┌──────────┬──────────┐
295        //                         │ LT Node  │ GTE Node │
296        //                         │    A     │    E     │
297        //                         └──────────┴──────────┘
298        //                               │          │
299        //                        ┌──────┘          │
300        //                        ▼                 ▼
301        //                  ┌─Page──────┐     ┌─Page──────┐
302        //                  │           │     │ ┌───┬───┐ │
303        //                  │ Always LT │     │ │ B │ D │ │
304        //                  │  new key  │     │ └───┴───┘ │
305        //                  └───────────┘     └───────────┘
306        //
307        // The less-than node never needs splitting, because all the keys within
308        // it are strictly less than the insert key.
309        //
310        // The GTE child page does need splitting - all the keys less than "C"
311        // need moving into the new node's less-than page.
312        //
313        // If the new "C" node will be inserted at the end of the node array,
314        // there's no GTE node to check - instead the high page may contain
315        // relevant nodes that must be split.
316
317        let page_to_split = match self.nodes.get_mut(idx) {
318            Some(n) if *n.key() == key => {
319                n.update_value_hash(value);
320                return;
321            }
322            Some(n) => n.lt_pointer_mut(),
323            None => &mut self.high_page,
324        };
325
326        // Split the higher-page, either within a GTE node or the high page.
327        let mut new_lt_page = split_off_lt(page_to_split, &key).map(Box::new);
328
329        if let Some(lt_page) = &mut new_lt_page {
330            debug_assert!(self.level > lt_page.level);
331            debug_assert!(!lt_page.nodes.is_empty());
332            debug_assert!(*lt_page.max_key() < key);
333
334            let high_page_lt = split_off_lt(&mut lt_page.high_page, &key);
335            let gte_page = std::mem::replace(&mut lt_page.high_page, high_page_lt.map(Box::new));
336            if let Some(gte_page) = gte_page {
337                debug_assert!(self.level > gte_page.level);
338                debug_assert!(!gte_page.nodes.is_empty());
339                debug_assert!(*gte_page.max_key() > key);
340
341                self.insert_high_page(gte_page);
342            }
343        }
344
345        self.nodes.insert(idx, Node::new(key, value, new_lt_page));
346    }
347}
348
349/// Split `page`, mutating it such that it contains only nodes with keys ordered
350/// strictly-less than `key`, returning a new [`Page`] containing the
351/// greater-than-or-equal-to nodes.
352///
353/// If splitting `page` would leave it with no nodes, it is set to [`None`].
354///
355/// NOTE: this only splits the page provided - it is up to the caller to split
356/// any high pages as necessary.
357///
358/// # Panics
359///
360/// This method panics if attempting to split a non-empty page (root pages are
361/// never split).
362fn split_off_lt<const N: usize, T, K>(page: &mut Option<T>, key: &K) -> Option<Page<N, K>>
363where
364    K: PartialOrd,
365    T: DerefMut<Target = Page<N, K>>,
366{
367    let page_ref = page.as_deref_mut()?;
368    debug_assert!(!page_ref.nodes.is_empty());
369
370    // A page should be split into two parts - one page containing the elements
371    // less-than "key", and one containing parts greater-or-equal to "key".
372    let partition_idx = find_idx(&page_ref.nodes, key);
373
374    // All the nodes are greater-than-or-equal-to "key" - there's no less-than
375    // nodes to return.
376    if partition_idx == 0 {
377        debug_assert!(page_ref.min_key() > key);
378
379        // The first gte node may have a lt_pointer with nodes that are lt key.
380        return match split_off_lt(page_ref.nodes[0].lt_pointer_mut(), key) {
381            Some(v) => {
382                // Invalidate the page hash as the lt_page was split or the keys
383                // moved, changing the content the hash covers.
384                page_ref.tree_hash = None;
385                Some(v)
386            }
387            None => None,
388        };
389    }
390
391    // All the nodes are less than key.
392    //
393    // As an optimisation, simply return the existing page as the new page
394    // (retaining the pre-computed hash if possible) and invalidate the old
395    // page.
396    if partition_idx == page_ref.nodes.len() {
397        debug_assert!(page_ref.max_key() < key);
398
399        // The page may have a high page, which may have nodes within the
400        // (max(nodes.key), key) range
401        let lt_high_nodes = split_off_lt(&mut page_ref.high_page, key);
402
403        // If existing the high page was split (both sides are non-empty) then
404        // invalidate the page hash.
405        //
406        // This effectively invalidates the page range of the returned lt_page
407        // as the cached hash covers the high page (which has now been split,
408        // changing the content).
409        if lt_high_nodes.is_some() && page_ref.high_page.is_some() {
410            page_ref.tree_hash = None;
411        }
412
413        // Put the lt nodes back into the high page, taking the gte nodes from
414        // the high page.
415        //
416        // This leaves the lt_high_nodes in the high page link of page_ref.
417        let gte_high_page = std::mem::replace(&mut page_ref.high_page, lt_high_nodes.map(Box::new));
418
419        // Initialise the page we're about to return.
420        //
421        // This puts an empty page into page_ref, taking the new lt nodes in
422        // page (potentially with the high page linked to lt_high_nodes)
423        let lt_page = Some(std::mem::replace(
424            page_ref,
425            Page::new(page_ref.level, vec![]),
426        ));
427
428        // Put the gte nodes into the input page, if any (page should contain
429        // all gte nodes after this split).
430        match gte_high_page {
431            Some(p) => *page_ref = *p,
432            None => *page = None,
433        }
434
435        return lt_page;
436    }
437
438    // Invalidate the page hash as at least one node will be removed.
439    page_ref.tree_hash = None;
440
441    // Obtain the set of nodes that are greater-than-or-equal-to "key".
442    let gte_nodes: Vec<_> = page_ref.nodes.drain(partition_idx..).collect();
443    debug_assert!(!gte_nodes.is_empty());
444
445    // page_ref now contains the lt nodes, and a high page that may be non-empty
446    // and gte than key.
447
448    // Initialise a new page to hold the gte nodes.
449    let mut gte_page = Page::new(page_ref.level, gte_nodes);
450    debug_assert!(gte_page.max_key() > key);
451
452    // Move the input high page onto the new gte page (which continues to be gte
453    // than the nodes taken from the input page).
454    if let Some(h) = page_ref.high_page.take() {
455        debug_assert!(!h.nodes.is_empty());
456        debug_assert!(h.level < page_ref.level);
457        debug_assert!(h.min_key() > key);
458        gte_page.insert_high_page(h);
459    }
460
461    // The first gte node may contain a lt_pointer with keys lt key, recurse
462    // into it.
463    let lt_key_high_nodes = split_off_lt(gte_page.nodes.first_mut().unwrap().lt_pointer_mut(), key);
464
465    // In which case it is gte all node keys in the lt page (or it wouldn't have
466    // been on the gte node).
467    //
468    // Add this to the new lt_page's high page next.
469
470    // Replace the input page with the gte nodes, taking the page containing the
471    // lt nodes and returning them to the caller.
472    let mut lt_page = std::mem::replace(page_ref, gte_page);
473    debug_assert!(!lt_page.nodes.is_empty());
474    debug_assert!(lt_page.max_key() < key);
475
476    // Insert the high page, if any.
477    if let Some(h) = lt_key_high_nodes {
478        debug_assert!(h.level < page_ref.level);
479        debug_assert!(h.max_key() < key);
480        debug_assert!(!h.nodes.is_empty());
481        lt_page.insert_high_page(Box::new(h));
482    }
483
484    Some(lt_page)
485}
486
487pub(crate) fn insert_intermediate_page<const N: usize, T, K>(
488    child_page: &mut T,
489    key: K,
490    level: u8,
491    value: ValueDigest<N>,
492) where
493    K: PartialOrd,
494    T: DerefMut<Target = Page<N, K>>,
495{
496    // Terminology:
497    //
498    //     * parent_page: top of the stack, parent of child_page
499    //     * intermediate/new page: intermediate page with level between parent_page
500    //       and child_page to be inserted between them.
501    //     * child_page: the lower page, child of parent_page
502    //
503
504    // The child page asked this page to insert a new intermediate page at this
505    // location.
506    //
507    //                        ┌──────────┐
508    //                        │ New Root │
509    //                   ┌────│    B     │─────┐         Level N
510    //                   │    └──────────┘     │
511    //              lt_pointer            high_page
512    //                   │                     │
513    //                   │                     │
514    //          ┌ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
515    //             ┌─────▼────┐          ┌─────▼────┐
516    //          │  │ LT Node  │          │ GTE Node │  Child Page │
517    //             │    A     │          │    C     │     Level 0
518    //          │  └──────────┘          └──────────┘             │
519    //           ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
520    //
521    // The child page must be split into nodes less-than key, and those
522    // greater-than-or-equal to key to preserve the ordering once this new page
523    // containing key is inserted. Both halves must be linked into the new page.
524
525    debug_assert!(child_page.level() < level);
526    debug_assert!(!child_page.nodes.is_empty());
527
528    // Split the child page into (less-than, greater-than) pages, split at the
529    // point where key would reside.
530    //
531    // NOTE: this may leave "page" empty if all the nodes moved to the lt page.
532    let mut lt_page = {
533        let child_page2 = child_page.deref_mut();
534        let mut child_page_ref = Some(&mut *child_page2);
535        split_off_lt(&mut child_page_ref, &key)
536    };
537
538    // If all the nodes moved out of the child_page and into lt_page it
539    // indicates that all nodes had keys less-than the new key, meaning there
540    // may be nodes in the lt_page high page that need splitting, as it may
541    // contain values between max(lt_page.nodes) and key.
542    //
543    // For example, when inserting 4:
544    //
545    //                              ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─
546    //                                ┌───┐ New Parent │
547    //                           ┌──│ │ 4 │    Level 2
548    //                           │    └───┘            │
549    //                           │  └ ─ ─ ─ ─ ─ ─ ─ ─ ─
550    //                           │
551    //                ┌ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
552    //                   ┌───┬───▼───────┐  Child Page │
553    //                │  │ 1 │ 2 │ high  │     Level 1
554    //                   └───┴───┴───────┘             │
555    //                └ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─
556    //                               │
557    //                           ┌ ─ ▼ ─ ─ ─ ─ ─ ─ ─ ─ ┐
558    //                             ┌───┬───┐
559    //                           │ │ 3 │ 5 │   Level 0 │
560    //                             └───┴───┘
561    //                           └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
562    //
563    // The existing entry of 5 must be moved, as it is greater than the new
564    // parent:
565    //
566    //                              ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
567    //                                            New Parent │
568    //                              │ ┌───┬───────┐  Level 2
569    //                            ┌───│ 4 │ high  │───┐      │
570    //                            │ │ └───┴───────┘   │
571    //                            │  ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ┘
572    //                            ▼                   │
573    //           ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─    │
574    //              ┌───┬───┬───────┐  Child Page │   │
575    //           │  │ 1 │ 2 │ high  │     Level 1     │
576    //              └───┴───┴───────┘             │   │
577    //           └ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─    │
578    //                          ▼                     ▼
579    //                  ┌ ─ ─ ─ ─ ─ ─ ─       ┌ ─ ─ ─ ─ ─ ─ ─
580    //                   ┌───┐         │       ┌───┐         │
581    //                  ││ 3 │ Level 0        ││ 5 │ Level 0
582    //                   └───┘         │       └───┘         │
583    //                  └ ─ ─ ─ ─ ─ ─ ─       └ ─ ─ ─ ─ ─ ─ ─
584    //
585    // To do this, we split the high page, attaching the lt_nodes to the lt_page
586    // created above, and attach the remaining gte_nodes to the high_page of the
587    // intermediate_page.
588    let mut gte_page = None;
589    if let Some(lt_page) = &mut lt_page {
590        debug_assert!(level > lt_page.level);
591        debug_assert!(!lt_page.nodes.is_empty());
592        debug_assert!(*lt_page.max_key() < key);
593
594        let high_page_lt = split_off_lt(&mut lt_page.high_page, &key);
595        gte_page = std::mem::replace(&mut lt_page.high_page, high_page_lt.map(Box::new));
596        if let Some(gte_page) = &gte_page {
597            debug_assert!(level > gte_page.level);
598            debug_assert!(!gte_page.nodes.is_empty());
599            debug_assert!(*gte_page.max_key() > key);
600        }
601    }
602
603    // Create the new node.
604    let node = Node::new(key, value, None);
605
606    // Create the new intermediate page, between the parent page and the child
607    // page.
608    let mut intermediate_page = Page::new(level, vec![node]);
609    if let Some(gte_page) = gte_page {
610        intermediate_page.insert_high_page(gte_page);
611    }
612
613    // Replace the page pointer at this level to point to the new page, taking
614    // the page that now contains the lt nodes after the split.
615    let gte_page = std::mem::replace(child_page.deref_mut(), intermediate_page);
616
617    // At this point, we have this structure:
618    //
619    //                         ┌─────────────┐
620    //                         │  This Page  │
621    //                         └─────────────┘
622    //                                │
623    //                                ▼
624    //                      ┌───────────────────┐
625    //                      │ Intermediate Page │
626    //                      └───────────────────┘
627    //
628    // The lt_page and gtw_pages need linking into the new node within the new
629    // intermediate page.
630
631    *child_page.nodes[0].lt_pointer_mut() = lt_page.map(Box::new);
632    if !gte_page.nodes.is_empty() {
633        debug_assert!(gte_page.max_key() > child_page.nodes[0].key()); // "key"
634        debug_assert!(level > gte_page.level);
635        child_page.high_page = Some(Box::new(gte_page));
636    }
637}
638
639/// Return the index into `nodes` at which `key` should be located.
640fn find_idx<const N: usize, K>(nodes: &[Node<N, K>], key: &K) -> usize
641where
642    K: PartialOrd,
643{
644    nodes
645        .iter()
646        .position(|v| *key <= *v.key())
647        .unwrap_or(nodes.len())
648}
649
650#[cfg(test)]
651mod tests {
652    use assert_matches::assert_matches;
653
654    use super::*;
655    use crate::{assert_tree, digest::Digest};
656
657    const MOCK_VALUE: ValueDigest<1> = ValueDigest::new(Digest::new([0; 1]));
658    const MOCK_PAGE_HASH: PageDigest = PageDigest::new([0; 16]);
659
660    #[test]
661    #[should_panic(expected = "!page_ref.nodes.is_empty()")]
662    fn test_split_page_empty() {
663        let mut gte_page = Some(Box::new(Page::<1, _>::new(42, vec![])));
664        let _lt_page = split_off_lt(&mut gte_page, &5);
665    }
666
667    #[test]
668    fn test_split_page_single_node_lt() {
669        let mut gte_page = Some(Box::new(Page::new(
670            42,
671            vec![Node::new(2, MOCK_VALUE, None)],
672        )));
673
674        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
675
676        let lt_page = split_off_lt(&mut gte_page, &5);
677        assert_matches!(gte_page, None);
678
679        assert_matches!(lt_page, Some(p) => {
680            assert_eq!(p.level, 42);
681
682            // The unmodified page has the hash retained.
683            assert_eq!(p.tree_hash, Some(MOCK_PAGE_HASH));
684
685            assert_eq!(p.nodes, [
686                Node::new(2, MOCK_VALUE, None),
687            ]);
688        });
689    }
690
691    #[test]
692    fn test_split_page_single_node_gt() {
693        let mut gte_page = Some(Box::new(Page::new(
694            42,
695            vec![Node::new(2, MOCK_VALUE, None)],
696        )));
697
698        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
699
700        let lt_page = split_off_lt(&mut gte_page, &1);
701        assert_matches!(gte_page, Some(p) => {
702            assert_eq!(p.level, 42);
703
704            // The unmodified page has the hash retained.
705            assert_eq!(p.tree_hash, Some(MOCK_PAGE_HASH));
706
707            assert_eq!(p.nodes, [
708                Node::new(2, MOCK_VALUE, None),
709            ]);
710        });
711
712        assert_matches!(lt_page, None);
713    }
714
715    /// Test that a page containing entirely gte nodes, but with a linked high
716    /// page that requires splitting, has the page has invalidated.
717    #[test]
718    fn test_split_page_single_node_gt_with_high_page_split() {
719        let mut high_page = Box::new(Page::new(
720            40,
721            vec![
722                Node::new(10, MOCK_VALUE, None),
723                Node::new(15, MOCK_VALUE, None),
724            ],
725        ));
726        high_page.tree_hash = Some(MOCK_PAGE_HASH);
727
728        let mut page = Box::new(Page::new(42, vec![Node::new(5, MOCK_VALUE, None)]));
729        page.tree_hash = Some(MOCK_PAGE_HASH);
730        page.insert_high_page(high_page);
731
732        let mut page = Some(page);
733
734        let lt_page = split_off_lt(&mut page, &12);
735        assert_matches!(page, Some(p) => {
736            assert_eq!(p.level, 40);
737
738            // The modified page has the hash invalidated as the high page was
739            // split.
740            assert_eq!(p.tree_hash, None);
741
742            assert_eq!(p.nodes, [
743                Node::new(15, MOCK_VALUE, None),
744            ]);
745            assert_eq!(p.high_page, None);
746        });
747
748        assert_matches!(lt_page, Some(p) => {
749            assert_eq!(p.level, 42);
750            assert_eq!(p.tree_hash, None);
751
752            assert_eq!(p.nodes, [
753                Node::new(5, MOCK_VALUE, None),
754            ]);
755
756            assert_eq!(p.high_page.as_ref().unwrap().nodes, [
757                Node::new(10, MOCK_VALUE, None),
758            ]);
759            assert_eq!(p.high_page.as_ref().unwrap().tree_hash, None);
760        });
761    }
762
763    /// Test that a page containing entirely lt nodes, but with a recursively
764    /// followed child page that requires splitting, has the page has
765    /// invalidated.
766    ///
767    /// Toe ensure page hashes are recursively invalidated, the split child page
768    /// is actually two steps away from the target page.
769    #[test]
770    fn test_split_page_single_node_gt_with_child_page_split() {
771        // The bottom-most/deepest child page that requires splitting.
772        let child_2 = Some(Box::new(Page::new(
773            40,
774            vec![
775                Node::new(1, MOCK_VALUE, None),
776                // Split at 2
777                Node::new(3, MOCK_VALUE, None),
778            ],
779        )));
780        // The parent of child_2
781        let child_1 = Some(Box::new(Page::new(
782            41,
783            vec![Node::new(4, MOCK_VALUE, child_2)],
784        )));
785
786        // The parent of child_1
787        let mut page = Some(Box::new(Page::new(
788            42,
789            vec![Node::new(5, MOCK_VALUE, child_1)],
790        )));
791
792        page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
793
794        let lt_page = split_off_lt(&mut page, &2);
795        assert_matches!(page, Some(p) => {
796            assert_eq!(p.level, 42);
797
798            // The modified page has the hash invalidated as the child page was
799            // split.
800            assert_eq!(p.tree_hash, None);
801
802            assert_eq!(p.nodes, [
803                Node::new(5, MOCK_VALUE, Some(Box::new(Page::new(
804                    41,
805                    vec![Node::new(4, MOCK_VALUE, Some(Box::new(Page::new(
806                        40,
807                        // 1 split away
808                        vec![Node::new(3, MOCK_VALUE, None)],
809                    ))))],
810                )))),
811            ]);
812        });
813
814        assert_matches!(lt_page, Some(p) => {
815            assert_eq!(p.level, 40);
816
817            assert_eq!(p.nodes, [
818                Node::new(1, MOCK_VALUE, None),
819            ]);
820
821            assert_eq!(p.tree_hash, None);
822        });
823    }
824
825    #[test]
826    fn test_split_page_eq() {
827        let mut gte_page = Some(Box::new(Page::new(
828            42,
829            vec![
830                Node::new(1, MOCK_VALUE, None),
831                Node::new(2, MOCK_VALUE, None),
832                Node::new(4, MOCK_VALUE, None),
833            ],
834        )));
835
836        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
837
838        let lt_page = split_off_lt(&mut gte_page, &2);
839        assert_matches!(gte_page, Some(p) => {
840            assert_eq!(p.level, 42);
841            assert_eq!(p.tree_hash, None);
842
843            assert_eq!(p.nodes, [
844                Node::new(2, MOCK_VALUE, None),
845                Node::new(4, MOCK_VALUE, None)
846            ]);
847        });
848
849        assert_matches!(lt_page, Some(p) => {
850            assert_eq!(p.level, 42);
851
852            // The modified page has the hash invalidated.
853            assert_eq!(p.tree_hash, None);
854
855            assert_eq!(p.nodes, [
856                Node::new(1, MOCK_VALUE, None),
857            ]);
858        });
859    }
860
861    #[test]
862    fn test_split_page_lt() {
863        let mut gte_page = Some(Box::new(Page::new(
864            42,
865            vec![
866                Node::new(1, MOCK_VALUE, None),
867                Node::new(2, MOCK_VALUE, None),
868                Node::new(4, MOCK_VALUE, None),
869            ],
870        )));
871
872        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
873
874        let lt_page = split_off_lt(&mut gte_page, &3);
875        assert_matches!(gte_page, Some(p) => {
876            assert_eq!(p.level, 42);
877            assert_eq!(p.tree_hash, None);
878
879            assert_eq!(p.nodes, [
880                Node::new(4, MOCK_VALUE, None)
881            ]);
882        });
883
884        assert_matches!(lt_page, Some(p) => {
885            assert_eq!(p.level, 42);
886
887            // The modified page has the hash invalidated.
888            assert_eq!(p.tree_hash, None);
889
890            assert_eq!(p.nodes, [
891                Node::new(1, MOCK_VALUE, None),
892                Node::new(2, MOCK_VALUE, None),
893            ]);
894        });
895    }
896
897    #[test]
898    fn test_split_page_all_gt() {
899        let mut gte_page = Some(Box::new(Page::new(
900            42,
901            vec![
902                Node::new(1, MOCK_VALUE, None),
903                Node::new(2, MOCK_VALUE, None),
904                Node::new(4, MOCK_VALUE, None),
905            ],
906        )));
907
908        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
909
910        let lt_page = split_off_lt(&mut gte_page, &0);
911        assert_matches!(gte_page, Some(p) => {
912            assert_eq!(p.level, 42);
913
914            // The new page containing all the nodes retains the pre-computed
915            // hash.
916            assert_eq!(p.tree_hash, Some(MOCK_PAGE_HASH));
917
918            assert_eq!(p.nodes, [
919                Node::new(1, MOCK_VALUE, None),
920                Node::new(2, MOCK_VALUE, None),
921                Node::new(4, MOCK_VALUE, None),
922            ]);
923        });
924
925        assert_matches!(lt_page, None);
926    }
927
928    #[test]
929    fn test_split_page_all_lt() {
930        let mut gte_page = Some(Box::new(Page::new(
931            42,
932            vec![
933                Node::new(1, MOCK_VALUE, None),
934                Node::new(2, MOCK_VALUE, None),
935                Node::new(4, MOCK_VALUE, None),
936            ],
937        )));
938
939        gte_page.as_mut().unwrap().tree_hash = Some(MOCK_PAGE_HASH);
940
941        let lt_page = split_off_lt(&mut gte_page, &10);
942        assert_matches!(gte_page, None);
943
944        assert_matches!(lt_page, Some(p) => {
945            assert_eq!(p.level, 42);
946
947            // The unmodified page retains the pre-computed hash.
948            assert_eq!(p.tree_hash, Some(MOCK_PAGE_HASH));
949
950            assert_eq!(p.nodes, [
951                Node::new(1, MOCK_VALUE, None),
952                Node::new(2, MOCK_VALUE, None),
953                Node::new(4, MOCK_VALUE, None),
954            ]);
955        });
956    }
957
958    #[test]
959    fn test_upsert_less_than_split_child() {
960        let mut p = Page::new(1, vec![Node::new(4, MOCK_VALUE, None)]);
961
962        p.upsert(3, 0, MOCK_VALUE);
963        p.upsert(1, 0, MOCK_VALUE);
964        p.upsert(2, 1, MOCK_VALUE);
965
966        assert_tree!(page = p);
967    }
968
969    #[test]
970    fn test_split_page_recursive_lt_pointer() {
971        let mut lt_pointer_page = Page::new(52, vec![Node::new(86, MOCK_VALUE, None)]);
972        lt_pointer_page.tree_hash = Some(MOCK_PAGE_HASH);
973
974        let mut root = Box::new(Page::new(
975            42,
976            vec![Node::new(161, MOCK_VALUE, Some(Box::new(lt_pointer_page)))],
977        ));
978        root.tree_hash = Some(MOCK_PAGE_HASH);
979
980        let key = 160;
981
982        let mut root = Some(root);
983        let lt_page = split_off_lt(&mut root, &key);
984
985        assert_matches!(lt_page, Some(p) => {
986            assert_eq!(p.level, 52);
987            assert_matches!(p.nodes(), [n] if *n.key() == 86)
988        });
989    }
990
991    #[test]
992    fn test_split_page_recursive_high_page() {
993        let mut high_page = Page::new(32, vec![Node::new(44, MOCK_VALUE, None)]);
994        high_page.tree_hash = Some(MOCK_PAGE_HASH);
995
996        let mut root = Box::new(Page::new(42, vec![Node::new(42, MOCK_VALUE, None)]));
997        root.tree_hash = Some(MOCK_PAGE_HASH);
998        root.insert_high_page(Box::new(high_page));
999
1000        let key = 43;
1001
1002        let mut root = Some(root);
1003        let lt_page = split_off_lt(&mut root, &key);
1004
1005        assert_matches!(lt_page, Some(p) => {
1006            assert_eq!(p.level, 42);
1007            assert_matches!(p.nodes(), [n] if *n.key() == 42)
1008        });
1009        assert_matches!(root, Some(p) => {
1010            assert_eq!(p.level, 32);
1011            assert_matches!(p.nodes(), [n] if *n.key() == 44)
1012        });
1013    }
1014}