bbtree 0.1.5

Fastest B-tree.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
//! Reads of a latched tree's nodes while other threads write them: internal
//! nodes always, by optimistic lock coupling, and leaves for lookups and
//! hints (D57; `latch.rs`, `design/09-concurrency.md`).
//!
//! A racing reader takes no latch. It reads the node's version, reads the
//! node in place, and checks the version after. A writer holding the node
//! changes it in place, with the ordinary node code. The reader may
//! meanwhile read half of one change and half of another, which the check
//! then throws away. So a read here:
//!
//! - goes through raw pointers and forms no reference into the node
//!   ([`NodeInlineKeys`] over its slots, edges read from their slots);
//! - reads the node's length once and clamps it to the capacity, so the
//!   search stays in bounds whatever it read (D14);
//! - follows no edge before the node's version vouches for it. The edge then
//!   reaches a page of the kind its tag says. Every page but the root's
//!   keeps its kind while threads share the tree. A node moved or freed
//!   keeps its page's latch word, whose version only grows
//!   (`tree/latched/pages.rs`);
//! - runs no user code on what it read. Where inline keys tie, it compares a
//!   separator's key, a leaf's head (D49), with that leaf latched shared,
//!   once the node's version vouches for the edge it walked down. A head key
//!   changes only while its leaf is latched exclusively, and the key a
//!   removal takes out may be dropped, and its memory freed, right after.
//!   Keys ordered by their own bytes alone (std integers and byte arrays) it
//!   compares as an unlatched copy instead, and checks the node's version
//!   after: a head changes only while the node holding its separator is
//!   held.

use core::borrow::Borrow;
use core::cmp::Ordering;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::Range;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicU8, Ordering as AtomicOrdering};

use super::Node;
use super::hash_tags::HashTags;
use super::inline_key_search::NodeInlineKeys;
use super::inline_keys::{KeyInliner, SearchKey, Window};
use super::internal::Internal;
use super::latch::{NodeLatch, Version};
use super::leaf::{CandidateLine, Leaf};
use super::page::{NodeKind, NodePtr};
use crate::inline_key::InlineKeyStrategy;

/// Where a key goes from an internal node read optimistically, as far as
/// its inline keys tell ([`Internal::route_racing_inline`]).
enum RacingRoute {
    Routed(Routed),
    /// The key ties with separators, whose keys decide.
    Tied(Tie),
}

/// Separators of an internal node, read optimistically, that tie with a key:
/// `candidates`, among the node's `len` as read. Without an inline key to
/// compare (`target` is `None`), all of them tie.
struct Tie {
    candidates: Range<usize>,
    len: usize,
    target: Option<Window>,
}

impl Tie {
    /// Down `edge`, right of a separator equal to the key if `at_separator`.
    fn routed(&self, edge: usize, at_separator: bool) -> Routed {
        Routed {
            edge,
            at_separator,
            len: self.len,
        }
    }
}

/// Where a key goes from an internal node read optimistically: down `edge`,
/// with the node's `len` as read. `at_separator` if the key equals separator
/// `edge - 1`, whose entry is the head of the leftmost leaf below (D17).
#[derive(Clone, Copy)]
pub(in crate::tree) struct Routed {
    pub(in crate::tree) edge: usize,
    pub(in crate::tree) at_separator: bool,
    pub(in crate::tree) len: usize,
}

impl<K, V, S: InlineKeyStrategy<K>> Leaf<K, V, S> {
    /// Whether `key` may sort after every key of this leaf, read in place
    /// without its latch while writers may change it. `false` if the leaf, as
    /// read, has no key, or a last key whose inline key alone sorts it after
    /// `key`. A hint for an append, which latches the leaf to be sure
    /// (`tree/latched/append.rs`): an insert that won't append then writes
    /// nothing to the last leaf.
    #[inline(always)]
    pub(in crate::tree) fn may_go_last_racing<Q>(self, key: &SearchKey<'_, K, S, Q>) -> bool
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        // SAFETY: the page is a leaf's, allocated while threads share the
        // tree.
        let (len, prefix_len, inline_keys) =
            unsafe { self.node_ptr().load_racing_inline_keys::<Self>() };
        let Some(last) = len.checked_sub(1) else {
            return false;
        };
        key.inline_target(prefix_len)
            .is_none_or(|target| !inline_keys.is_above(last, target.inline_key()))
    }

