Skip to main content

rudb_graph/
keymap.rs

1//! Turning a parent key value into a [`Rid`].
2//!
3//! A link is built from an equality between a child column and a parent column, and to build it the
4//! parent column's values have to become row ids. That map is the key map. It has the three
5//! physical forms of spec/graph/02-the-data-model.md section 2.2, chosen by measurement at build
6//! time rather than by declaration, and the form that was chosen is recorded in the header so that
7//! a reader does not have to guess.
8//!
9//! The three exist because they are three different answers to the same question and the cheapest
10//! one is usually available:
11//!
12//! - [`Form::Identity`] when the keys are exactly `base .. base + n` in order. Nothing is stored
13//!   but two numbers, and TPC-H hits this on six of its eight tables.
14//! - [`Form::Dense`] when the keys are distinct integers packed densely enough into a range that a
15//!   bitmap plus a rank index beats storing them.
16//! - [`Form::Sorted`] for everything else, including every string key, which arrives here as
17//!   dictionary codes rather than as text.
18//!
19//! What is deliberately absent is a hash. A minimal perfect hash is faster to probe than the sorted
20//! form and much slower to build, and there is no measurement yet saying the probe is where the
21//! time goes. spec/graph/11-open-questions.md keeps it open, and adding it later costs nothing
22//! because the form is a tag in a header that a reader is already required to be able to not
23//! recognize.
24
25use rudb_common::{Error, Result};
26use rudb_encoding::bitpack;
27
28use crate::rid::Rid;
29
30/// How dense a range has to be before the bitmap form beats the sorted form.
31///
32/// One in eight, per section 2.2. Below it the bitmap is larger than storing the keys: a bitmap
33/// costs `range / 8` bytes plus about an eighth again for the rank index, and the sorted form costs
34/// `count` keys plus `count` permutation entries, so the crossover is a ratio rather than a size.
35/// The default is here as a named constant rather than inline because it is a number somebody will
36/// want to move once there is a measurement that says where, and moving it should be a diff.
37pub const DENSE_THRESHOLD: u64 = 8;
38
39/// Bits in one rank superblock.
40const SUPERBLOCK_BITS: usize = 4096;
41
42/// Bits in one rank block.
43const BLOCK_BITS: usize = 512;
44
45/// Blocks in one superblock.
46const BLOCKS_PER_SUPERBLOCK: usize = SUPERBLOCK_BITS / BLOCK_BITS;
47
48/// Which of the three physical forms a key map took.
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum Form {
51    /// `rid = key - base`, and nothing is stored but `base` and the count.
52    Identity,
53    /// `rid = rank(key - base)` over a bitmap of the range, with a two level rank index.
54    Dense,
55    /// Binary search over the sorted keys, then a permutation lookup.
56    Sorted,
57}
58
59impl Form {
60    /// The tag this form takes in a section header.
61    #[must_use]
62    pub fn tag(self) -> u8 {
63        match self {
64            Self::Identity => 0,
65            Self::Dense => 1,
66            Self::Sorted => 2,
67        }
68    }
69
70    /// What this form is called where a person reads it, which is `rudb_links()`.
71    #[must_use]
72    pub fn label(self) -> &'static str {
73        match self {
74            Self::Identity => "identity",
75            Self::Dense => "dense",
76            Self::Sorted => "sorted",
77        }
78    }
79
80    /// The form a header tag names.
81    ///
82    /// # Errors
83    ///
84    /// If the tag is not one of the three. A reader that meets an unfamiliar form has met a file
85    /// written by a later build, and the right response is the one section 3.2 requires of an
86    /// unfamiliar section kind: ignore this key map and answer the query without it. So this
87    /// returns an error and the caller drops the section rather than failing the open.
88    pub fn from_tag(tag: u8) -> Result<Self> {
89        match tag {
90            0 => Ok(Self::Identity),
91            1 => Ok(Self::Dense),
92            2 => Ok(Self::Sorted),
93            _ => Err(malformed(format!("key map form {tag} is not one this build knows"))),
94        }
95    }
96}
97
98/// What the build saw while it read the parent key column.
99///
100/// This is the cardinality verification of section 2.3, and it is written into the header rather
101/// than recomputed because the build already had every value in front of it. Recording what was
102/// observed rather than what was declared is what keeps a wrong `FOREIGN KEY` from producing a
103/// wrong answer: a declaration that fails verification is reported, and no link is built.
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub struct Observed {
106    /// Non-null values seen.
107    pub rows: u64,
108    /// Nulls seen, which are not keys and match no child row.
109    pub nulls: u64,
110    /// Whether every non-null value was distinct. False means no link may be built at all.
111    pub distinct: bool,
112    /// Whether the values arrived in non-decreasing order.
113    pub sorted: bool,
114    /// The smallest non-null value, or `None` when there were none.
115    pub min: Option<i128>,
116    /// The largest non-null value, or `None` when there were none.
117    pub max: Option<i128>,
118}
119
120impl Observed {
121    /// Whether this column can be the parent side of a link.
122    ///
123    /// Distinctness is the whole requirement. A parent side that is not unique is not an error and
124    /// is not a link: section 2.3 says it is a relationship that has to be executed as an ordinary
125    /// join, and the planner is told so rather than left to find out.
126    #[must_use]
127    pub fn usable_as_parent(&self) -> bool {
128        self.distinct
129    }
130}
131
132/// A two level rank index over a bitmap.
133///
134/// Superblocks of 4096 bits hold a `u32` cumulative count from the start of the bitmap, and blocks
135/// of 512 bits hold a `u16` count from the start of their superblock. A rank is then two loads and
136/// a `popcount` over at most eight words, which is section 3.3's arithmetic and is the reason the
137/// block size is 512: a `u16` cannot hold a count over a wider superblock than 4096, and eight
138/// words is the most a `popcount` loop should have to do.
139#[derive(Debug, Clone)]
140struct Rank {
141    superblocks: Vec<u32>,
142    blocks: Vec<u16>,
143}
144
145impl Rank {
146    fn build(bits: &[u64]) -> Self {
147        let blocks = bits.len().div_ceil(BLOCK_BITS / 64);
148        let mut index = Self {
149            superblocks: Vec::with_capacity(blocks.div_ceil(BLOCKS_PER_SUPERBLOCK)),
150            blocks: Vec::with_capacity(blocks),
151        };
152        let mut total = 0_u32;
153        let mut within = 0_u16;
154        for block in 0..blocks {
155            if block % BLOCKS_PER_SUPERBLOCK == 0 {
156                index.superblocks.push(total);
157                within = 0;
158            }
159            index.blocks.push(within);
160            let words = block * (BLOCK_BITS / 64);
161            let ones: u32 = bits[words..(words + BLOCK_BITS / 64).min(bits.len())]
162                .iter()
163                .map(|word| word.count_ones())
164                .sum();
165            total += ones;
166            // A superblock holds at most 4096 ones, so this cannot overflow a u16, and the `as` is
167            // guarded by the reset above rather than by hope.
168            #[expect(
169                clippy::cast_possible_truncation,
170                reason = "a superblock holds at most 4096 bits, which fits a u16"
171            )]
172            let ones = ones as u16;
173            within += ones;
174        }
175        index
176    }
177
178    /// How many bits are set strictly below `at`.
179    fn rank(&self, bits: &[u64], at: usize) -> u64 {
180        let block = at / BLOCK_BITS;
181        let superblock = block / BLOCKS_PER_SUPERBLOCK;
182        let mut count = u64::from(self.superblocks[superblock]) + u64::from(self.blocks[block]);
183        let from = block * (BLOCK_BITS / 64);
184        let word = at / 64;
185        for whole in &bits[from..word] {
186            count += u64::from(whole.count_ones());
187        }
188        let remainder = at % 64;
189        if remainder != 0 {
190            let mask = (1_u64 << remainder) - 1;
191            count += u64::from((bits[word] & mask).count_ones());
192        }
193        count
194    }
195
196    fn bytes(&self) -> usize {
197        self.superblocks.len() * size_of::<u32>() + self.blocks.len() * size_of::<u16>()
198    }
199
200    /// How many blocks and superblocks index a bitmap of this many words.
201    ///
202    /// Derived rather than stored, because both counts are a function of the range the header
203    /// already carries and a stored count is a count that can disagree with the array it describes.
204    fn shape(words: usize) -> (usize, usize) {
205        let blocks = words.div_ceil(BLOCK_BITS / 64);
206        (blocks, blocks.div_ceil(BLOCKS_PER_SUPERBLOCK))
207    }
208
209    fn write(&self, out: &mut Vec<u8>) {
210        for count in &self.superblocks {
211            out.extend_from_slice(&count.to_le_bytes());
212        }
213        for offset in &self.blocks {
214            out.extend_from_slice(&offset.to_le_bytes());
215        }
216    }
217
218    /// Reads an index over a bitmap of `words` words from exactly the bytes it takes.
219    fn read(bytes: &[u8], words: usize) -> Result<Self> {
220        let (blocks, superblocks) = Self::shape(words);
221        let split = superblocks * size_of::<u32>();
222        if bytes.len() != split + blocks * size_of::<u16>() {
223            return Err(malformed(
224                "a dense key map's rank index is not the size its range implies",
225            ));
226        }
227        Ok(Self {
228            superblocks: bytes[..split]
229                .chunks_exact(size_of::<u32>())
230                .map(|word| u32::from_le_bytes(word.try_into().expect("four bytes")))
231                .collect(),
232            blocks: bytes[split..]
233                .chunks_exact(size_of::<u16>())
234                .map(|word| u16::from_le_bytes(word.try_into().expect("two bytes")))
235                .collect(),
236        })
237    }
238}
239
240/// The three forms, behind one interface.
241#[derive(Debug, Clone)]
242enum Body {
243    Identity {
244        base: i128,
245        count: u64,
246    },
247    Dense {
248        base: i128,
249        range: u64,
250        bits: Vec<u64>,
251        rank: Rank,
252    },
253    Sorted {
254        /// The smallest key, so that every stored key is a `u64` offset from it whatever the
255        /// column's own type was.
256        base: i128,
257        /// Bits one stored key offset takes.
258        key_width: usize,
259        /// The key offsets in ascending order, bit packed.
260        keys: Vec<u8>,
261        /// Bits one permutation entry takes, which is `ceil(log2(rows))`.
262        rid_width: usize,
263        /// Sorted position to `rid`, bit packed.
264        perm: Vec<u8>,
265        count: u64,
266    },
267}
268
269/// A map from a parent key value to the `rid` of the row that holds it.
270#[derive(Debug, Clone)]
271pub struct KeyMap {
272    body: Body,
273    observed: Observed,
274}
275
276impl KeyMap {
277    /// Builds the cheapest correct form for these keys.
278    ///
279    /// `keys` is the parent key column in `rid` order, with `None` for a null. The `rid` of a value
280    /// is its index, which is what makes this the whole build: the caller has already read the
281    /// column in append order, so the row ids are the positions and there is nothing to look up.
282    ///
283    /// String keys arrive here as dictionary codes rather than as text, per section 2.2. That is
284    /// not a convenience, it is the reason a sorted key map over a `VARCHAR` column never touches a
285    /// byte of text: the codes of a file wide stable dictionary are integers with the column's own
286    /// order, so the search is over `u32`.
287    ///
288    /// # Errors
289    ///
290    /// If the column's values span more than a `u64`, if it holds more rows than a `u64` of
291    /// `rid`s, or if a bit packed payload cannot be written. A non-distinct column is not an
292    /// error: it produces a key map whose [`Observed`] says so, and the caller is expected to ask
293    /// before building a link on it.
294    pub fn build(keys: &[Option<i128>]) -> Result<Self> {
295        let mut observed = observe(keys);
296        // See [`KeyMap::build_from`], which takes the same shortcut for the same reason and is
297        // where the reason is written. The two paths agree on every column or a table's key map
298        // depends on which of them built it.
299        if !observed.distinct {
300            return Ok(Self { body: Body::Identity { base: 0, count: 0 }, observed });
301        }
302        Ok(match plan(&observed)? {
303            Plan::Empty => Self { body: Body::Identity { base: 0, count: 0 }, observed },
304            Plan::Identity { base, count } => {
305                Self { body: Body::Identity { base, count }, observed }
306            }
307            Plan::Dense { base, range } => Self { body: dense(keys, base, range)?, observed },
308            Plan::Sorted { base } => {
309                // The sorted form sorts, so it is the one place distinctness can be settled for a
310                // column that did not arrive in order. `observe` can only see an adjacent
311                // duplicate; this sees every duplicate, and the answer replaces the guess.
312                let (body, distinct) = sorted(keys, base, observed.rows)?;
313                observed.distinct = distinct;
314                Self { body, observed }
315            }
316        })
317    }
318
319    /// Builds the cheapest correct form by reading the column rather than by holding it.
320    ///
321    /// The same build as [`KeyMap::build`] and the same decision, taken from a source that can be
322    /// scanned twice instead of from a slice that is already in memory. That difference is the
323    /// whole reason this exists. A parent key column at TPC-H SF10 is fifteen million rows of
324    /// `orders`, and a `Vec<Option<i128>>` of those is four hundred and eighty megabytes held for
325    /// the length of a build that does not need a single one of them twice. At SF100 it is four and
326    /// a half gigabytes, which is not a slow build, it is a build that does not happen.
327    ///
328    /// So the first scan observes and nothing else, and what the second scan does depends on what
329    /// the first one found. The identity form, which is the form every TPC-H parent key takes,
330    /// needs no second scan at all: the four observed facts are the whole map. The dense form fills
331    /// a bitmap sized from the range, which is bounded by the table rather than by the scan. Only
332    /// the sorted form has to hold the column, because sorting is what it is, and it says so here
333    /// rather than surprising a caller with it.
334    ///
335    /// # Errors
336    ///
337    /// If the scan fails, or for any of the reasons [`KeyMap::build`] fails.
338    pub fn build_from<K: Keys + ?Sized>(keys: &K) -> Result<Self> {
339        let mut observer = Observer::new();
340        keys.scan(&mut |key| {
341            observer.push(key);
342            Ok(())
343        })?;
344        let mut observed = observer.observed;
345        // A column the first scan already saw a repeat in gets no body at all. No form answers a
346        // rid for a key that is in two rows, so every byte spent on one is spent on a map nothing
347        // may use, and the bytes are not small: TPC-H SF10 `lineitem(l_orderkey)` sorts sixty
348        // million keys into three hundred and ninety megabytes before the budget throws all of it
349        // away. This is only reachable where the duplicates are adjacent, which is where the column
350        // arrived in order, and that is the case this is for. A repeat that only the sort can find
351        // is still found by the sort, below.
352        if !observed.distinct {
353            return Ok(Self { body: Body::Identity { base: 0, count: 0 }, observed });
354        }
355        Ok(match plan(&observed)? {
356            Plan::Empty => Self { body: Body::Identity { base: 0, count: 0 }, observed },
357            Plan::Identity { base, count } => {
358                Self { body: Body::Identity { base, count }, observed }
359            }
360            Plan::Dense { base, range } => {
361                let mut bits = DenseBits::new(base, range);
362                keys.scan(&mut |key| match key {
363                    Some(key) => bits.push(key),
364                    None => Ok(()),
365                })?;
366                Self { body: bits.finish(), observed }
367            }
368            Plan::Sorted { base } => {
369                let mut held = Vec::with_capacity(
370                    usize::try_from(observed.rows + observed.nulls).unwrap_or_default(),
371                );
372                keys.scan(&mut |key| {
373                    held.push(key);
374                    Ok(())
375                })?;
376                let (body, distinct) = sorted(&held, base, observed.rows)?;
377                observed.distinct = distinct;
378                Self { body, observed }
379            }
380        })
381    }
382
383    /// Which form this map took.
384    #[must_use]
385    pub fn form(&self) -> Form {
386        match self.body {
387            Body::Identity { .. } => Form::Identity,
388            Body::Dense { .. } => Form::Dense,
389            Body::Sorted { .. } => Form::Sorted,
390        }
391    }
392
393    /// What the build saw, which is the cardinality verification.
394    #[must_use]
395    pub fn observed(&self) -> &Observed {
396        &self.observed
397    }
398
399    /// The value every stored key is an offset from, which is the smallest key.
400    pub(crate) fn base(&self) -> i128 {
401        match &self.body {
402            Body::Identity { base, .. } | Body::Dense { base, .. } | Body::Sorted { base, .. } => {
403                *base
404            }
405        }
406    }
407
408    /// Appends the form's own bytes, after the header that `wire` has already written.
409    ///
410    /// Nothing here is stored that the header and the form together derive. The identity form
411    /// writes nothing at all, because its count is the header's row count, which is section 3.3's
412    /// "no extents beyond the header" in code rather than in prose.
413    pub(crate) fn write_body(&self, out: &mut Vec<u8>) -> Result<()> {
414        match &self.body {
415            Body::Identity { .. } => Ok(()),
416            Body::Dense { range, bits, rank, .. } => {
417                out.extend_from_slice(&range.to_le_bytes());
418                for word in bits {
419                    out.extend_from_slice(&word.to_le_bytes());
420                }
421                rank.write(out);
422                Ok(())
423            }
424            Body::Sorted { key_width, keys, rid_width, perm, .. } => {
425                // The widths are a byte each, and a width past sixty four is a width no `u64` key
426                // offset can have taken, so it is a torn header rather than a wide key.
427                let widths = [*key_width, *rid_width];
428                for width in widths {
429                    let width = u8::try_from(width)
430                        .map_err(|_| malformed("a sorted key map's width does not fit a byte"))?;
431                    out.push(width);
432                }
433                out.extend_from_slice(keys);
434                out.extend_from_slice(perm);
435                Ok(())
436            }
437        }
438    }
439
440    /// Reads back what [`KeyMap::write_body`] wrote, and fills in the maximum key.
441    ///
442    /// The maximum is not in the header because each form derives it: identity from its count,
443    /// dense from its range, sorted from its last stored key. That is the whole reason this takes
444    /// [`Observed`] and returns a map rather than taking a finished one.
445    ///
446    /// # Errors
447    ///
448    /// If the body is not exactly the length its header implies. Exactly, not at least: a body
449    /// longer than its form needs means the header and the body disagree about which form this is,
450    /// and the safe reading of a disagreement is neither of them.
451    pub(crate) fn read_body(
452        form: Form,
453        base: i128,
454        mut observed: Observed,
455        body: &[u8],
456    ) -> Result<Self> {
457        match form {
458            Form::Identity => {
459                if !body.is_empty() {
460                    return Err(malformed("an identity key map has no body"));
461                }
462                if observed.rows > 0 {
463                    observed.max = Some(
464                        base.checked_add(i128::from(observed.rows) - 1)
465                            .ok_or_else(|| malformed("an identity key map's range overflows"))?,
466                    );
467                }
468                Ok(Self { body: Body::Identity { base, count: observed.rows }, observed })
469            }
470            Form::Dense => {
471                let Some(head) = body.get(..size_of::<u64>()) else {
472                    return Err(malformed("a dense key map has no range"));
473                };
474                let range = u64::from_le_bytes(head.try_into().expect("eight bytes"));
475                let Ok(range_usize) = usize::try_from(range) else {
476                    return Err(malformed("a dense key map's range does not fit this machine"));
477                };
478                let words = range_usize.div_ceil(64);
479                let bitmap = words * size_of::<u64>();
480                let rest = &body[size_of::<u64>()..];
481                if rest.len() < bitmap {
482                    return Err(malformed("a dense key map's bitmap is shorter than its range"));
483                }
484                let bits: Vec<u64> = rest[..bitmap]
485                    .chunks_exact(size_of::<u64>())
486                    .map(|word| u64::from_le_bytes(word.try_into().expect("eight bytes")))
487                    .collect();
488                let rank = Rank::read(&rest[bitmap..], words)?;
489                observed.max = Some(
490                    base.checked_add(i128::from(range) - 1)
491                        .ok_or_else(|| malformed("a dense key map's range overflows"))?,
492                );
493                Ok(Self { body: Body::Dense { base, range, bits, rank }, observed })
494            }
495            Form::Sorted => {
496                if body.len() < 2 {
497                    return Err(malformed("a sorted key map has no widths"));
498                }
499                let key_width = usize::from(body[0]);
500                let rid_width = usize::from(body[1]);
501                if key_width == 0 || key_width > 64 || rid_width == 0 || rid_width > 64 {
502                    return Err(malformed("a sorted key map's width is not one a u64 can take"));
503                }
504                let count = observed.rows;
505                let Ok(count_usize) = usize::try_from(count) else {
506                    return Err(malformed(
507                        "a sorted key map holds more keys than this machine can",
508                    ));
509                };
510                let key_bytes = (count_usize * key_width).div_ceil(8);
511                let perm_bytes = (count_usize * rid_width).div_ceil(8);
512                let rest = &body[2..];
513                if rest.len() != key_bytes + perm_bytes {
514                    return Err(malformed(
515                        "a sorted key map's arrays are not the size its widths and count imply",
516                    ));
517                }
518                let keys = rest[..key_bytes].to_vec();
519                let perm = rest[key_bytes..].to_vec();
520                if count > 0 {
521                    let largest = bitpack::tail_at(&keys, key_width, count_usize - 1)?;
522                    observed.max =
523                        Some(base.checked_add(i128::from(largest)).ok_or_else(|| {
524                            malformed("a sorted key map's largest key overflows")
525                        })?);
526                }
527                Ok(Self {
528                    body: Body::Sorted { base, key_width, keys, rid_width, perm, count },
529                    observed,
530                })
531            }
532        }
533    }
534
535    /// Keys this map resolves.
536    #[must_use]
537    pub fn len(&self) -> u64 {
538        match &self.body {
539            Body::Identity { count, .. } | Body::Sorted { count, .. } => *count,
540            Body::Dense { .. } => self.observed.rows,
541        }
542    }
543
544    /// Whether this map resolves nothing.
545    #[must_use]
546    pub fn is_empty(&self) -> bool {
547        self.len() == 0
548    }
549
550    /// Bytes this map holds resident, for the budget of section 3.7 and the cache of section 4.4.
551    ///
552    /// Identity is twenty four bytes and says so, which is the number that makes the budget
553    /// livable on TPC-H.
554    #[must_use]
555    pub fn bytes(&self) -> usize {
556        match &self.body {
557            Body::Identity { .. } => size_of::<i128>() + size_of::<u64>(),
558            Body::Dense { bits, rank, .. } => bits.len() * size_of::<u64>() + rank.bytes(),
559            Body::Sorted { keys, perm, .. } => keys.len() + perm.len(),
560        }
561    }
562
563    /// The `rid` of the row holding this key, or `None` when no row holds it.
564    ///
565    /// `None` is the ordinary answer and not an exceptional one: a child key with no matching
566    /// parent is what section 2.4 reserves *no parent* for, and a null child key never reaches
567    /// here at all.
568    ///
569    /// # Errors
570    ///
571    /// If a bit packed payload is torn, which is a corrupt section rather than a missing key.
572    pub fn lookup(&self, key: i128) -> Result<Option<Rid>> {
573        match &self.body {
574            Body::Identity { base, count } => {
575                let Some(offset) = key.checked_sub(*base) else {
576                    return Ok(None);
577                };
578                match u64::try_from(offset) {
579                    Ok(rid) if rid < *count => Ok(Some(rid)),
580                    _ => Ok(None),
581                }
582            }
583            Body::Dense { base, range, bits, rank } => {
584                let Some(offset) = key.checked_sub(*base) else {
585                    return Ok(None);
586                };
587                let Ok(offset) = u64::try_from(offset) else {
588                    return Ok(None);
589                };
590                if offset >= *range {
591                    return Ok(None);
592                }
593                #[expect(
594                    clippy::cast_possible_truncation,
595                    reason = "the build checked the range fits a usize"
596                )]
597                let at = offset as usize;
598                if bits[at / 64] >> (at % 64) & 1 == 0 {
599                    return Ok(None);
600                }
601                Ok(Some(rank.rank(bits, at)))
602            }
603            Body::Sorted { base, key_width, keys, rid_width, perm, count } => {
604                let Some(offset) = key.checked_sub(*base) else {
605                    return Ok(None);
606                };
607                let Ok(wanted) = u64::try_from(offset) else {
608                    return Ok(None);
609                };
610                #[expect(
611                    clippy::cast_possible_truncation,
612                    reason = "the build refused a column wider than a usize of rows"
613                )]
614                let len = *count as usize;
615                // A plain binary search over the packed keys. Branchless in the sense that matters
616                // here, which is that the comparison drives an index rather than a branch to a
617                // different loop, and every probe is one `tail_at` rather than a decode of the
618                // block around it.
619                let mut low = 0_usize;
620                let mut high = len;
621                while low < high {
622                    let mid = low + (high - low) / 2;
623                    let at = bitpack::tail_at(keys, *key_width, mid)?;
624                    if at < wanted {
625                        low = mid + 1;
626                    } else {
627                        high = mid;
628                    }
629                }
630                if low >= len || bitpack::tail_at(keys, *key_width, low)? != wanted {
631                    return Ok(None);
632                }
633                Ok(Some(bitpack::tail_at(perm, *rid_width, low)?))
634            }
635        }
636    }
637}
638
639/// A parent key column that can be read more than once, in `rid` order.
640///
641/// The build wants two passes over a column it does not want to hold, so this is what it reads
642/// instead of a slice: something that can be asked to produce the column again. A file can do that
643/// for the price of a read, and the second read is against pages the first one just warmed.
644///
645/// Values arrive as `Option<i128>`, with `None` for a null. A string key arrives as its dictionary
646/// code rather than as text, per section 2.2, which is why one integer signature covers every key
647/// type rudb has.
648pub trait Keys {
649    /// Calls `each` once per row of the column, in `rid` order.
650    ///
651    /// # Errors
652    ///
653    /// If the column cannot be read, or if `each` fails, which stops the scan rather than
654    /// continuing past a value that could not be used.
655    fn scan(&self, each: &mut dyn FnMut(Option<i128>) -> Result<()>) -> Result<()>;
656}
657
658impl Keys for [Option<i128>] {
659    fn scan(&self, each: &mut dyn FnMut(Option<i128>) -> Result<()>) -> Result<()> {
660        for key in self {
661            each(*key)?;
662        }
663        Ok(())
664    }
665}
666
667/// Which form the build chose, decided once and carried out twice.
668///
669/// Separating the decision from the filling is what lets [`KeyMap::build`] and
670/// [`KeyMap::build_from`] be the same build. A second copy of these three conditions is a second
671/// place for the positional guard below to be got wrong.
672enum Plan {
673    Empty,
674    Identity { base: i128, count: u64 },
675    Dense { base: i128, range: u64 },
676    Sorted { base: i128 },
677}
678
679/// Picks the cheapest form that is correct for what the column turned out to hold.
680fn plan(observed: &Observed) -> Result<Plan> {
681    // A column with no keys in it at all is an identity map over nothing. It is worth having rather
682    // than refusing, because an empty parent table is a legal table and a join against it returns
683    // no rows rather than failing.
684    if observed.rows == 0 {
685        return Ok(Plan::Empty);
686    }
687    let (Some(min), Some(max)) = (observed.min, observed.max) else {
688        // A non-zero row count guarantees both, so this is unreachable. It is an error rather than
689        // an `expect` because a key map that panicked on its own bookkeeping would take down a
690        // query that section 3.1 promises can always be answered without it.
691        return Err(malformed("a column with keys in it reported no minimum"));
692    };
693    let range = range_of(min, max)?;
694
695    // Both of the cheap forms answer with a *count of keys below the value*, and both are correct
696    // only where that count is the `rid`. It is the `rid` when the column is ascending and holds no
697    // nulls, and it is not otherwise: a null earlier in the column, or a value out of order, shifts
698    // every row after it. Getting this wrong would not fail, it would resolve every key to a
699    // neighbour of the right row, which is the one failure mode section 3.1 does not catch for
700    // free. So the guard is shared and stated once.
701    let positional = observed.distinct && observed.sorted && observed.nulls == 0;
702
703    if positional && range == observed.rows {
704        // Identity needs more than positional: it needs the values to be exactly the positions,
705        // which on a distinct ascending column is the range equalling the row count. The check is
706        // subtraction rather than a walk because the walk already happened in the observation.
707        return Ok(Plan::Identity { base: min, count: observed.rows });
708    }
709
710    // The bitmap is over the value range, so a range that does not fit a `usize` cannot be one
711    // however dense it is.
712    if positional && usize::try_from(range).is_ok() && range / observed.rows < DENSE_THRESHOLD {
713        return Ok(Plan::Dense { base: min, range });
714    }
715
716    Ok(Plan::Sorted { base: min })
717}
718
719/// The four facts section 3.3 says the build records, accumulated one value at a time.
720///
721/// One value at a time rather than one column at a time so that the pass can be driven by a scan
722/// of a file as easily as by a slice. See [`KeyMap::build_from`] for why that matters.
723struct Observer {
724    observed: Observed,
725    previous: Option<i128>,
726}
727
728impl Observer {
729    fn new() -> Self {
730        Self {
731            observed: Observed {
732                rows: 0,
733                nulls: 0,
734                distinct: true,
735                sorted: true,
736                min: None,
737                max: None,
738            },
739            previous: None,
740        }
741    }
742
743    // Distinctness on a column that is not sorted cannot be settled in one pass without a set, so
744    // this settles it for the sorted case and leaves the unsorted case to the sort that the sorted
745    // form does anyway. That is why `distinct` is fixed up in `sorted` below rather than being
746    // final here, and it is worth the awkwardness: the common case on real keys is ascending, and a
747    // hash set over fifteen million rows to discover what adjacency already proves is the build
748    // cost this avoids.
749    fn push(&mut self, key: Option<i128>) {
750        let Some(key) = key else {
751            self.observed.nulls += 1;
752            return;
753        };
754        self.observed.rows += 1;
755        self.observed.min = Some(self.observed.min.map_or(key, |held| held.min(key)));
756        self.observed.max = Some(self.observed.max.map_or(key, |held| held.max(key)));
757        if let Some(previous) = self.previous {
758            if key < previous {
759                self.observed.sorted = false;
760            } else if key == previous {
761                self.observed.distinct = false;
762            }
763        }
764        self.previous = Some(key);
765    }
766}
767
768/// One pass over the column, recording the four facts section 3.3 says the build records.
769fn observe(keys: &[Option<i128>]) -> Observed {
770    let mut observer = Observer::new();
771    for key in keys {
772        observer.push(*key);
773    }
774    observer.observed
775}
776
777/// How many distinct values lie between `min` and `max` inclusive.
778///
779/// The arithmetic is in `u128` and not `i128` because a column holding both `i128::MIN` and
780/// `i128::MAX` has a range of `2^128`, and `max - min` on an `i128` for that column is an overflow
781/// rather than a number. A `HUGEINT` key column spanning more than a `u64` of values is pathological
782/// but legal, so it gets an error naming what happened rather than a panic in a build: the caller
783/// records the relationship as not built, exactly as it does for one that does not fit the budget.
784///
785/// `max >= min` always holds here, so the wrapping subtraction is exact in `u128`.
786fn range_of(min: i128, max: i128) -> Result<u64> {
787    let span = max.wrapping_sub(min) as u128;
788    u64::try_from(span)
789        .ok()
790        .and_then(|span| span.checked_add(1))
791        .ok_or_else(|| malformed("the key column spans more than a u64 of values"))
792}
793
794/// The offset a key takes from the base.
795///
796/// `range_of` bounded the span to a `u64` before either form that uses this was chosen, so the
797/// subtraction cannot overflow and the offset cannot exceed a `u64`. Both are checked anyway: this
798/// is the one arithmetic in the crate whose silent failure would resolve keys to the wrong rows.
799fn offset_of(key: i128, base: i128) -> Result<u64> {
800    let offset = key
801        .checked_sub(base)
802        .ok_or_else(|| malformed("a key is further from the base than an i128 holds"))?;
803    u64::try_from(offset)
804        .map_err(|_| malformed("a key is below the base or further from it than a u64 holds"))
805}
806
807/// Builds the bitmap form one key at a time.
808///
809/// The caller guarantees the column is distinct, ascending and null free, which is what makes a
810/// rank equal to a `rid`. The assertion restates it where the correctness depends on it rather than
811/// where the decision was made.
812struct DenseBits {
813    base: i128,
814    range: u64,
815    bits: Vec<u64>,
816    previous: Option<i128>,
817}
818
819impl DenseBits {
820    fn new(base: i128, range: u64) -> Self {
821        #[expect(
822            clippy::cast_possible_truncation,
823            reason = "the caller checked the range fits a usize"
824        )]
825        let range_usize = range as usize;
826        Self { base, range, bits: vec![0_u64; range_usize.div_ceil(64)], previous: None }
827    }
828
829    fn push(&mut self, key: i128) -> Result<()> {
830        debug_assert!(
831            self.previous.is_none_or(|held| key > held),
832            "the bitmap form needs a distinct ascending column, because a rank is a count of keys below a value and that is a rid only there"
833        );
834        self.previous = Some(key);
835        let offset = offset_of(key, self.base)?;
836        #[expect(
837            clippy::cast_possible_truncation,
838            reason = "the caller checked the range fits a usize and the offset is inside it"
839        )]
840        let at = offset as usize;
841        self.bits[at / 64] |= 1 << (at % 64);
842        Ok(())
843    }
844
845    fn finish(self) -> Body {
846        let rank = Rank::build(&self.bits);
847        Body::Dense { base: self.base, range: self.range, bits: self.bits, rank }
848    }
849}
850
851fn dense(keys: &[Option<i128>], base: i128, range: u64) -> Result<Body> {
852    let mut bits = DenseBits::new(base, range);
853    for key in keys.iter().flatten() {
854        bits.push(*key)?;
855    }
856    Ok(bits.finish())
857}
858
859/// Builds the general form, and settles distinctness on the way.
860///
861/// Returns the body and whether every key was distinct. The second is not a courtesy: the sort this
862/// form performs is the only place a duplicate that is not adjacent in the column can be seen, and
863/// section 2.3 needs that answer to decide whether a link may be built at all.
864fn sorted(keys: &[Option<i128>], base: i128, rows: u64) -> Result<(Body, bool)> {
865    let mut pairs: Vec<(u64, u64)> = Vec::with_capacity(keys.len());
866    for (rid, key) in keys.iter().enumerate() {
867        let Some(key) = *key else { continue };
868        let offset = offset_of(key, base)?;
869        let rid = u64::try_from(rid).map_err(|_| malformed("the column is too long for a rid"))?;
870        pairs.push((offset, rid));
871    }
872    // Sorted by key, then by rid so that a duplicated key resolves to its first row rather than to
873    // whichever one the sort happened to leave first. A duplicated key means no link gets built, so
874    // this only decides what a map nobody should be using returns, and deciding it anyway is what
875    // keeps a test of this form reproducible.
876    pairs.sort_unstable();
877    let distinct = pairs.windows(2).all(|pair| pair[0].0 != pair[1].0);
878    debug_assert_eq!(
879        u64::try_from(pairs.len()).ok(),
880        Some(rows),
881        "the pair list is the non-null column"
882    );
883    let key_width = width_for(pairs.last().map_or(0, |pair| pair.0));
884    let rows_width = u64::try_from(keys.len().saturating_sub(1))
885        .map_err(|_| malformed("the column is too long for a rid"))?;
886    let rid_width = width_for(rows_width);
887    let mut key_bytes = Vec::new();
888    let mut rid_bytes = Vec::new();
889    let key_values: Vec<u64> = pairs.iter().map(|pair| pair.0).collect();
890    let rid_values: Vec<u64> = pairs.iter().map(|pair| pair.1).collect();
891    // The linear packer and not the tail one, because a tail is bounded at a thousand values and a
892    // parent key column is not. The layout is the same and `tail_at` reads either.
893    bitpack::pack_linear(&key_values, key_width, &mut key_bytes)?;
894    bitpack::pack_linear(&rid_values, rid_width, &mut rid_bytes)?;
895    Ok((
896        Body::Sorted { base, key_width, keys: key_bytes, rid_width, perm: rid_bytes, count: rows },
897        distinct,
898    ))
899}
900
901/// Bits needed to hold every value up to and including `largest`.
902///
903/// One rather than zero for a largest of zero, because a width of zero is a packed payload with no
904/// bytes in it and `tail_at` on one of those has nothing to return. A column of a single key is a
905/// real column.
906fn width_for(largest: u64) -> usize {
907    let bits = u64::BITS - largest.leading_zeros();
908    bits.max(1) as usize
909}
910
911fn malformed(message: impl Into<String>) -> Error {
912    Error::invalid_input(format!("invalid rudb key map: {}", message.into()))
913}
914
915#[cfg(test)]
916mod tests {
917    use super::*;
918
919    fn keys(values: &[i128]) -> Vec<Option<i128>> {
920        values.iter().copied().map(Some).collect()
921    }
922
923    /// Every key in the column resolves to the row that holds it, whatever form was chosen.
924    fn resolves(column: &[Option<i128>], map: &KeyMap) {
925        for (rid, key) in column.iter().enumerate() {
926            let Some(key) = *key else { continue };
927            let found = map.lookup(key).expect("lookup").expect("a key in the column resolves");
928            assert_eq!(found, rid as u64, "key {key} resolved to {found} rather than {rid}");
929        }
930    }
931
932    #[test]
933    fn a_sequence_from_one_is_the_identity_form_and_stores_two_numbers() {
934        // TPC-H's `region`, `nation`, `supplier`, `customer`, `part` and `orders` all land here,
935        // which is the case the whole budget in section 3.7 depends on.
936        let column = keys(&(1..=1000).collect::<Vec<i128>>());
937        let map = KeyMap::build(&column).expect("build");
938        assert_eq!(map.form(), Form::Identity);
939        assert_eq!(map.bytes(), 24, "section 4.2 says identity is twenty four bytes");
940        assert_eq!(map.len(), 1000);
941        resolves(&column, &map);
942        assert_eq!(map.lookup(0).expect("lookup"), None, "below the base");
943        assert_eq!(map.lookup(1001).expect("lookup"), None, "past the end");
944    }
945
946    #[test]
947    fn a_sequence_from_zero_is_also_the_identity_form() {
948        let column = keys(&(0..64).collect::<Vec<i128>>());
949        let map = KeyMap::build(&column).expect("build");
950        assert_eq!(map.form(), Form::Identity);
951        resolves(&column, &map);
952    }
953
954    #[test]
955    fn a_sequence_with_a_gap_in_it_is_the_dense_form() {
956        // Every other value over a range of two thousand, which is a density of one in two and
957        // comfortably inside the threshold.
958        let column = keys(&(0..1000).map(|value| value * 2).collect::<Vec<i128>>());
959        let map = KeyMap::build(&column).expect("build");
960        assert_eq!(map.form(), Form::Dense);
961        resolves(&column, &map);
962        assert_eq!(
963            map.lookup(1).expect("lookup"),
964            None,
965            "a value in the range and not in the column"
966        );
967        assert_eq!(map.lookup(2001).expect("lookup"), None, "past the range");
968    }
969
970    #[test]
971    fn a_range_too_sparse_for_a_bitmap_is_the_sorted_form() {
972        // A thousand keys spread over a million, which is a density of one in a thousand: the
973        // bitmap would be 125 KB to hold a thousand values and the sorted form is a few kilobytes.
974        let column = keys(&(0..1000).map(|value| value * 1000).collect::<Vec<i128>>());
975        let map = KeyMap::build(&column).expect("build");
976        assert_eq!(map.form(), Form::Sorted);
977        resolves(&column, &map);
978        assert_eq!(map.lookup(500).expect("lookup"), None);
979    }
980
981    #[test]
982    fn the_sorted_form_is_not_bounded_by_a_packed_unit() {
983        // The sorted form packs its keys and its permutation sequentially, and the sequential
984        // packer a column uses is for the remainder past the last transposed unit, so it refuses a
985        // thousand and twenty four values. A parent key column is sixty times that at SF1 and
986        // fifteen thousand times it at SF10, so the form would exist only for toy tables. This is
987        // the smallest column that would have hit it.
988        let column = keys(&(0..5000).map(|value| (value * 7919) % 100_003).collect::<Vec<i128>>());
989        let map = KeyMap::build(&column).expect("build");
990        assert_eq!(map.form(), Form::Sorted);
991        resolves(&column, &map);
992    }
993
994    #[test]
995    fn keys_in_no_order_at_all_resolve_to_the_rows_that_hold_them() {
996        // The case the permutation exists for. The column is not sorted, so the sorted form's
997        // position is not the rid, and a map that confused the two would resolve every key to the
998        // wrong row while looking exactly like a working map.
999        let column = keys(&[500, 3, 9000, 12, 7, 88, 41, 6]);
1000        let map = KeyMap::build(&column).expect("build");
1001        assert_eq!(map.form(), Form::Sorted);
1002        resolves(&column, &map);
1003    }
1004
1005    #[test]
1006    fn a_descending_column_dense_enough_for_a_bitmap_still_resolves_correctly() {
1007        // The trap in the dense form: a bitmap is in value order, so a rank is a position in value
1008        // order, and on a descending column that is not the rid. `dense` detects it and falls back.
1009        let column = keys(&(0..500).rev().collect::<Vec<i128>>());
1010        let map = KeyMap::build(&column).expect("build");
1011        assert_eq!(map.form(), Form::Sorted, "a descending column cannot take the bitmap");
1012        resolves(&column, &map);
1013    }
1014
1015    #[test]
1016    fn nulls_are_not_keys_and_do_not_shift_the_rows_around_them() {
1017        // This column is distinct, ascending, and dense enough for a bitmap on the numbers alone:
1018        // three keys over a range of twenty one. It cannot have one, because a rank counts keys
1019        // below a value and the nulls in between mean that count is not the row's position. A map
1020        // that took the bitmap here would resolve key 20 to row 1 and look entirely healthy doing
1021        // it.
1022        let column = vec![Some(10), None, Some(20), None, Some(30)];
1023        let map = KeyMap::build(&column).expect("build");
1024        assert_eq!(
1025            map.form(),
1026            Form::Sorted,
1027            "a null before a key shifts it out of the cheap forms"
1028        );
1029        resolves(&column, &map);
1030        assert_eq!(map.observed().nulls, 2);
1031        assert_eq!(map.observed().rows, 3);
1032        assert_eq!(
1033            map.lookup(20).expect("lookup"),
1034            Some(2),
1035            "the rid is the position in the column"
1036        );
1037    }
1038
1039    #[test]
1040    fn a_leading_null_keeps_an_otherwise_perfect_sequence_out_of_the_identity_form() {
1041        // The same trap on the form that would otherwise be free. Worth its own test because a
1042        // sequence from one is the case every TPC-H table hits, and the version of it with a null
1043        // in front is one `INSERT` away.
1044        let mut column = vec![None];
1045        column.extend((1..=1000).map(Some));
1046        let map = KeyMap::build(&column).expect("build");
1047        assert_ne!(map.form(), Form::Identity);
1048        resolves(&column, &map);
1049        assert_eq!(map.lookup(1).expect("lookup"), Some(1), "row zero is the null, not key one");
1050    }
1051
1052    #[test]
1053    fn a_null_only_column_builds_and_resolves_nothing() {
1054        let column = vec![None, None, None];
1055        let map = KeyMap::build(&column).expect("build");
1056        assert!(map.is_empty());
1057        assert_eq!(map.observed().nulls, 3);
1058        assert_eq!(map.lookup(0).expect("lookup"), None);
1059    }
1060
1061    #[test]
1062    fn an_empty_column_builds_and_resolves_nothing() {
1063        let map = KeyMap::build(&[]).expect("build");
1064        assert!(map.is_empty());
1065        assert_eq!(map.lookup(0).expect("lookup"), None);
1066        assert!(map.observed().usable_as_parent(), "an empty parent is unique, vacuously");
1067    }
1068
1069    #[test]
1070    fn a_duplicated_key_is_reported_rather_than_resolved_to_one_of_its_rows() {
1071        // Section 2.3's verification. The map still builds, because the caller is the one that
1072        // decides what to do about it, and what it decides is to build no link.
1073        let column = keys(&[5, 7, 5, 9]);
1074        let map = KeyMap::build(&column).expect("build");
1075        assert!(!map.observed().distinct);
1076        assert!(!map.observed().usable_as_parent(), "a non-unique parent side takes no link");
1077    }
1078
1079    #[test]
1080    fn a_column_that_arrives_with_its_repeats_together_is_not_sorted_into_a_map() {
1081        // The scan sees the repeat, so nothing is packed. What matters is the bytes: this is
1082        // `lineitem(l_orderkey)`, where the form that would have been chosen holds one packed key
1083        // and one packed permutation entry per row.
1084        let column = keys(&[1, 1, 2, 2, 2, 90_000, 90_000]);
1085        let map = KeyMap::build_from(&column[..]).expect("build");
1086        assert!(!map.observed().distinct);
1087        assert_eq!(map.observed().rows, 7, "the column was still counted");
1088        assert_eq!(map.observed().max, Some(90_000));
1089        assert_eq!(map.bytes(), KeyMap::build(&keys(&[])).expect("build").bytes());
1090        assert_eq!(map.lookup(2).expect("lookup"), None, "and it answers nothing, as it must");
1091    }
1092
1093    #[test]
1094    fn a_single_key_column_resolves_it() {
1095        // The width of zero case: one key at the base is an offset of zero, and a packed payload of
1096        // width zero has no bytes for `tail_at` to read.
1097        let column = keys(&[42]);
1098        let map = KeyMap::build(&column).expect("build");
1099        resolves(&column, &map);
1100        assert_eq!(map.lookup(41).expect("lookup"), None);
1101        assert_eq!(map.lookup(43).expect("lookup"), None);
1102    }
1103
1104    #[test]
1105    fn negative_keys_resolve_because_the_base_is_the_minimum_and_not_zero() {
1106        let column = keys(&[-9000, -3, -1, 0, 7]);
1107        let map = KeyMap::build(&column).expect("build");
1108        resolves(&column, &map);
1109        assert_eq!(map.lookup(-9001).expect("lookup"), None);
1110    }
1111
1112    #[test]
1113    fn a_column_spanning_more_than_a_u64_of_values_is_refused_and_not_panicked_over() {
1114        // `max - min` on a HUGEINT column holding both ends of the type overflows an i128, so this
1115        // is where a build panics if the range arithmetic is done in the column's own type. It is
1116        // refused instead, and the caller records the relationship as not built.
1117        let column = keys(&[i128::MIN, 0, i128::MAX]);
1118        let error = KeyMap::build(&column).expect_err("refused");
1119        assert!(error.to_string().contains("spans more than a u64"), "{error}");
1120    }
1121
1122    #[test]
1123    fn keys_at_the_far_end_of_the_integer_type_resolve_when_their_range_is_narrow() {
1124        // The other half of the same arithmetic: the values are extreme and the range is not, which
1125        // is a column a key map has to handle rather than refuse.
1126        let column = keys(&[i128::MIN, i128::MIN + 5, i128::MIN + 2]);
1127        let map = KeyMap::build(&column).expect("build");
1128        resolves(&column, &map);
1129        assert_eq!(map.lookup(i128::MAX).expect("lookup"), None);
1130        assert_eq!(map.lookup(0).expect("lookup"), None);
1131    }
1132
1133    #[test]
1134    fn the_rank_index_agrees_with_counting_the_bits_by_hand() {
1135        // The rank structure is two levels and an eight word popcount, and an off by one in any of
1136        // the three resolves every key past the fault to the row before or after the right one. So
1137        // it is checked against the naive count over a bitmap wide enough to use every level: 4096
1138        // bits is one superblock exactly, so 20,000 forces five of them and the last one partial.
1139        let column = keys(&(0..10_000).map(|value| value * 2).collect::<Vec<i128>>());
1140        let map = KeyMap::build(&column).expect("build");
1141        assert_eq!(map.form(), Form::Dense);
1142        resolves(&column, &map);
1143    }
1144
1145    #[test]
1146    fn a_string_key_arrives_as_dictionary_codes_and_never_as_text() {
1147        // Section 2.2's composition with the global dictionary. There is nothing string shaped in
1148        // this crate and that is the point: the codes of a file wide stable dictionary carry the
1149        // column's own order, so a sorted key map over a VARCHAR is this and the search is over
1150        // integers.
1151        let codes = keys(&[7, 1, 4, 9, 2]);
1152        let map = KeyMap::build(&codes).expect("build");
1153        resolves(&codes, &map);
1154    }
1155
1156    #[test]
1157    fn the_form_tag_round_trips_and_an_unknown_one_is_refused() {
1158        for form in [Form::Identity, Form::Dense, Form::Sorted] {
1159            assert_eq!(Form::from_tag(form.tag()).expect("a known tag"), form);
1160        }
1161        assert!(Form::from_tag(3).is_err(), "an unfamiliar form is refused rather than guessed");
1162    }
1163
1164    #[test]
1165    fn the_dense_form_costs_a_bitmap_and_about_an_eighth_again() {
1166        // The space claim in section 3.3, checked. A range of 80,000 bits is 10,000 bytes and the
1167        // index is a u16 per 512 bits plus a u32 per 4096, which is about 12.5 percent.
1168        let column = keys(&(0..10_000).map(|value| value * 8).collect::<Vec<i128>>());
1169        let map = KeyMap::build(&column).expect("build");
1170        assert_eq!(map.form(), Form::Dense);
1171        let bitmap = 80_000 / 8;
1172        let bytes = map.bytes();
1173        assert!(bytes > bitmap, "the map took {bytes} bytes and the bitmap alone is {bitmap}");
1174        assert!(
1175            bytes < bitmap * 5 / 4,
1176            "the map took {bytes} bytes, more than a quarter over the bitmap's {bitmap}"
1177        );
1178    }
1179
1180    /// A column that counts how many times it was read, so a test can say what a build cost.
1181    struct Counted {
1182        column: Vec<Option<i128>>,
1183        scans: std::cell::Cell<usize>,
1184    }
1185
1186    impl Keys for Counted {
1187        fn scan(&self, each: &mut dyn FnMut(Option<i128>) -> Result<()>) -> Result<()> {
1188            self.scans.set(self.scans.get() + 1);
1189            self.column.scan(each)
1190        }
1191    }
1192
1193    #[test]
1194    fn a_build_from_a_scan_is_the_same_map_as_a_build_from_a_slice() {
1195        // The two builds have to agree on every column, because the streaming one is not a second
1196        // implementation, it is the same decision carried out against a source that is read twice.
1197        // If these ever disagree, a table's key map depends on which path built it.
1198        let columns: Vec<Vec<Option<i128>>> = vec![
1199            Vec::new(),
1200            keys(&[]),
1201            keys(&(1..=1000).collect::<Vec<i128>>()),
1202            keys(&(0..500).map(|value| value * 4).collect::<Vec<i128>>()),
1203            keys(&[100, 3, 40, 7, 9000]),
1204            keys(&[5, 5, 9]),
1205            vec![Some(10), None, Some(20), None, Some(30)],
1206            vec![None, None],
1207        ];
1208        for column in &columns {
1209            let held = KeyMap::build(column).expect("build from a slice");
1210            let read = KeyMap::build_from(&column[..]).expect("build from a scan");
1211            assert_eq!(read.form(), held.form(), "{column:?}");
1212            assert_eq!(read.observed(), held.observed(), "{column:?}");
1213            assert_eq!(read.len(), held.len(), "{column:?}");
1214            assert_eq!(read.bytes(), held.bytes(), "{column:?}");
1215            // A column with a repeat in it has no one right row for its key, which is exactly why
1216            // section 2.3 refuses to build a link on one. So the round trip is checked where the
1217            // question has an answer.
1218            if read.observed().usable_as_parent() {
1219                resolves(column, &read);
1220            }
1221        }
1222    }
1223
1224    #[test]
1225    fn the_identity_form_is_built_without_reading_the_column_twice() {
1226        // The reason `build_from` exists. Every TPC-H parent key takes the identity form, and the
1227        // identity form is two numbers, so a build of one has no business holding fifteen million
1228        // values or reading them a second time.
1229        let identity =
1230            Counted { column: keys(&(1..=1000).collect::<Vec<i128>>()), scans: 0.into() };
1231        assert_eq!(KeyMap::build_from(&identity).expect("build").form(), Form::Identity);
1232        assert_eq!(
1233            identity.scans.get(),
1234            1,
1235            "the identity form is the observation and nothing more"
1236        );
1237
1238        // The other two forms have something to fill, so they read it again, and once is the number
1239        // that matters: a form that scanned per value would be a build nobody could afford.
1240        let dense = Counted {
1241            column: keys(&(0..500).map(|v| v * 4).collect::<Vec<i128>>()),
1242            scans: 0.into(),
1243        };
1244        assert_eq!(KeyMap::build_from(&dense).expect("build").form(), Form::Dense);
1245        assert_eq!(dense.scans.get(), 2);
1246
1247        let sorted = Counted { column: keys(&[100, 3, 40, 7, 9000]), scans: 0.into() };
1248        assert_eq!(KeyMap::build_from(&sorted).expect("build").form(), Form::Sorted);
1249        assert_eq!(sorted.scans.get(), 2);
1250    }
1251
1252    #[test]
1253    fn a_scan_that_fails_stops_the_build_rather_than_half_finishing_it() {
1254        struct Broken;
1255        impl Keys for Broken {
1256            fn scan(&self, _: &mut dyn FnMut(Option<i128>) -> Result<()>) -> Result<()> {
1257                Err(malformed("the column could not be read"))
1258            }
1259        }
1260        let error = KeyMap::build_from(&Broken).expect_err("a build over an unreadable column");
1261        assert!(error.to_string().contains("could not be read"), "{error}");
1262    }
1263}