Skip to main content

rudb_graph/
link.rs

1//! The forward link: for each child row, the [`Rid`] of its parent.
2//!
3//! spec/graph/03-the-file-format.md section 3.4. One per relationship, in child `rid` order, with
4//! [`NO_PARENT`] for a child whose key matched nothing. Two physical forms, chosen by measuring the
5//! column rather than by declaring it, exactly as the key map's three are.
6//!
7//! [`Form::Packed`] is the general one: the parent `rid`s bit-packed to `ceil(log2(parent + 1))`
8//! bits, with the maximum representable value meaning no parent. Random access is a shift and a
9//! mask. It answers the child to parent direction and nothing else.
10//!
11//! [`Form::Monotone`] is the one that makes the budget in section 3.7 livable. When the child table
12//! is physically clustered by the join key, which is how `dbgen` emits `lineitem` against `orders`
13//! and `partsupp` against `part`, the parent `rid`s are non-decreasing and storing one integer per
14//! child is a waste. The payload becomes a bit vector of `children + parents` bits: for each parent
15//! in `rid` order, a run of one bits, one per child that points at it, then a zero. On TPC-H SF100
16//! that is 93.8 MB against 2.10 GB for the packed form of the same relationship, and it answers
17//! both directions, so the backward adjacency of section 3.5 does not have to exist for it.
18//!
19//! # The two formulas, and the convention that decides them
20//!
21//! Section 3.4 gives `forward(child) = rank0(select1(child))` and a backward formula beside it. The
22//! two are only both true under one layout, and the one that makes the forward formula right is
23//! ones first: parent zero's children, then a zero, then parent one's children, then a zero. Under
24//! that layout a child's one bit has exactly as many zeros before it as its parent has `rid`, which
25//! is the forward formula, and the backward formula is `[cum(parent - 1), cum(parent))` where
26//! `cum(p) = select0(p) - p` is the number of children of every parent up to and including `p`.
27//! The forward direction is the hot one, so it is the one the layout is chosen for.
28//!
29//! # What the monotone form refuses
30//!
31//! A child with no parent. Under the packed form that is a reserved value; under this one there is
32//! nowhere to put it, because every bit is either a child of the parent whose run it is in or a
33//! parent boundary. A relationship with an unmatched child is therefore packed even when its
34//! matched children are in order, which is the honest answer and is what
35//! [`Link::build`] does without being asked.
36//!
37//! # Where the part-skip statistic comes from
38//!
39//! Section 5.5 prunes a whole part during a semi-join reduction using the minimum and maximum
40//! parent `rid` in that part. Section 3.4 expected that for free from the zone map of a stored
41//! column. This link is a section payload rather than a stored column, for the reason section 3.8
42//! sanctions: the parent's key map has to exist before the child's link can be built, so the link
43//! is built in a second pass at checkpoint time, and a second pass can append a section to a
44//! committed file but cannot go back and add a column to its stripes. So the statistic is stored
45//! here instead, as a minimum and a maximum per [`PART_ROWS`] children, which is sixteen bytes per
46//! thousand and change rows. The monotone form stores none, because a non-decreasing sequence's
47//! minimum and maximum over a range are its two ends and two selects are cheaper than nine
48//! megabytes.
49
50use rudb_common::{Error, Result};
51use rudb_encoding::bitpack;
52
53use crate::bits::BitVector;
54use crate::rid::{NO_PARENT, PART_ROWS, Rid};
55use crate::tail::Tail;
56
57/// The payload layout version. See the same constant in `wire.rs` for why it is belt and braces.
58const LAYOUT: u8 = 1;
59
60/// Bytes of fixed header at the front of a forward link payload.
61///
62/// `children`, `parents`, `linked`, then the four bytes that say what shape the rest is.
63pub const HEADER_BYTES: usize = 32;
64
65/// The three counts a forward link's header holds and the form of the body behind them. See
66/// [`Link::counts`].
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub struct Counts {
69    /// Rows in the child table.
70    pub children: u64,
71    /// Rows in the parent table.
72    pub parents: u64,
73    /// Children that found a parent.
74    pub linked: u64,
75    /// Which form the body behind it takes.
76    pub form: Form,
77}
78
79/// Which physical form a forward link took.
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum Form {
82    /// One bit-packed parent `rid` per child, maximum value reserved for no parent.
83    Packed,
84    /// A bit vector of runs, one run per parent, answering both directions.
85    Monotone,
86}
87
88impl Form {
89    /// The byte that names this form in a section's `flags`.
90    #[must_use]
91    pub fn tag(self) -> u8 {
92        match self {
93            Self::Packed => 0,
94            Self::Monotone => 1,
95        }
96    }
97
98    /// What `rudb_links()` calls this form.
99    #[must_use]
100    pub fn label(self) -> &'static str {
101        match self {
102            Self::Packed => "packed",
103            Self::Monotone => "monotone",
104        }
105    }
106
107    /// The form a tag names.
108    ///
109    /// # Errors
110    ///
111    /// If the tag is not one this build knows, which by section 3.2 means a section to ignore.
112    pub fn from_tag(tag: u8) -> Result<Self> {
113        match tag {
114            0 => Ok(Self::Packed),
115            1 => Ok(Self::Monotone),
116            _ => Err(malformed(format!("forward link form {tag} is not one this build knows"))),
117        }
118    }
119}
120
121/// The minimum and maximum parent `rid` over one part of the child table.
122///
123/// `None` for a part in which no child has a parent, which is a part a reduction can skip outright
124/// rather than a part whose bounds happen to be empty.
125pub type Bounds = Option<(Rid, Rid)>;
126
127#[derive(Debug, Clone)]
128enum Body {
129    Packed {
130        /// Bit-packed parent `rid`s, `width` bits each.
131        bytes: Tail,
132        width: usize,
133        /// Minimum and maximum per [`PART_ROWS`] children, for section 5.5.
134        heads: Vec<Bounds>,
135    },
136    Monotone {
137        vector: BitVector,
138    },
139}
140
141/// A relationship's child to parent map.
142#[derive(Debug, Clone)]
143pub struct Link {
144    children: u64,
145    parents: u64,
146    linked: u64,
147    body: Body,
148}
149
150/// Where [`Link::backward_from`] last stopped.
151#[derive(Debug, Clone, Copy, Default)]
152pub struct Cursor {
153    at: Option<At>,
154}
155
156#[derive(Debug, Clone, Copy)]
157struct At {
158    parent: Rid,
159    /// The bit of the zero that ends this parent's run.
160    zero: usize,
161    from: Rid,
162    to: Rid,
163}
164
165impl Cursor {
166    /// How many parents on a cursor reads rather than selects. A run is a few bits for a parent of
167    /// a few children, so this is a few words at most.
168    const NEAR: Rid = 64;
169}
170
171/// The bit of the `k`th zero, counting from zero, at or after bit `start`. `None` past the end of
172/// the words, which a caller inside the vector's zero count never reaches.
173fn kth_zero(words: &[u64], start: usize, k: u64) -> Option<usize> {
174    let mut left = k;
175    let mut word = start / 64;
176    let mut zeros = !*words.get(word)? & (u64::MAX << (start % 64));
177    loop {
178        let here = u64::from(zeros.count_ones());
179        if left < here {
180            // Under sixty four, since it is under the count of one word.
181            return Some(word * 64 + crate::bits::nth_set(zeros, left as u32) as usize);
182        }
183        left -= here;
184        word += 1;
185        zeros = !*words.get(word)?;
186    }
187}
188
189impl Link {
190    /// Builds a link from one parent `rid` per child, with [`NO_PARENT`] for the unmatched.
191    ///
192    /// The form is chosen here and not by the caller: monotone when every child has a parent and
193    /// the `rid`s are non-decreasing, packed otherwise. That decision is a pass over the slice the
194    /// caller already produced, so it costs a comparison per child on top of a build that was
195    /// already linear.
196    ///
197    /// # Errors
198    ///
199    /// If a parent `rid` is not [`NO_PARENT`] and is not below `parents`, which means the link and
200    /// the key map it was built against disagree about how many rows the parent table has. That is
201    /// a bug rather than a data condition, and a link built past the end of its parent resolves to
202    /// a row that is not there, which is the one failure in this layer that is a wrong answer.
203    pub fn build(parents_of: &[Rid], parents: u64) -> Result<Self> {
204        let children = count(parents_of.len());
205        let mut linked = 0_u64;
206        let mut monotone = true;
207        let mut previous = 0_u64;
208        for parent in parents_of {
209            if *parent == NO_PARENT {
210                monotone = false;
211                continue;
212            }
213            if *parent >= parents {
214                return Err(malformed(format!(
215                    "a forward link points at parent {parent} of a table with {parents} rows"
216                )));
217            }
218            if *parent < previous {
219                monotone = false;
220            }
221            previous = *parent;
222            linked += 1;
223        }
224        let body = if monotone && parents > 0 {
225            Body::Monotone { vector: runs(parents_of, parents)? }
226        } else {
227            packed(parents_of, parents)?
228        };
229        Ok(Self { children, parents, linked, body })
230    }
231
232    /// Which form the build chose.
233    #[must_use]
234    pub fn form(&self) -> Form {
235        match self.body {
236            Body::Packed { .. } => Form::Packed,
237            Body::Monotone { .. } => Form::Monotone,
238        }
239    }
240
241    /// Rows in the child table.
242    #[must_use]
243    pub fn children(&self) -> u64 {
244        self.children
245    }
246
247    /// Rows in the parent table.
248    #[must_use]
249    pub fn parents(&self) -> u64 {
250        self.parents
251    }
252
253    /// Children that found a parent.
254    #[must_use]
255    pub fn linked(&self) -> u64 {
256        self.linked
257    }
258
259    /// The bits of the monotone form, one run of ones per parent in `rid` order and a zero after
260    /// each, or `None` for the packed form.
261    ///
262    /// For a push that wants whole parents at a time rather than one child at a time, see
263    /// [`crate::rids::Rids::forward`].
264    pub(crate) fn runs(&self) -> Option<&BitVector> {
265        match &self.body {
266            Body::Monotone { vector } => Some(vector),
267            Body::Packed { .. } => None,
268        }
269    }
270
271    /// Bytes the body costs, not counting the header.
272    #[must_use]
273    pub fn bytes(&self) -> usize {
274        match &self.body {
275            Body::Packed { bytes, heads, .. } => bytes.len() + heads.len() * 16,
276            Body::Monotone { vector } => vector.bytes(),
277        }
278    }
279
280    /// The parent of a child row, or `None` if it has none or the child is past the end.
281    #[must_use]
282    pub fn forward(&self, child: Rid) -> Option<Rid> {
283        if child >= self.children {
284            return None;
285        }
286        match &self.body {
287            Body::Packed { bytes, width, .. } => {
288                // `tail_at` fails on a width past sixty four or an index past the end, and the
289                // bound above plus the width check at read rule out both, so an error here is not a
290                // condition to report but a bug. Section 3.1 says the answer to a broken section is
291                // no section, and `None` is what no section says about a child.
292                let value = bitpack::tail_at(bytes, *width, usize::try_from(child).ok()?).ok()?;
293                (value != reserved(*width)).then_some(value)
294            }
295            Body::Monotone { vector } => {
296                let at = vector.select1(child)?;
297                Some(vector.rank0(at))
298            }
299        }
300    }
301
302    /// The parents of a run of consecutive children, with [`NO_PARENT`] for the ones that have none.
303    ///
304    /// This is [`Link::forward`] over a range, and what it adds is the monotone form. Answering one
305    /// child there is a `select1`, which is a search, and walking a run of them one search at a time
306    /// is paying for random access on a read that is sequential. So the run is found once and then
307    /// read off the bitmap in order: a one bit is a child of the current parent and a zero bit moves
308    /// on to the next parent, which is a load per sixty four bits and a count of zeros per word.
309    ///
310    /// # Errors
311    ///
312    /// If the run goes past the last child.
313    pub fn forward_run(&self, first: Rid, out: &mut [Rid]) -> Result<()> {
314        let end = first.checked_add(count(out.len()));
315        if end.is_none_or(|end| end > self.children) {
316            return Err(Error::internal(format!(
317                "a run of {} children from {first} goes past the {} the link has",
318                out.len(),
319                self.children
320            )));
321        }
322        if out.is_empty() {
323            return Ok(());
324        }
325        match &self.body {
326            Body::Packed { bytes, width, .. } => {
327                let absent = reserved(*width);
328                let start = usize::try_from(first)
329                    .map_err(|_| malformed("a child past what fits in memory"))?;
330                for (at, slot) in out.iter_mut().enumerate() {
331                    let value = bitpack::tail_at(bytes, *width, start + at)?;
332                    *slot = if value == absent { NO_PARENT } else { value };
333                }
334            }
335            Body::Monotone { vector } => {
336                // Every child has a parent in this form, so the first child's parent is the count
337                // of zeros before its bit and every later one follows from the bits in between.
338                let Some(mut at) = vector.select1(first) else {
339                    return Err(malformed("a monotone link has fewer ones than children"));
340                };
341                let mut parent = vector.rank0(at);
342                let words = vector.words();
343                for slot in out.iter_mut() {
344                    // Skip the zeros up to the next one bit, a word at a time, counting each as a
345                    // parent boundary crossed.
346                    loop {
347                        let word = words.get(at / 64).copied().unwrap_or(0) >> (at % 64);
348                        if word == 0 {
349                            let skipped = 64 - at % 64;
350                            parent += count(skipped);
351                            at += skipped;
352                            if at >= vector.len() {
353                                return Err(malformed("a monotone link ran out of ones"));
354                            }
355                            continue;
356                        }
357                        let zeros = word.trailing_zeros() as usize;
358                        parent += count(zeros);
359                        at += zeros;
360                        break;
361                    }
362                    *slot = parent;
363                    at += 1;
364                }
365            }
366        }
367        Ok(())
368    }
369
370    /// The parent of each child in a list, with [`NO_PARENT`] for a child that has none or is past
371    /// the end.
372    ///
373    /// This is [`Link::forward`] over the rows a filter or a reduction left, and it is for the
374    /// monotone form again. A child there is a `select1` and a `rank0`, about three hundred
375    /// instructions between them, and on q09 those were a tenth of the query for 319,404 children.
376    /// The children a scan hands up are ascending, so the next one is usually a few words further
377    /// along the bitmap than the last, and walking those words is a count of ones per word. A
378    /// child further away than `Link::WALK` children, or one before the last, is searched for
379    /// again, so the answer is the same in any order and only the cost depends on it.
380    pub fn forward_each(&self, children: &[Rid], out: &mut Vec<Rid>) {
381        out.clear();
382        out.reserve(children.len());
383        let Body::Monotone { vector } = &self.body else {
384            out.extend(children.iter().map(|&child| self.forward(child).unwrap_or(NO_PARENT)));
385            return;
386        };
387        let words = vector.words();
388        // The last child answered, the position of its bit and its parent.
389        let mut last: Option<(Rid, usize, Rid)> = None;
390        for &child in children {
391            if child >= self.children {
392                out.push(NO_PARENT);
393                continue;
394            }
395            let near = last.filter(|&(from, ..)| child >= from && child - from <= Self::WALK);
396            let (at, parent) = match near {
397                Some((from, at, parent)) => {
398                    walk_ones(words, at, parent, child - from).unwrap_or((usize::MAX, NO_PARENT))
399                }
400                None => match vector.select1(child) {
401                    Some(at) => (at, vector.rank0(at)),
402                    None => (usize::MAX, NO_PARENT),
403                },
404            };
405            if parent == NO_PARENT {
406                last = None;
407            } else {
408                last = Some((child, at, parent));
409            }
410            out.push(parent);
411        }
412    }
413
414    /// How many children [`Link::forward_each`] walks the bitmap across before it searches instead.
415    ///
416    /// A word walked is about five instructions and holds a few dozen children on a table with a
417    /// few children per parent, and a search is about three hundred, so the break even is some
418    /// thousands of children and this stays well under it.
419    const WALK: Rid = 1024;
420
421    /// The children of a parent row, as a half open range of child `rid`s.
422    ///
423    /// `None` for the packed form, which does not answer this direction, and for a parent past the
424    /// end. An empty range is a parent with no children and is not the same answer.
425    #[must_use]
426    pub fn backward(&self, parent: Rid) -> Option<std::ops::Range<Rid>> {
427        let Body::Monotone { vector } = &self.body else { return None };
428        if parent >= self.parents {
429            return None;
430        }
431        // `cum(p)` is the children of every parent up to and including `p`: the `p`th zero has `p`
432        // zeros and every earlier one bit before it, so subtracting the zeros leaves the ones.
433        let cum = |nth: Rid| -> Option<u64> { vector.select0(nth).map(|at| count(at) - nth) };
434        let from = if parent == 0 { 0 } else { cum(parent - 1)? };
435        Some(from..cum(parent)?)
436    }
437
438    /// [`Self::backward`] for a parent at or a little past the one `cursor` was left at, found by
439    /// reading on from there rather than by two selects.
440    ///
441    /// For a caller asking about parents in rising order, which is a child read in its own order
442    /// asking about its siblings. A select is a search each time, and on TPC-H q21 two of them per
443    /// line of `lineitem` were a tenth of the query, where the next parent asked about is a word or
444    /// two of bits further on. A parent behind the cursor or far past it is two selects as before,
445    /// and leaves the cursor there.
446    #[must_use]
447    pub fn backward_from(&self, parent: Rid, cursor: &mut Cursor) -> Option<std::ops::Range<Rid>> {
448        let Body::Monotone { vector } = &self.body else { return None };
449        if parent >= self.parents {
450            return None;
451        }
452        if let Some(at) = cursor.at
453            && at.parent == parent
454        {
455            return Some(at.from..at.to);
456        }
457        let near = cursor.at.filter(|at| at.parent < parent && parent - at.parent <= Cursor::NEAR);
458        let found = match near {
459            Some(at) => {
460                let words = vector.words();
461                // Every run ends in a zero, so the parents in between are that many zeros on, and
462                // the ones passed on the way are their children.
463                let start = at.zero + 1;
464                let between = parent - at.parent - 1;
465                let (first, from) = if between == 0 {
466                    (start, at.to)
467                } else {
468                    let before = kth_zero(words, start, between - 1)?;
469                    (before + 1, at.to + count(before - start) - (between - 1))
470                };
471                let zero = kth_zero(words, first, 0)?;
472                At { parent, zero, from, to: from + count(zero - first) }
473            }
474            None => {
475                let zero = vector.select0(parent)?;
476                let to = count(zero) - parent;
477                let from =
478                    if parent == 0 { 0 } else { count(vector.select0(parent - 1)?) - (parent - 1) };
479                At { parent, zero, from, to }
480            }
481        };
482        cursor.at = Some(found);
483        Some(found.from..found.to)
484    }
485
486    /// The minimum and maximum parent `rid` over one part of the child table, for section 5.5.
487    ///
488    /// `None` for a part past the end of the table; `Some(None)` for a part in which no child has a
489    /// parent, which is a part a reduction skips.
490    #[must_use]
491    pub fn part_bounds(&self, part: usize) -> Option<Bounds> {
492        let first = count(part * PART_ROWS);
493        if first >= self.children {
494            return None;
495        }
496        match &self.body {
497            Body::Packed { heads, .. } => heads.get(part).copied(),
498            // A non-decreasing sequence's extremes over a range are its ends, so this is two
499            // selects rather than the nine megabytes SF100 would spend storing them.
500            Body::Monotone { .. } => {
501                let last = (first + count(PART_ROWS) - 1).min(self.children - 1);
502                match (self.forward(first), self.forward(last)) {
503                    (Some(low), Some(high)) => Some(Some((low, high))),
504                    _ => Some(None),
505                }
506            }
507        }
508    }
509
510    /// Appends the header and the body.
511    ///
512    /// # Errors
513    ///
514    /// If a length does not fit the width the layout gives it.
515    pub fn write(&self, out: &mut Vec<u8>) -> Result<()> {
516        let start = out.len();
517        out.extend_from_slice(&self.children.to_le_bytes());
518        out.extend_from_slice(&self.parents.to_le_bytes());
519        out.extend_from_slice(&self.linked.to_le_bytes());
520        out.push(self.form().tag());
521        out.push(match &self.body {
522            // The width is derivable from `parents`, and it is written anyway, because a packed
523            // array read at the wrong width is not an error but a page of plausible wrong numbers.
524            // This is the one place in this layer where a number stored twice earns its keep.
525            Body::Packed { width, .. } => u8::try_from(*width)
526                .map_err(|_| malformed("a forward link wider than a byte can name"))?,
527            Body::Monotone { .. } => 0,
528        });
529        out.push(LAYOUT);
530        // Five bytes of nothing, so that the header is thirty two and the body behind it starts on
531        // an eight byte boundary. The monotone form's body is an array of `u64`s and the packed
532        // form's head is pairs of them, and a payload whose reader has to handle both an aligned
533        // and an unaligned case for no reason is a payload with a second code path in it.
534        out.extend_from_slice(&[0; 5]);
535        debug_assert_eq!(
536            out.len() - start,
537            HEADER_BYTES,
538            "the forward link header is thirty two bytes"
539        );
540        match &self.body {
541            Body::Packed { bytes, heads, .. } => {
542                for head in heads {
543                    let (low, high) = head.unwrap_or((NO_PARENT, NO_PARENT));
544                    out.extend_from_slice(&low.to_le_bytes());
545                    out.extend_from_slice(&high.to_le_bytes());
546                }
547                out.extend_from_slice(bytes);
548            }
549            Body::Monotone { vector } => vector.write(out),
550        }
551        Ok(())
552    }
553
554    /// The counts at the front of a link's payload, read without its body.
555    ///
556    /// `bytes` is at least the first [`HEADER_BYTES`] of what [`Link::write`] produced, and may be
557    /// all of it. This is for a caller that only wants to know whether every child found a parent,
558    /// which a planner asks of every relationship before a query, and which is three numbers at the
559    /// front of a body that is megabytes long for the links of a large table.
560    ///
561    /// # Errors
562    ///
563    /// If there are fewer bytes than a header, or the header names a form or a layout this build
564    /// does not know, which is what [`Link::read`] refuses the header for too.
565    pub fn counts(bytes: &[u8]) -> Result<Counts> {
566        if bytes.len() < HEADER_BYTES {
567            return Err(malformed("a forward link payload is shorter than its header"));
568        }
569        let form = Form::from_tag(bytes[24])?;
570        if bytes[26] != LAYOUT {
571            return Err(malformed(format!(
572                "forward link layout {} is not one this build knows",
573                bytes[26]
574            )));
575        }
576        Ok(Counts {
577            children: number(&bytes[0..8])?,
578            parents: number(&bytes[8..16])?,
579            linked: number(&bytes[16..24])?,
580            form,
581        })
582    }
583
584    /// Reads a link from exactly the bytes [`Link::write`] produced.
585    ///
586    /// # Errors
587    ///
588    /// If the payload is shorter than its header, names a form or a layout this build does not
589    /// know, or holds a body that is not the size its header implies. Every one of those is a
590    /// section to drop rather than a query to fail, by section 3.1.
591    pub fn read(bytes: &[u8]) -> Result<Self> {
592        Self::read_from(bytes.to_vec(), 0)
593    }
594
595    /// [`Link::read`] of the bytes of `payload` from `at` on, keeping `payload` for the packed
596    /// parents rather than copying them out of it. See `Tail` for why.
597    ///
598    /// # Errors
599    ///
600    /// As [`Link::read`], or if `at` is past the end of `payload`.
601    pub fn read_from(payload: Vec<u8>, at: usize) -> Result<Self> {
602        let bytes = payload.get(at..).ok_or_else(|| malformed("a forward link header is torn"))?;
603        let Counts { children, parents, linked, form } = Self::counts(bytes)?;
604        let width = bytes[25] as usize;
605        let rest = &bytes[HEADER_BYTES..];
606        let body = match form {
607            Form::Packed => {
608                if width != width_for(parents) {
609                    return Err(malformed(
610                        "a forward link's width is not the one its parents imply",
611                    ));
612                }
613                let parts = usize::try_from(children.div_ceil(count(PART_ROWS)))
614                    .map_err(|_| malformed("a forward link with more parts than fit in memory"))?;
615                let head = parts * 16;
616                let rows = usize::try_from(children)
617                    .map_err(|_| malformed("a forward link longer than fits in memory"))?;
618                let packed = bitpack::tail_len(rows, width);
619                if rest.len() != head + packed {
620                    return Err(malformed(
621                        "a forward link's body is not the size its header implies",
622                    ));
623                }
624                let mut heads = Vec::with_capacity(parts);
625                for part in 0..parts {
626                    let low = number(&rest[part * 16..part * 16 + 8])?;
627                    let high = number(&rest[part * 16 + 8..part * 16 + 16])?;
628                    heads.push((low != NO_PARENT).then_some((low, high)));
629                }
630                let bytes = Tail::of(payload, at + HEADER_BYTES + head).ok_or_else(|| {
631                    malformed("a forward link's body is not the size its header implies")
632                })?;
633                Body::Packed { bytes, width, heads }
634            }
635            Form::Monotone => {
636                let len = usize::try_from(linked + parents)
637                    .map_err(|_| malformed("a forward link longer than fits in memory"))?;
638                Body::Monotone { vector: BitVector::read(rest, len)? }
639            }
640        };
641        Ok(Self { children, parents, linked, body })
642    }
643}
644
645/// The bit vector of runs, one run of ones per parent, each terminated by a zero.
646fn runs(parents_of: &[Rid], parents: u64) -> Result<BitVector> {
647    let len = usize::try_from(count(parents_of.len()) + parents)
648        .map_err(|_| malformed("a forward link longer than fits in memory"))?;
649    let mut words = vec![0_u64; len.div_ceil(64)];
650    let mut at = 0_usize;
651    let mut child = 0_usize;
652    for parent in 0..parents {
653        while child < parents_of.len() && parents_of[child] == parent {
654            words[at / 64] |= 1 << (at % 64);
655            at += 1;
656            child += 1;
657        }
658        at += 1;
659    }
660    debug_assert_eq!(at, len, "every child is a one and every parent is a zero");
661    BitVector::new(words, len)
662}
663
664/// The bit-packed array, plus the per-part bounds section 5.5 asks for.
665///
666/// The substituted values are collected before packing rather than written in place, because
667/// `bitpack::pack_linear` takes a slice and the packer's carry chain is what makes it worth
668/// reusing. That is eight bytes per child held twice for the length of one call, on top of the
669/// slice the caller already built, and it is the reason the monotone form matters: this is the
670/// path SF100's `lineitem` against `part` takes and it is expensive in both directions.
671fn packed(parents_of: &[Rid], parents: u64) -> Result<Body> {
672    let width = width_for(parents);
673    let absent = reserved(width);
674    let mut heads = Vec::with_capacity(parents_of.len().div_ceil(PART_ROWS));
675    for rows in parents_of.chunks(PART_ROWS) {
676        let mut bounds: Bounds = None;
677        for parent in rows {
678            if *parent == NO_PARENT {
679                continue;
680            }
681            bounds = Some(match bounds {
682                None => (*parent, *parent),
683                Some((low, high)) => (low.min(*parent), high.max(*parent)),
684            });
685        }
686        heads.push(bounds);
687    }
688    let values = parents_of
689        .iter()
690        .map(|parent| if *parent == NO_PARENT { absent } else { *parent })
691        .collect::<Vec<u64>>();
692    let mut bytes = Vec::with_capacity(bitpack::tail_len(values.len(), width));
693    bitpack::pack_linear(&values, width, &mut bytes)?;
694    Ok(Body::Packed { bytes: bytes.into(), width, heads })
695}
696
697/// Bits per entry: enough for every parent `rid` and one more value meaning no parent.
698///
699/// The bit length of `parents`, which is `ceil(log2(parents + 1))` written the way a CPU computes
700/// it. A table of three parents has `rid`s zero, one and two and needs a fourth value for absent,
701/// which is two bits exactly; a table of four needs three.
702fn width_for(parents: u64) -> usize {
703    (u64::BITS - parents.leading_zeros()).max(1) as usize
704}
705
706/// The value that means no parent, which is the largest the width can hold.
707fn reserved(width: usize) -> u64 {
708    if width >= 64 { u64::MAX } else { (1_u64 << width) - 1 }
709}
710
711/// A row count as a `u64`, which is what every count in a header is.
712/// The position and parent of the one bit `skip` ones after the one at `at`, whose parent is
713/// `parent`, or `None` if the bitmap runs out first.
714///
715/// Each zero crossed is a parent boundary. A word at a time: shift out the bits at or before the
716/// current one, and either the ones left in the word are too few, so count them and its zeros and
717/// move on, or the one wanted is in it.
718fn walk_ones(words: &[u64], at: usize, mut parent: Rid, skip: Rid) -> Option<(usize, Rid)> {
719    if skip == 0 {
720        return Some((at, parent));
721    }
722    let mut left = skip - 1;
723    let mut from = at + 1;
724    loop {
725        let index = from / 64;
726        let offset = from % 64;
727        let word = *words.get(index)? >> offset;
728        let span = 64 - offset;
729        let ones = u64::from(word.count_ones());
730        if ones > left {
731            #[expect(clippy::cast_possible_truncation, reason = "under the ones in one word")]
732            let within = crate::bits::nth_set(word, left as u32) as usize;
733            // The zeros between `from` and the one found are the parents crossed.
734            parent += count(within) - left;
735            return Some((from + within, parent));
736        }
737        // The caller checked the child against the count of children, so the one wanted is in
738        // the words and the tail past the length is never reached.
739        parent += count(span) - ones;
740        left -= ones;
741        from += span;
742    }
743}
744
745fn count(rows: usize) -> u64 {
746    u64::try_from(rows).unwrap_or(u64::MAX)
747}
748
749fn number(bytes: &[u8]) -> Result<u64> {
750    Ok(u64::from_le_bytes(
751        bytes.try_into().map_err(|_| malformed("a forward link header is torn"))?,
752    ))
753}
754
755fn malformed(message: impl Into<String>) -> Error {
756    Error::invalid_input(format!("invalid rudb forward link: {}", message.into()))
757}
758
759#[cfg(test)]
760mod tests {
761    use super::*;
762
763    #[test]
764    fn a_cursor_finds_the_same_children_as_a_select() {
765        // Parents of zero to nine children, some childless, over several words of runs.
766        let mut parents_of = Vec::new();
767        for parent in 0..3_000_u64 {
768            for _ in 0..(parent * 7 + parent / 13) % 10 {
769                parents_of.push(parent);
770            }
771        }
772        let link = Link::build(&parents_of, 3_000).expect("build");
773        assert_eq!(link.form(), Form::Monotone);
774        let mut asked: Vec<Rid> = (0..3_000).step_by(3).collect();
775        // Repeats, steps of one, a step back, a jump past what the cursor reads on over, the last.
776        asked.extend([2_000, 2_000, 2_001, 2_002, 5, 6, 2_900, 2_999, 0, 1_000, 1_064, 1_129]);
777        let mut cursor = Cursor::default();
778        for parent in asked {
779            assert_eq!(link.backward_from(parent, &mut cursor), link.backward(parent), "{parent}");
780        }
781        assert_eq!(link.backward_from(3_000, &mut cursor), None);
782    }
783
784    /// Checks every child resolves to the parent it was built from, in the link and in a copy of it
785    /// that went through the payload.
786    fn resolves(parents_of: &[Rid], parents: u64) -> Link {
787        let built = Link::build(parents_of, parents).expect("build");
788        let mut bytes = Vec::new();
789        built.write(&mut bytes).expect("write");
790        let read = Link::read(&bytes).expect("read");
791        let counts = Link::counts(&bytes[..HEADER_BYTES]).expect("the header alone");
792        assert_eq!(
793            counts,
794            Counts {
795                children: built.children(),
796                parents: built.parents(),
797                linked: built.linked(),
798                form: built.form()
799            }
800        );
801        assert_eq!(read.form(), built.form(), "the form survives the round trip");
802        assert_eq!(read.children(), built.children());
803        assert_eq!(read.parents(), built.parents());
804        assert_eq!(read.linked(), built.linked());
805        for link in [&built, &read] {
806            for (child, parent) in parents_of.iter().enumerate() {
807                let want = (*parent != NO_PARENT).then_some(*parent);
808                assert_eq!(link.forward(child as Rid), want, "child {child}");
809            }
810            assert_eq!(link.forward(parents_of.len() as Rid), None, "past the last child");
811        }
812        built
813    }
814
815    #[test]
816    fn a_clustered_child_takes_the_monotone_form_and_answers_both_directions() {
817        // Three children of parent zero, none of parent one, two of parent two. This is the shape
818        // `lineitem` has against `orders` and it is the whole reason the form exists.
819        let link = resolves(&[0, 0, 0, 2, 2], 3);
820        assert_eq!(link.form(), Form::Monotone);
821        assert_eq!(link.backward(0), Some(0..3));
822        assert_eq!(link.backward(1), Some(3..3), "a parent with no children, not a missing parent");
823        assert_eq!(link.backward(2), Some(3..5));
824        assert_eq!(link.backward(3), None, "past the last parent");
825    }
826
827    #[test]
828    fn an_unclustered_child_takes_the_packed_form_and_answers_one_direction() {
829        let link = resolves(&[4, 1, 4, 0, 2], 5);
830        assert_eq!(link.form(), Form::Packed);
831        assert_eq!(link.backward(0), None, "the packed form does not answer backward");
832    }
833
834    #[test]
835    fn a_child_with_no_parent_keeps_the_link_out_of_the_monotone_form() {
836        // Every bit of the monotone vector is a child or a parent boundary, so there is nowhere to
837        // put an unmatched child. Ordered children plus one orphan is packed, and that is honest
838        // rather than a missed opportunity.
839        let link = resolves(&[0, 1, NO_PARENT, 2], 3);
840        assert_eq!(link.form(), Form::Packed);
841        assert_eq!(link.linked(), 3, "the orphan is not linked and the other three are");
842    }
843
844    #[test]
845    fn every_child_pointing_at_one_parent_is_one_run() {
846        let link = resolves(&[7; 50], 8);
847        assert_eq!(link.form(), Form::Monotone);
848        assert_eq!(link.backward(6), Some(0..0));
849        assert_eq!(link.backward(7), Some(0..50));
850    }
851
852    #[test]
853    fn a_link_with_no_children_builds_and_resolves_nothing() {
854        let link = resolves(&[], 10);
855        assert_eq!(link.children(), 0);
856        assert_eq!(link.forward(0), None);
857        assert_eq!(link.part_bounds(0), None, "there is no part zero of an empty table");
858    }
859
860    #[test]
861    fn a_link_whose_parent_table_is_empty_is_packed_and_matches_nothing() {
862        // Not monotone: a bit vector of zero runs has nowhere to put a child. The packed form with
863        // one reserved value is the answer, and every child is unmatched, which is what a link
864        // against an empty parent means.
865        let link = resolves(&[NO_PARENT, NO_PARENT], 0);
866        assert_eq!(link.form(), Form::Packed);
867        assert_eq!(link.linked(), 0);
868    }
869
870    #[test]
871    fn a_parent_rid_past_the_parent_table_is_refused_rather_than_stored() {
872        // The one failure in this layer that is a wrong answer rather than a slow one: a link built
873        // past the end of its parent resolves to a row that is not there.
874        let error = Link::build(&[0, 9], 5).expect_err("refused");
875        assert!(error.to_string().contains("parent 9"), "{error}");
876    }
877
878    #[test]
879    fn the_reserved_value_is_not_a_parent_rid_even_at_the_width_boundary() {
880        // Three parents need two bits for rids zero, one and two, and a third value for no parent,
881        // which is four values and therefore two bits exactly. Four parents need three.
882        assert_eq!(width_for(3), 2);
883        assert_eq!(width_for(4), 3);
884        assert_eq!(reserved(2), 3);
885        let link = resolves(&[2, 0, NO_PARENT], 3);
886        assert_eq!(link.form(), Form::Packed);
887    }
888
889    #[test]
890    fn a_packed_link_carries_the_bounds_of_every_part() {
891        let mut parents_of = vec![0_u64; PART_ROWS * 2 + 5];
892        for (child, parent) in parents_of.iter_mut().enumerate() {
893            // Descending within each part, so the part is not monotone and its bounds are not its
894            // ends, which is what the stored head is for.
895            *parent = (PART_ROWS - child % PART_ROWS) as u64;
896        }
897        let link = Link::build(&parents_of, PART_ROWS as u64 + 1).expect("build");
898        assert_eq!(link.form(), Form::Packed);
899        assert_eq!(link.part_bounds(0), Some(Some((1, PART_ROWS as u64))));
900        assert_eq!(link.part_bounds(2), Some(Some((PART_ROWS as u64 - 4, PART_ROWS as u64))));
901        assert_eq!(link.part_bounds(3), None, "there is no fourth part");
902    }
903
904    #[test]
905    fn a_part_in_which_nothing_matched_is_reported_as_skippable() {
906        let mut parents_of = vec![NO_PARENT; PART_ROWS * 2];
907        parents_of[PART_ROWS] = 3;
908        let link = Link::build(&parents_of, 10).expect("build");
909        assert_eq!(link.part_bounds(0), Some(None), "a part a reduction can skip outright");
910        assert_eq!(link.part_bounds(1), Some(Some((3, 3))));
911    }
912
913    #[test]
914    fn a_monotone_link_derives_its_part_bounds_from_its_ends() {
915        let parents_of = (0..PART_ROWS as u64 * 2).map(|child| child / 4).collect::<Vec<Rid>>();
916        let link = Link::build(&parents_of, PART_ROWS as u64).expect("build");
917        assert_eq!(link.form(), Form::Monotone);
918        assert_eq!(link.part_bounds(0), Some(Some((0, (PART_ROWS as u64 - 1) / 4))));
919        assert_eq!(
920            link.part_bounds(1),
921            Some(Some((PART_ROWS as u64 / 4, (PART_ROWS as u64 * 2 - 1) / 4)))
922        );
923    }
924
925    #[test]
926    fn the_monotone_form_is_a_bit_per_child_and_the_packed_form_is_a_rid_per_child() {
927        // Section 3.4's arithmetic in miniature. Ten thousand children of a thousand parents: the
928        // packed form is ten bits each and the monotone form is one bit each plus one per parent.
929        let ordered = (0..10_000_u64).map(|child| child / 10).collect::<Vec<Rid>>();
930        let monotone = Link::build(&ordered, 1000).expect("build");
931        assert_eq!(monotone.form(), Form::Monotone);
932        let mut shuffled = ordered.clone();
933        shuffled.swap(0, 9999);
934        let packed = Link::build(&shuffled, 1000).expect("build");
935        assert_eq!(packed.form(), Form::Packed);
936        assert!(
937            monotone.bytes() * 4 < packed.bytes(),
938            "monotone {} is not far below packed {}",
939            monotone.bytes(),
940            packed.bytes()
941        );
942    }
943
944    #[test]
945    fn a_payload_shorter_than_its_header_is_refused() {
946        let link = Link::build(&[0, 1], 2).expect("build");
947        let mut bytes = Vec::new();
948        link.write(&mut bytes).expect("write");
949        for cut in [0, 1, HEADER_BYTES - 1] {
950            assert!(Link::read(&bytes[..cut]).is_err(), "a payload of {cut} bytes is refused");
951            assert!(Link::counts(&bytes[..cut]).is_err(), "a header of {cut} bytes is refused");
952        }
953    }
954
955    #[test]
956    fn a_form_or_a_layout_this_build_does_not_know_is_refused() {
957        let link = Link::build(&[0, 1], 2).expect("build");
958        let mut bytes = Vec::new();
959        link.write(&mut bytes).expect("write");
960        let mut wrong = bytes.clone();
961        wrong[24] = 9;
962        assert!(Link::read(&wrong).is_err(), "an unknown form is refused");
963        assert!(Link::counts(&wrong).is_err(), "and its counts are not read");
964        let mut wrong = bytes;
965        wrong[26] = LAYOUT + 1;
966        assert!(Link::read(&wrong).is_err(), "an unknown layout is refused");
967    }
968
969    #[test]
970    fn a_width_that_does_not_match_the_parents_is_refused_rather_than_read_at() {
971        // A packed array read at the wrong width is a page of plausible wrong numbers rather than
972        // an error, which is why the width is both stored and checked against what it should be.
973        let link = Link::build(&[1, 0], 2).expect("build");
974        let mut bytes = Vec::new();
975        link.write(&mut bytes).expect("write");
976        bytes[25] = 7;
977        let error = Link::read(&bytes).expect_err("refused");
978        assert!(error.to_string().contains("width"), "{error}");
979    }
980
981    #[test]
982    fn a_truncated_body_is_refused_for_either_form() {
983        for parents_of in [vec![0_u64, 0, 1, 2], vec![2_u64, 0, 1, 0]] {
984            let link = Link::build(&parents_of, 3).expect("build");
985            let mut bytes = Vec::new();
986            link.write(&mut bytes).expect("write");
987            let short = &bytes[..bytes.len() - 1];
988            assert!(Link::read(short).is_err(), "a truncated {:?} body is refused", link.form());
989        }
990    }
991
992    /// A run decodes to what the per child lookup says, from every starting point and across long
993    /// stretches of parents with no children, which is where the word at a time walk could slip.
994    #[test]
995    fn a_run_agrees_with_the_per_child_lookup_in_both_forms() {
996        let mut clustered = Vec::new();
997        for parent in 0..400_u64 {
998            // Parents with no children in runs of up to a few hundred, so a walk crosses whole
999            // words of zeros.
1000            let children = if parent % 50 < 45 { 0 } else { parent % 7 + 1 };
1001            clustered.extend(std::iter::repeat_n(parent, children as usize));
1002        }
1003        let scattered: Vec<Rid> = (0..3000_u64)
1004            .map(|child| if child % 13 == 0 { NO_PARENT } else { (child * 37) % 500 })
1005            .collect();
1006        for (parents_of, parents) in [(clustered, 400), (scattered, 500)] {
1007            let link = Link::build(&parents_of, parents).expect("build");
1008            let children = link.children();
1009            for first in [0, 1, 63, 64, 65, children / 2, children - 1] {
1010                for len in [0, 1, 2, 100, children - first] {
1011                    let len = len.min(children - first);
1012                    let mut out = vec![0; len as usize];
1013                    link.forward_run(first, &mut out).expect("in range");
1014                    let want: Vec<Rid> = (first..first + len)
1015                        .map(|child| link.forward(child).unwrap_or(NO_PARENT))
1016                        .collect();
1017                    assert_eq!(out, want, "{:?} from {first} for {len}", link.form());
1018                }
1019            }
1020            let mut out = vec![0; 2];
1021            assert!(link.forward_run(children - 1, &mut out).is_err(), "past the last child");
1022        }
1023    }
1024
1025    /// A list of children decodes to what the per child lookup says, whether the list goes up in
1026    /// small steps, in steps past the walk, backwards, or past the last child.
1027    #[test]
1028    fn a_list_agrees_with_the_per_child_lookup_in_both_forms() {
1029        let mut clustered = Vec::new();
1030        for parent in 0..3000_u64 {
1031            let children = if parent % 50 < 45 { parent % 3 } else { parent % 7 + 1 };
1032            clustered.extend(std::iter::repeat_n(parent, children as usize));
1033        }
1034        let scattered: Vec<Rid> = (0..3000_u64)
1035            .map(|child| if child % 13 == 0 { NO_PARENT } else { (child * 37) % 500 })
1036            .collect();
1037        for (parents_of, parents) in [(clustered, 3000), (scattered, 500)] {
1038            let link = Link::build(&parents_of, parents).expect("build");
1039            let children = link.children();
1040            let mut lists: Vec<Vec<Rid>> = vec![
1041                Vec::new(),
1042                (0..children).collect(),
1043                (0..children).step_by(7).collect(),
1044                (0..children).step_by(1500).collect(),
1045                (0..children).rev().step_by(11).collect(),
1046                vec![5, 5, 4, children - 1, children, children + 9, 0, 63, 64, 65],
1047            ];
1048            let mut state = 7_u64;
1049            let mut sparse = Vec::new();
1050            for child in 0..children {
1051                state = state.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
1052                if state >> 60 == 0 {
1053                    sparse.push(child);
1054                }
1055            }
1056            lists.push(sparse);
1057            let mut out = Vec::new();
1058            for list in &lists {
1059                link.forward_each(list, &mut out);
1060                let want: Vec<Rid> =
1061                    list.iter().map(|&child| link.forward(child).unwrap_or(NO_PARENT)).collect();
1062                assert_eq!(out, want, "{:?} over {} children", link.form(), list.len());
1063            }
1064        }
1065    }
1066}