    /// [`Self::candidate_line`], read in place while writers may change the
    /// leaf, and the prefix length it read the leaf at. Both hold only if the
    /// leaf's version is unchanged after. A batch's lane reads it before it
    /// latches the leaf, to fetch the candidate's entry first
    /// (`tree/latched/batch.rs`).
    ///
    /// `key` shares the leaf's prefix if it routed here through nodes whose
    /// versions held.
    #[inline(always)]
    pub(in crate::tree) fn candidate_line_racing<Q>(
        self,
        key: &SearchKey<'_, K, S, Q>,
    ) -> (CandidateLine, usize)
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        // SAFETY: the page is a leaf's, allocated while threads share the
        // tree.
        let (len, prefix_len, inline_keys) =
            unsafe { self.node_ptr().load_racing_inline_keys::<Self>() };
        let candidate = match key.inline_target(prefix_len) {
            Some(target) => self.candidate_line_among(target, inline_keys, len),
            None => CandidateLine::Unknown,
        };
        (candidate, prefix_len)
    }

    /// The line of the entry an insertion of `key` would shift first, as the
    /// leaf's inline keys say, read in place while writers may change them.
    /// A batch's lane fetches it before its insert searches the leaf latched
    /// (`tree/latched/batch.rs`). `None` if the key would go last, shifting
    /// nothing, or the inline keys can't place it.
    #[inline(always)]
    pub(in crate::tree) fn racing_insertion_line<Q>(
        self,
        key: &SearchKey<'_, K, S, Q>,
    ) -> Option<*const u8>
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        // SAFETY: the page is a leaf's, allocated while threads share the
        // tree.
        let (len, prefix_len, inline_keys) =
            unsafe { self.node_ptr().load_racing_inline_keys::<Self>() };
        let edge = inline_keys
            .equal_range(key.inline_target(prefix_len)?.inline_key())
            .start;
        // SAFETY: `edge < len`, which is clamped to the capacity, so the slot
        // is in the page; only its address is taken.
        (edge < len).then(|| unsafe {
            self.node_ptr()
                .key_slots::<Self>()
                .keys()
                .slot(edge)
                .cast::<u8>()
                .as_ptr()
                .cast_const()
        })
    }

    /// A copy of key `index` and its value, read in place while writers may
    /// change them: an entry of the leaf only if its version is unchanged
    /// after ([`RacingEntry`]).
    ///
    /// # Panics
    ///
    /// In debug builds, if `index` is not below the capacity.
    #[inline(always)]
    pub(in crate::tree) fn load_racing_entry(self, index: usize) -> RacingEntry<K, V> {
        debug_assert!(index < Self::capacity());
        let page = self.node_ptr();
        // SAFETY: `index` is below the capacity, so key slot `index` and
        // value slot `index` are in the page, which is a leaf's, allocated
        // while threads share the tree. Both are read as plain bytes, which
        // `MaybeUninit` holds whatever they are.
        unsafe {
            RacingEntry {
                key: page.key_slots::<Self>().keys().slot(index).cast().read(),
                value: page.value_slots().slot(index).cast().read(),
            }
        }
    }

    /// A copy of value `index`, read in place while writers may change it:
    /// the value of key `index` only if the leaf's version is unchanged
    /// after.
    ///
    /// # Panics
    ///
    /// In debug builds, if `index` is not below the capacity.
    #[inline(always)]
    pub(in crate::tree) fn load_racing_value(self, index: usize) -> MaybeUninit<V> {
        debug_assert!(index < Self::capacity());
        // SAFETY: `index` is below the capacity, so value slot `index` is in
        // the page, which is a leaf's, allocated while threads share the
        // tree, read as plain bytes.
        unsafe { self.node_ptr().value_slots().slot(index).cast().read() }
    }

    /// Whether key `index` is `key`, decided by the leaf alone, read in place
    /// while writers may change it. `index` is a candidate: its inline key,
    /// at the leaf's `prefix_len`, equals `key`'s. `Some` for a byte string
    /// that ends within its inline key: equal lengths then make the keys
    /// equal, and an exact hash tag tells the length (D36). `None` where
    /// only the keys' bytes can tell. The answer holds only if the leaf's
    /// version is unchanged after.
    ///
    /// `key` shares the leaf's prefix if it routed here through nodes whose
    /// versions held.
    ///
    /// # Panics
    ///
    /// In debug builds, if `index` is not below the capacity.
    #[inline(always)]
    pub(in crate::tree) fn racing_candidate_is<Q>(
        self,
        key: &SearchKey<'_, K, S, Q>,
        index: usize,
        prefix_len: usize,
    ) -> Option<bool>
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        debug_assert!(index < Self::capacity());
        if !key.ends_within_window::<Self>(prefix_len) {
            return None;
        }
        let query_tag = key
            .hash_tag()
            .filter(|&tag| HashTags::is_exact_length(tag))?;
        // SAFETY: the page is a leaf's, allocated while threads share the
        // tree, and its hash tags were initialized with it (invariant 5).
        // Tag `index`, below the capacity, is a byte in the page, read as an
        // atomic.
        let tag = unsafe {
            let tags = self.node_ptr().key_columns::<Self>().hash_tags()?;
            AtomicU8::from_ptr(tags.slot(index).as_ptr()).load(AtomicOrdering::Relaxed)
        };
        Some(tag == query_tag)
    }

    /// A copy of the head's key and value, read in place while writers may
    /// change them, as [`Self::load_racing_entry`]; `None` if the leaf, as
    /// read, has no head.
    #[inline(always)]
    pub(in crate::tree) fn load_racing_head_entry(self) -> Option<RacingEntry<K, V>> {
        let page = self.node_ptr();
        // SAFETY: the page is a leaf's, allocated while threads share the tree,
        // in a map with inline keys (D49); its head key slot and head slot are
        // in it, read as plain bytes.
        unsafe {
            page.load_racing_has_head().then(|| RacingEntry {
                key: page.head_key_slot().cast().read(),
                value: page.head_and_value_slots().slot(0).cast().read(),
            })
        }
    }

    /// A copy of the head's key, read in place while writers may change it,
    /// for keys ordered by their own bytes alone
    /// ([`KeyInliner::orders_by_own_bytes`]). Whatever bytes the copy holds
    /// make a key that compares by them, and a version check after tells
    /// whether the comparison held. `None` if the leaf, as read, has no head.
    #[inline(always)]
    fn load_racing_head_key(self) -> Option<ManuallyDrop<K>> {
        debug_assert!(KeyInliner::<K>::orders_by_own_bytes::<S>());
        let page = self.node_ptr();
        // SAFETY: the page is a leaf's, allocated while threads share the tree,
        // in a map with inline keys (D49). Its head key slot is in the page,
        // and initialized once the leaf has had a head. Every bit pattern is a
        // valid key of such a type.
        unsafe {
            page.load_racing_has_head()
                .then(|| ManuallyDrop::new(page.head_key_slot().read()))
        }
    }
}

impl<K, V, S: InlineKeyStrategy<K>> Internal<K, V, S> {
    /// Routes `key` through this node, read at `version`, as
    /// [`Internal::search`] does, but in place while writers may change it.
    /// The result holds only if the version is unchanged after. `None` if a
    /// tie found the node changed, or what it read is no node any writer
    /// left; the caller starts over.
    ///
    /// `key` shares the node's prefix if it routed here through nodes whose
    /// versions held.
    #[inline(always)]
    pub(in crate::tree) fn route_racing<Q>(
        self,
        key: &SearchKey<'_, K, S, Q>,
        version: Version,
    ) -> Option<Routed>
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        match self.route_racing_inline(key) {
            RacingRoute::Routed(routed) => Some(routed),
            RacingRoute::Tied(tie) => self.route_tied(tie, version, key),
        }
    }

    /// Routes `key` through this node, read in place while writers may
    /// change it, as far as its inline keys tell: where the key goes, or the
    /// separators it ties with, whose keys in leaf heads decide (D49). The
    /// result holds only if the node's version is unchanged after.
    #[inline(always)]
    fn route_racing_inline<Q>(self, key: &SearchKey<'_, K, S, Q>) -> RacingRoute
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        // SAFETY: the page is an internal node's, allocated while threads
        // share the tree.
        let (len, prefix_len, inline_keys) =
            unsafe { self.node_ptr().load_racing_inline_keys::<Self>() };
        let Some(target) = key.inline_target(prefix_len) else {
            // A lookup through a form the nodes can't encode compares full
            // keys.
            return RacingRoute::Tied(Tie {
                candidates: 0..len,
                len,
                target: None,
            });
        };
        let candidates = inline_keys.equal_range(target.inline_key());
        // Most searches tie with no separator: they stop at the inline keys,
        // without a call (D49).
        if candidates.is_empty() {
            return RacingRoute::Routed(Routed {
                edge: candidates.start,
                at_separator: false,
                len,
            });
        }
        RacingRoute::Tied(Tie {
            candidates,
            len,
            target: Some(target),
        })
    }

    /// A binary search among the separators `tie` names, each key read in
    /// its leaf's head (D49).
    #[inline(never)]
    fn route_tied<Q>(
        self,
        tie: Tie,
        version: Version,
        key: &SearchKey<'_, K, S, Q>,
    ) -> Option<Routed>
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        let (mut low, mut high) = (tie.candidates.start, tie.candidates.end);
        while low < high {
            let middle = low + (high - low) / 2;
            let child = self.racing_child(middle + 1)?;
            // SAFETY: the tree is latched (`route_racing`'s caller), and its
            // pages stay node pages of their kind (`tree/latched`).
            if !unsafe { self.node_ptr().latch() }.is_unchanged(version) {
                return None;
            }
            let leaf = child.racing_leftmost_leaf()?;
            match self.cmp_separator_head(leaf, version, key, tie.target)? {
                Ordering::Less => high = middle,
                Ordering::Greater => low = middle + 1,
                Ordering::Equal => return Some(tie.routed(middle + 1, true)),
            }
        }
        Some(tie.routed(low, false))
    }

    /// How `key` orders against the key of a separator of this node: the
    /// head key of `leaf`, the leftmost leaf right of it (D49). The head is
    /// read with the leaf latched shared, or as a copy for keys ordered by
    /// their own bytes. The result stands only if the node, read at
    /// `version`, is unchanged once the head is read: the walk to the leaf
    /// went down first edges, which only a thread holding the node changes.
    /// `target` is the key's window the separators tie with, if it has one.
    /// `None` if the node changed, or the leaf has no head.
    ///
    /// The caller holds no latch, so waiting for the leaf's latch waits for
    /// no thread that waits for the caller.
    #[inline(always)]
    fn cmp_separator_head<Q>(
        self,
        leaf: Leaf<K, V, S>,
        version: Version,
        key: &SearchKey<'_, K, S, Q>,
        target: Option<Window>,
    ) -> Option<Ordering>
    where
        K: Borrow<Q>,
        Q: Ord + ?Sized,
    {
        // SAFETY: the tree is latched (`route_racing`'s caller), and its
        // pages stay node pages of their kind (`tree/latched`).
        let latch_of = |node: NodePtr<K, V, S>| unsafe { node.latch() };
        let cmp = |stored: &K| match target {
            Some(target) => key.cmp_tied::<Self>(target, stored),
            None => key.key().cmp(stored.borrow()),
        };
        if KeyInliner::<K>::orders_by_own_bytes::<S>() {
            // Without the latch: the head changes only while this node is
            // held (`tree/latched/held.rs`), which its version tells.
            let head = leaf.load_racing_head_key()?;
            let ordering = cmp(&head);
            return latch_of(self.node_ptr())
                .is_unchanged(version)
                .then_some(ordering);
        }
        let latched = SharedLatch::lock(latch_of(leaf.node_ptr()));
        let ordering = (latch_of(self.node_ptr()).is_unchanged(version) && leaf.has_head())
            .then(|| cmp(leaf.head_key()));
        drop(latched);
        ordering
    }

    /// The node's length, read in place while writers may change it, and
    /// clamped to the capacity. It is the node's only if the node's version
    /// is unchanged after.
    #[inline(always)]
    pub(in crate::tree) fn racing_len(self) -> usize {
        // SAFETY: the page is an internal node's, allocated while threads
        // share the tree, its header initialized.
        let (len, _) = unsafe { self.node_ptr().load_racing_header() };
        len.min(Self::capacity())
    }

    /// The node's prefix length, read in place while writers may change it.
    /// It is the node's only if the node's version is unchanged after.
    #[inline(always)]
    pub(in crate::tree) fn racing_prefix_len(self) -> usize {
        // SAFETY: as for `racing_len`.
        let (_, prefix_len) = unsafe { self.node_ptr().load_racing_header() };
        prefix_len
    }

    /// The child at edge `index`, read in place while writers may change
    /// it: what a writer stored there, or `None` for an edge none has.
    ///
    /// # Panics
    ///
    /// In debug builds, if `index > capacity`.
    #[inline(always)]
    pub(in crate::tree) fn racing_child(self, index: usize) -> Option<Node<K, V, S>> {
        debug_assert!(index <= Self::capacity());
        // SAFETY: `index <= capacity`, so the edge slot is in the page, which
        // is allocated while threads share the tree. The slot is aligned for a
        // pointer and initialized, zeroed when allocated. It is read as a raw
        // pointer, as a zeroed one is no `NodePtr`. A non-null edge is a
        // tagged pointer to a node of this map.
        unsafe {
            let slot = self.node_ptr().edge_slots().slot(index);
            let tagged = slot.cast::<*mut u8>().read();
            NonNull::new(tagged).map(|tagged| Node::at(NodePtr::from_tagged(tagged)))
        }
    }
}

impl<K, V, S: InlineKeyStrategy<K>> Node<K, V, S> {
    /// The leftmost leaf of this node, down first edges read in place while
    /// writers may change them. The leaf reached holds only while the node
    /// above this one is unchanged, which only a thread holding that node
    /// changes. `None` if the walk meets a null edge.
    #[inline(always)]
    fn racing_leftmost_leaf(self) -> Option<Leaf<K, V, S>> {
        let mut node = self;
        loop {
            node = match node {
                Node::Leaf(leaf) => return Some(leaf),
                Node::Internal(internal) => internal.racing_child(0)?,
            };
        }
    }
}

impl<K, V, S: InlineKeyStrategy<K>> NodePtr<K, V, S> {
    /// The length and prefix length of the `Kind` node on this page, and its
    /// inline keys, read in place while writers may change them. Each field
    /// is read once, and the length is clamped to the capacity, so a search
    /// over the inline keys stays in bounds whatever it read (D14).
    ///
    /// # Safety
    ///
    /// The page is a `Kind` node's, allocated while threads share the tree.
    #[inline(always)]
    unsafe fn load_racing_inline_keys<'a, Kind: NodeKind>(
        self,
    ) -> (usize, usize, NodeInlineKeys<'a>) {
        let capacity = Self::capacity::<Kind>();
        // SAFETY: the page is an allocated `Kind` node's, its header
        // initialized (caller); every inline-key slot up to the capacity is
        // initialized (invariant 4), and the view reads them through their
        // pointer.
        unsafe {
            let (len, prefix_len) = self.load_racing_header();
            let len = len.min(capacity);
            let slots = self
                .key_columns::<Kind>()
                .inline_keys()
                .expect("a latched tree's keys have inline keys");
            (len, prefix_len, NodeInlineKeys::new(slots, capacity, len))
        }
    }
}

/// A copy of a leaf's entry, its key and value, read in place while writers
/// may change them. It may be torn, or of slots no entry fills; it is an
/// entry the leaf held only if the leaf's version is unchanged after the
/// read.
pub(in crate::tree) struct RacingEntry<K, V> {
    key: MaybeUninit<K>,
    value: MaybeUninit<V>,
}

/// A key and value copied out of a leaf, which the copy must not drop: the
/// leaf's own stay where they are.
pub(in crate::tree) type CopiedEntry<K, V> = (ManuallyDrop<K>, ManuallyDrop<V>);

impl<K, V> RacingEntry<K, V> {
    /// The key and value read.
    ///
    /// # Safety
    ///
    /// The leaf stayed at one version, with no thread holding it
    /// exclusively, from before the read to after it. The read was of an
    /// entry the leaf held at that version: a key below its length, or its
    /// head, if it had one. Both are copies of the tree's, which the caller
    /// must not drop.
    #[inline(always)]
    pub(in crate::tree) unsafe fn assume_read(self) -> CopiedEntry<K, V> {
        // SAFETY: the slots held the entry's key and value throughout the
        // read (caller).
        unsafe {
            (
                ManuallyDrop::new(self.key.assume_init()),
                ManuallyDrop::new(self.value.assume_init()),
            )
        }
    }
}

/// A node latched shared until dropped, unwinding included.
struct SharedLatch<'a>(&'a NodeLatch);

impl<'a> SharedLatch<'a> {
    fn lock(latch: &'a NodeLatch) -> Self {
        latch.lock_shared();
        Self(latch)
    }
}

impl Drop for SharedLatch<'_> {
    fn drop(&mut self) {
        self.0.unlock_shared();
    }
}