Skip to main content

lance_table/
rowids.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3//! Indices for mapping row ids to their corresponding addresses.
4//!
5//! Each fragment in a table has a [RowIdSequence] that contains the row ids
6//! in the order they appear in the fragment. The [RowIdIndex] aggregates these
7//! sequences and maps row ids to their corresponding addresses across the
8//! whole dataset.
9//!
10//! [RowIdSequence]s are serialized individually and stored in the fragment
11//! metadata. Use [read_row_ids] and [write_row_ids] to read and write these
12//! sequences. The on-disk format is designed to align well with the in-memory
13//! representation, to avoid unnecessary deserialization.
14use std::ops::{Range, RangeInclusive};
15// TODO: replace this with Arrow BooleanBuffer.
16
17// These are all internal data structures, and are private.
18mod bitmap;
19mod encoded_array;
20mod index;
21pub mod segment;
22mod serde;
23pub mod version;
24
25use lance_core::deepsize::DeepSizeOf;
26// These are the public API.
27pub use index::FragmentRowIdIndex;
28pub use index::RowIdIndex;
29use lance_core::{Error, Result};
30use lance_io::ReadBatchParams;
31use lance_select::{RowAddrMask, RowAddrTreeMap, RowSetOps};
32pub use serde::{read_row_ids, write_row_ids};
33
34use crate::utils::LanceIteratorExtension;
35use segment::{SegmentCursorState, U64Segment};
36use tracing::instrument;
37
38/// A sequence of row ids.
39///
40/// Row ids are u64s that:
41///
42/// 1. Are **unique** within a table (except for tombstones)
43/// 2. Are *often* but not always sorted and/or contiguous.
44///
45/// This sequence of row ids is optimized to be compact when the row ids are
46/// contiguous and sorted. However, it does not require that the row ids are
47/// contiguous or sorted.
48///
49/// We can make optimizations that assume uniqueness.
50#[derive(Debug, Clone, DeepSizeOf, PartialEq, Eq, Default)]
51pub struct RowIdSequence(Vec<U64Segment>);
52
53/// Stateful reader for selections that usually advance through a sequence.
54///
55/// Streaming readers reuse this cursor across record batches. If a later
56/// selection moves backwards then the cursor rewinds before continuing.
57#[derive(Debug, Default)]
58pub(crate) struct RowIdSequenceCursor {
59    segment_idx: usize,
60    rows_passed: usize,
61    segment_len: Option<usize>,
62    segment_cursor: SegmentCursorState,
63    last_index: Option<usize>,
64}
65
66impl RowIdSequenceCursor {
67    fn advance_segment(&mut self) {
68        self.rows_passed += self.segment_len.unwrap_or_default();
69        self.segment_idx += 1;
70        self.segment_len = None;
71        self.segment_cursor = SegmentCursorState::default();
72    }
73
74    fn get(&mut self, sequence: &RowIdSequence, index: usize) -> Option<u64> {
75        if index < self.rows_passed || self.last_index.is_some_and(|last| index < last) {
76            *self = Self::default();
77        }
78        self.last_index = Some(index);
79
80        loop {
81            let segment = sequence.0.get(self.segment_idx)?;
82            let segment_len = *self.segment_len.get_or_insert_with(|| segment.len());
83            let local_index = index - self.rows_passed;
84            if local_index < segment_len {
85                return self.segment_cursor.get(segment, local_index);
86            }
87            self.advance_segment();
88        }
89    }
90
91    fn extend_range(
92        &mut self,
93        sequence: &RowIdSequence,
94        selection: Range<usize>,
95        row_ids: &mut Vec<u64>,
96    ) {
97        if selection.is_empty() {
98            return;
99        }
100        if selection.start < self.rows_passed
101            || self.last_index.is_some_and(|last| selection.start < last)
102        {
103            *self = Self::default();
104        }
105        self.last_index = Some(selection.end - 1);
106
107        let mut index = selection.start;
108        while index < selection.end {
109            let Some(segment) = sequence.0.get(self.segment_idx) else {
110                break;
111            };
112            let segment_len = *self.segment_len.get_or_insert_with(|| segment.len());
113            let local_start = index - self.rows_passed;
114            if local_start >= segment_len {
115                self.advance_segment();
116                continue;
117            }
118
119            let count = (selection.end - index).min(segment_len - local_start);
120            let local_end = local_start + count;
121            self.segment_cursor
122                .extend_range(segment, local_start..local_end, row_ids);
123            index += count;
124            if local_end == segment_len {
125                self.advance_segment();
126            }
127        }
128    }
129
130    // Keep the sparse loop in `extend_range` unchanged. Sharing this loop with
131    // the dense decoder measurably slows sparse system-only scans.
132    fn extend_dense_range(
133        &mut self,
134        sequence: &RowIdSequence,
135        selection: Range<usize>,
136        row_ids: &mut Vec<u64>,
137    ) {
138        if selection.is_empty() {
139            return;
140        }
141        if selection.start < self.rows_passed
142            || self.last_index.is_some_and(|last| selection.start < last)
143        {
144            *self = Self::default();
145        }
146        self.last_index = Some(selection.end - 1);
147
148        let mut index = selection.start;
149        while index < selection.end {
150            let Some(segment) = sequence.0.get(self.segment_idx) else {
151                break;
152            };
153            let segment_len = *self.segment_len.get_or_insert_with(|| segment.len());
154            let local_start = index - self.rows_passed;
155            if local_start >= segment_len {
156                self.advance_segment();
157                continue;
158            }
159
160            let count = (selection.end - index).min(segment_len - local_start);
161            let local_end = local_start + count;
162            self.segment_cursor
163                .extend_dense_range(segment, local_start..local_end, row_ids);
164            index += count;
165            if local_end == segment_len {
166                self.advance_segment();
167            }
168        }
169    }
170}
171
172impl std::fmt::Display for RowIdSequence {
173    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174        let mut iter = self.iter();
175        let mut first_10 = Vec::new();
176        let mut last_10 = Vec::new();
177        for row_id in iter.by_ref() {
178            first_10.push(row_id);
179            if first_10.len() > 10 {
180                break;
181            }
182        }
183
184        while let Some(row_id) = iter.next_back() {
185            last_10.push(row_id);
186            if last_10.len() > 10 {
187                break;
188            }
189        }
190        last_10.reverse();
191
192        let theres_more = iter.next().is_some();
193
194        write!(f, "[")?;
195        for row_id in first_10 {
196            write!(f, "{}", row_id)?;
197        }
198        if theres_more {
199            write!(f, ", ...")?;
200        }
201        for row_id in last_10 {
202            write!(f, ", {}", row_id)?;
203        }
204        write!(f, "]")
205    }
206}
207
208impl From<Range<u64>> for RowIdSequence {
209    fn from(range: Range<u64>) -> Self {
210        Self(vec![U64Segment::Range(range)])
211    }
212}
213
214impl From<&[u64]> for RowIdSequence {
215    fn from(row_ids: &[u64]) -> Self {
216        Self(vec![U64Segment::from_slice(row_ids)])
217    }
218}
219
220/// Return some value that appears more than once in `row_ids`, if any.
221///
222/// The already-sorted case is the common one for row id sequences, and is
223/// checked in a single pass without allocating.
224fn find_duplicate(row_ids: &[u64]) -> Option<u64> {
225    if row_ids.windows(2).all(|pair| pair[0] < pair[1]) {
226        return None;
227    }
228    let mut sorted = row_ids.to_vec();
229    sorted.sort_unstable();
230    sorted
231        .windows(2)
232        .find(|pair| pair[0] == pair[1])
233        .map(|pair| pair[0])
234}
235
236impl RowIdSequence {
237    pub fn new() -> Self {
238        Self::default()
239    }
240
241    /// Build a sequence from row ids, rejecting duplicates within the sequence.
242    ///
243    /// The segment encodings represent a sorted run as a range plus its holes,
244    /// so a repeated value would be silently encoded as a shorter sequence with
245    /// a spurious hole. Callers assembling a sequence from untrusted input
246    /// should use this instead of the infallible `From` conversions, which
247    /// assume uniqueness.
248    ///
249    /// Row ids must also be unique across the dataset. That is not checked
250    /// here, and commit does not re-check it either.
251    pub fn try_from_iter(row_ids: impl IntoIterator<Item = u64>) -> Result<Self> {
252        let row_ids: Vec<u64> = row_ids.into_iter().collect();
253        if row_ids.is_empty() {
254            return Ok(Self::new());
255        }
256        if let Some(duplicate) = find_duplicate(&row_ids) {
257            return Err(Error::invalid_input(format!(
258                "Row ids must be unique, but row id {} appears more than once in the sequence of {} row ids",
259                duplicate,
260                row_ids.len()
261            )));
262        }
263        Ok(Self(vec![U64Segment::from_iter(row_ids)]))
264    }
265
266    pub fn iter(&self) -> impl DoubleEndedIterator<Item = u64> + '_ {
267        self.0.iter().flat_map(|segment| segment.iter())
268    }
269
270    pub fn len(&self) -> u64 {
271        self.0.iter().map(|segment| segment.len() as u64).sum()
272    }
273
274    pub fn is_empty(&self) -> bool {
275        self.0.is_empty()
276    }
277
278    /// Returns the bounding range `[min, max]` across all row IDs in this sequence,
279    /// or `None` if the sequence contains no values.
280    ///
281    /// This is a conservative bounding box: a value falling within the returned range
282    /// is not guaranteed to exist in the sequence (segments may be sparse), but any
283    /// value that *does* exist is guaranteed to fall within the range.  This makes
284    /// the result suitable as a cheap pre-filter before a full scan.
285    pub fn row_id_range(&self) -> Option<RangeInclusive<u64>> {
286        let min = self
287            .0
288            .iter()
289            .filter_map(|s| s.range())
290            .map(|r| *r.start())
291            .min()?;
292        let max = self
293            .0
294            .iter()
295            .filter_map(|s| s.range())
296            .map(|r| *r.end())
297            .max()?;
298        Some(min..=max)
299    }
300
301    /// Combines this row id sequence with another row id sequence.
302    pub fn extend(&mut self, other: Self) {
303        // If the last element of this sequence and the first element of next
304        // sequence are ranges, we might be able to combine them into a single
305        // range.
306        if let (Some(U64Segment::Range(range1)), Some(U64Segment::Range(range2))) =
307            (self.0.last(), other.0.first())
308            && range1.end == range2.start
309        {
310            let new_range = U64Segment::Range(range1.start..range2.end);
311            self.0.pop();
312            self.0.push(new_range);
313            self.0.extend(other.0.into_iter().skip(1));
314            return;
315        }
316        // TODO: add other optimizations, such as combining two RangeWithHoles.
317        self.0.extend(other.0);
318    }
319
320    /// Remove a set of row ids from the sequence.
321    pub fn delete(&mut self, row_ids: impl IntoIterator<Item = u64>) {
322        // Order the row ids by position in which they appear in the sequence.
323        let (row_ids, offsets) = self.find_ids(row_ids);
324
325        let capacity = self.0.capacity();
326        let old_segments = std::mem::replace(&mut self.0, Vec::with_capacity(capacity));
327        let mut remaining_segments = old_segments.as_slice();
328
329        for (segment_idx, range) in offsets {
330            let segments_handled = old_segments.len() - remaining_segments.len();
331            let segments_to_add = segment_idx - segments_handled;
332            self.0
333                .extend_from_slice(&remaining_segments[..segments_to_add]);
334            remaining_segments = &remaining_segments[segments_to_add..];
335
336            let segment;
337            (segment, remaining_segments) = remaining_segments.split_first().unwrap();
338
339            let segment_ids = &row_ids[range];
340            self.0.push(segment.delete(segment_ids));
341        }
342
343        // Add the remaining segments.
344        self.0.extend_from_slice(remaining_segments);
345    }
346
347    /// Delete row ids by position.
348    pub fn mask(&mut self, positions: impl IntoIterator<Item = u32>) -> Result<()> {
349        let mut local_positions = Vec::new();
350        let mut positions_iter = positions.into_iter();
351        let mut curr_position = positions_iter.next();
352        let mut offset = 0;
353        let mut cutoff = 0;
354
355        for segment in &mut self.0 {
356            // Make vector of local positions
357            cutoff += segment.len() as u32;
358            while let Some(position) = curr_position {
359                if position >= cutoff {
360                    break;
361                }
362                local_positions.push(position - offset);
363                curr_position = positions_iter.next();
364            }
365
366            if !local_positions.is_empty() {
367                segment.mask(&local_positions);
368                local_positions.clear();
369            }
370            offset = cutoff;
371        }
372
373        self.0.retain(|segment| !segment.is_empty());
374
375        Ok(())
376    }
377
378    /// Find the row ids in the sequence.
379    ///
380    /// Returns the row ids sorted by their appearance in the sequence.
381    /// Also returns the segment index and the range where that segment's
382    /// row id matches are found in the returned row id vector.
383    fn find_ids(
384        &self,
385        row_ids: impl IntoIterator<Item = u64>,
386    ) -> (Vec<u64>, Vec<(usize, Range<usize>)>) {
387        // Often, the row ids will already be provided in the order they appear.
388        // So the optimal way to search will be to cycle through rather than
389        // restarting the search from the beginning each time.
390        let mut segment_iter = self.0.iter().enumerate().cycle();
391
392        let mut segment_matches = vec![Vec::new(); self.0.len()];
393
394        row_ids.into_iter().for_each(|row_id| {
395            let mut i = 0;
396            // If we've cycled through all segments, we know the row id is not in the sequence.
397            while i < self.0.len() {
398                let (segment_idx, segment) = segment_iter.next().unwrap();
399                if segment.range().is_some_and(|range| range.contains(&row_id))
400                    && let Some(offset) = segment.position(row_id)
401                {
402                    segment_matches.get_mut(segment_idx).unwrap().push(offset);
403                    // The row id was not found it the segment. It might be in a later segment.
404                }
405                i += 1;
406            }
407        });
408        for matches in &mut segment_matches {
409            matches.sort_unstable();
410        }
411
412        let mut offset = 0;
413        let segment_ranges = segment_matches
414            .iter()
415            .enumerate()
416            .filter(|(_, matches)| !matches.is_empty())
417            .map(|(segment_idx, matches)| {
418                let range = offset..offset + matches.len();
419                offset += matches.len();
420                (segment_idx, range)
421            })
422            .collect();
423        let row_ids = segment_matches
424            .into_iter()
425            .enumerate()
426            .flat_map(|(segment_idx, offset)| {
427                offset
428                    .into_iter()
429                    .map(move |offset| self.0[segment_idx].get(offset).unwrap())
430            })
431            .collect();
432
433        (row_ids, segment_ranges)
434    }
435
436    pub fn slice(&self, offset: usize, len: usize) -> RowIdSeqSlice<'_> {
437        if len == 0 {
438            return RowIdSeqSlice {
439                segments: &[],
440                offset_start: 0,
441                offset_last: 0,
442            };
443        }
444
445        // Find the starting position
446        let mut offset_start = offset;
447        let mut segment_offset = 0;
448        for segment in &self.0 {
449            let segment_len = segment.len();
450            if offset_start < segment_len {
451                break;
452            }
453            offset_start -= segment_len;
454            segment_offset += 1;
455        }
456
457        // Find the ending position
458        let mut offset_last = offset_start + len;
459        let mut segment_offset_last = segment_offset;
460        for segment in &self.0[segment_offset..] {
461            let segment_len = segment.len();
462            if offset_last <= segment_len {
463                break;
464            }
465            offset_last -= segment_len;
466            segment_offset_last += 1;
467        }
468
469        RowIdSeqSlice {
470            segments: &self.0[segment_offset..=segment_offset_last],
471            offset_start,
472            offset_last,
473        }
474    }
475
476    /// Get the row id at the given index.
477    ///
478    /// If the index is out of bounds, this will return None.
479    /// The segments backing the sequence, in offset order.
480    pub fn segments(&self) -> &[U64Segment] {
481        &self.0
482    }
483
484    pub fn get(&self, index: usize) -> Option<u64> {
485        let mut offset = 0;
486        for segment in &self.0 {
487            let segment_len = segment.len();
488            if index < offset + segment_len {
489                return segment.get(index - offset);
490            }
491            offset += segment_len;
492        }
493        None
494    }
495
496    /// Get row ids from the sequence based on the provided _sorted_ offsets
497    ///
498    /// Any out of bounds offsets will be ignored
499    ///
500    /// # Panics
501    ///
502    /// If the input selection is not sorted, this function will panic
503    pub fn select<'a>(
504        &'a self,
505        selection: impl Iterator<Item = usize> + 'a,
506    ) -> impl Iterator<Item = u64> + 'a {
507        let mut cursor = RowIdSequenceCursor::default();
508        let mut last_index = None;
509        selection.filter_map(move |index| {
510            if last_index.is_some_and(|last| index < last) {
511                panic!("Selection is not sorted");
512            }
513            last_index = Some(index);
514            cursor.get(self, index)
515        })
516    }
517
518    pub(crate) fn cursor(&self) -> RowIdSequenceCursor {
519        RowIdSequenceCursor::default()
520    }
521
522    /// Choose the dense decoder once for a stream and reuse its cardinality.
523    ///
524    /// A stream uses one decoder for its lifetime, so multi-segment sequences
525    /// conservatively retain the sparse path. For a single bitmap segment, the
526    /// cardinality computed for the density decision seeds the cursor instead
527    /// of scanning the bitmap again on the first batch.
528    pub(crate) fn cursor_with_dense_range_expansion(&self) -> (RowIdSequenceCursor, bool) {
529        let mut cursor = self.cursor();
530        let [segment @ U64Segment::RangeWithBitmap { .. }] = self.0.as_slice() else {
531            return (cursor, false);
532        };
533        let segment_len = segment.len();
534        cursor.segment_len = Some(segment_len);
535        let use_dense_range_expansion = segment.use_dense_range_expansion(segment_len);
536        (cursor, use_dense_range_expansion)
537    }
538
539    /// Get a contiguous range of row ids while preserving scan state from a
540    /// previous call.
541    pub(crate) fn select_range_with_cursor(
542        &self,
543        cursor: &mut RowIdSequenceCursor,
544        selection: Range<usize>,
545    ) -> Vec<u64> {
546        let mut row_ids = Vec::with_capacity(selection.len());
547        cursor.extend_range(self, selection, &mut row_ids);
548        row_ids
549    }
550
551    /// Get a contiguous range from a sequence whose bitmap segments are dense.
552    pub(crate) fn select_dense_range_with_cursor(
553        &self,
554        cursor: &mut RowIdSequenceCursor,
555        selection: Range<usize>,
556    ) -> Vec<u64> {
557        let mut row_ids = Vec::with_capacity(selection.len());
558        cursor.extend_dense_range(self, selection, &mut row_ids);
559        row_ids
560    }
561
562    /// Get row ids while preserving scan state from a previous call.
563    ///
564    /// Decreasing offsets are supported by rewinding the cursor. This matters
565    /// for take requests, whose indices are not required to be sorted.
566    pub(crate) fn select_with_cursor<'a>(
567        &'a self,
568        cursor: &'a mut RowIdSequenceCursor,
569        selection: impl Iterator<Item = usize> + 'a,
570    ) -> impl Iterator<Item = u64> + 'a {
571        selection.filter_map(move |index| cursor.get(self, index))
572    }
573
574    /// Given a mask of row ids, calculate the offset ranges of the row ids that are present
575    /// in the sequence.
576    ///
577    /// For example, given a mask that selects all even ids and a sequence that is
578    /// [80..85, 86..90, 14]
579    ///
580    /// this will return [0, 2, 4, 5, 7, 9]
581    /// because the range expands to
582    ///
583    /// [80, 81, 82, 83, 84, 86, 87, 88, 89, 14] with offsets
584    /// [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9]
585    ///
586    /// This function is useful when determining which row offsets to read from a fragment given
587    /// a mask.
588    #[instrument(level = "debug", skip_all)]
589    pub fn mask_to_offset_ranges(&self, mask: &RowAddrMask) -> Vec<Range<u64>> {
590        let mut offset = 0;
591        let mut ranges = Vec::new();
592        for segment in &self.0 {
593            match segment {
594                U64Segment::Range(range) => {
595                    let mut ids = RowAddrTreeMap::from(range.clone());
596                    ids.mask(mask);
597                    // Range-aware path: walk the bitmap's runs directly via
598                    // iter_runs so the per-row cost collapses to per-run cost.
599                    let mut cur: Option<Range<u64>> = None;
600                    for (fragment, run) in ids.iter_runs() {
601                        let frag = u64::from(fragment);
602                        let run_start = (frag << 32) | u64::from(*run.start());
603                        let run_end_excl = (frag << 32) | (u64::from(*run.end()) + 1);
604                        let start = run_start - range.start + offset;
605                        let end = run_end_excl - range.start + offset;
606                        match cur.as_mut() {
607                            Some(c) if c.end == start => c.end = end,
608                            Some(c) => {
609                                ranges.push(std::mem::replace(c, start..end));
610                            }
611                            None => cur = Some(start..end),
612                        }
613                    }
614                    if let Some(c) = cur {
615                        ranges.push(c);
616                    }
617                    offset += range.end - range.start;
618                }
619                U64Segment::RangeWithHoles { range, holes } => {
620                    let offset_start = offset;
621                    let mut ids = RowAddrTreeMap::from(range.clone());
622                    offset += range.end - range.start;
623                    for hole in holes.iter() {
624                        if ids.remove(hole) {
625                            offset -= 1;
626                        }
627                    }
628                    ids.mask(mask);
629
630                    // Sadly we can't just subtract the offset because of the holes
631                    let mut sorted_holes = holes.clone().into_iter().collect::<Vec<_>>();
632                    sorted_holes.sort_unstable();
633                    let mut next_holes_iter = sorted_holes.into_iter().peekable();
634                    let mut holes_passed = 0;
635                    ranges.extend(GroupingIterator::new(ids.into_addr_iter().map(|addr| {
636                        while let Some(next_hole) = next_holes_iter.peek() {
637                            if *next_hole < addr {
638                                next_holes_iter.next();
639                                holes_passed += 1;
640                            } else {
641                                break;
642                            }
643                        }
644                        addr - range.start + offset_start - holes_passed
645                    })));
646                }
647                U64Segment::RangeWithBitmap { range, bitmap } => {
648                    let mut ids = RowAddrTreeMap::from(range.clone());
649                    let offset_start = offset;
650                    offset += range.end - range.start;
651                    for (i, val) in range.clone().enumerate() {
652                        if !bitmap.get(i) && ids.remove(val) {
653                            offset -= 1;
654                        }
655                    }
656                    ids.mask(mask);
657                    let mut bitmap_iter = bitmap.iter();
658                    let mut bitmap_iter_pos = 0;
659                    let mut holes_passed = 0;
660                    ranges.extend(GroupingIterator::new(ids.into_addr_iter().map(|addr| {
661                        let position_in_range = addr - range.start;
662                        while bitmap_iter_pos < position_in_range {
663                            if !bitmap_iter.next().unwrap() {
664                                holes_passed += 1;
665                            }
666                            bitmap_iter_pos += 1;
667                        }
668                        offset_start + position_in_range - holes_passed
669                    })));
670                }
671                U64Segment::SortedArray(array) | U64Segment::Array(array) => {
672                    // TODO: Could probably optimize the sorted array case to be O(N) instead of O(N log N)
673                    ranges.extend(GroupingIterator::new(array.iter().enumerate().filter_map(
674                        |(off, id)| {
675                            if mask.selected(id) {
676                                Some(off as u64 + offset)
677                            } else {
678                                None
679                            }
680                        },
681                    )));
682                    offset += array.len() as u64;
683                }
684            }
685        }
686        ranges
687    }
688}
689
690/// An iterator that groups row ids into ranges
691///
692/// For example, given an input iterator of [1, 2, 3, 5, 6, 7, 10, 11, 12]
693/// this will return an iterator of [(1..4), (5..8), (10..13)]
694struct GroupingIterator<I: Iterator<Item = u64>> {
695    iter: I,
696    cur_range: Option<Range<u64>>,
697}
698
699impl<I: Iterator<Item = u64>> GroupingIterator<I> {
700    fn new(iter: I) -> Self {
701        Self {
702            iter,
703            cur_range: None,
704        }
705    }
706}
707
708impl<I: Iterator<Item = u64>> Iterator for GroupingIterator<I> {
709    type Item = Range<u64>;
710
711    fn next(&mut self) -> Option<Self::Item> {
712        for id in self.iter.by_ref() {
713            if let Some(range) = self.cur_range.as_mut() {
714                if range.end == id {
715                    range.end = id + 1;
716                } else {
717                    let ret = Some(range.clone());
718                    self.cur_range = Some(id..id + 1);
719                    return ret;
720                }
721            } else {
722                self.cur_range = Some(id..id + 1);
723            }
724        }
725        self.cur_range.take()
726    }
727}
728
729impl From<&RowIdSequence> for RowAddrTreeMap {
730    fn from(row_ids: &RowIdSequence) -> Self {
731        let mut tree_map = Self::new();
732        for segment in &row_ids.0 {
733            let mut seg = Self::new();
734            match segment {
735                U64Segment::Range(range) => {
736                    seg.insert_range(range.clone());
737                }
738                U64Segment::RangeWithBitmap { range, bitmap } => {
739                    seg.insert_range(range.clone());
740                    for (i, val) in range.clone().enumerate() {
741                        if !bitmap.get(i) {
742                            seg.remove(val);
743                        }
744                    }
745                }
746                U64Segment::RangeWithHoles { range, holes } => {
747                    seg.insert_range(range.clone());
748                    for hole in holes.iter() {
749                        seg.remove(hole);
750                    }
751                }
752                U64Segment::SortedArray(array) | U64Segment::Array(array) => {
753                    for val in array.iter() {
754                        seg.insert(val);
755                    }
756                }
757            }
758            tree_map |= seg;
759        }
760        tree_map
761    }
762}
763
764#[derive(Debug)]
765pub struct RowIdSeqSlice<'a> {
766    /// Current slice of the segments we cover
767    segments: &'a [U64Segment],
768    /// Offset into the first segment to start iterating from
769    offset_start: usize,
770    /// Offset into the last segment to stop iterating at
771    offset_last: usize,
772}
773
774impl RowIdSeqSlice<'_> {
775    pub fn iter(&self) -> impl Iterator<Item = u64> + '_ {
776        let mut known_size = self.segments.iter().map(|segment| segment.len()).sum();
777        known_size -= self.offset_start;
778        known_size -= self.segments.last().map(|s| s.len()).unwrap_or_default() - self.offset_last;
779
780        let end = self.segments.len().saturating_sub(1);
781        self.segments
782            .iter()
783            .enumerate()
784            .flat_map(move |(i, segment)| {
785                match i {
786                    0 if self.segments.len() == 1 => {
787                        let len = self.offset_last - self.offset_start;
788                        // TODO: Optimize this so we don't have to use skip
789                        // (take is probably fine though.)
790                        Box::new(segment.iter().skip(self.offset_start).take(len))
791                            as Box<dyn Iterator<Item = u64>>
792                    }
793                    0 => Box::new(segment.iter().skip(self.offset_start)),
794                    i if i == end => Box::new(segment.iter().take(self.offset_last)),
795                    _ => Box::new(segment.iter()),
796                }
797            })
798            .exact_size(known_size)
799    }
800}
801
802/// Re-chunk a sequences of row ids into chunks of a given size.
803///
804/// The sequences may less than chunk sizes, because the sequences only
805/// contains the row ids that we want to keep, they come from the updates records.
806/// But the chunk sizes are based on the fragment physical rows(may contain inserted records).
807/// So if the sequences are smaller than the chunk sizes, we need to
808/// assign the incremental row ids in the further step. This behavior is controlled by the
809/// `allow_incomplete` parameter.
810///
811/// # Errors
812///
813/// If `allow_incomplete` is false, will return an error if the sum of the chunk sizes
814/// is not equal to the total number of row ids in the sequences.
815pub fn rechunk_sequences(
816    sequences: impl IntoIterator<Item = RowIdSequence>,
817    chunk_sizes: impl IntoIterator<Item = u64>,
818    allow_incomplete: bool,
819) -> Result<Vec<RowIdSequence>> {
820    // TODO: return an iterator. (with a good size hint?)
821    let chunk_sizes_vec: Vec<u64> = chunk_sizes.into_iter().collect();
822    let total_chunks = chunk_sizes_vec.len();
823    let mut chunked_sequences = Vec::with_capacity(total_chunks);
824    let mut segment_iter = sequences
825        .into_iter()
826        .flat_map(|sequence| sequence.0.into_iter())
827        .peekable();
828
829    let too_few_segments_error = |chunk_index: usize, expected_chunk_size: u64, remaining: u64| {
830        Error::invalid_input(format!(
831            "Got too few segments for chunk {}. Expected chunk size: {}, remaining needed: {}",
832            chunk_index, expected_chunk_size, remaining
833        ))
834    };
835
836    let too_many_segments_error = |processed_chunks: usize, total_chunk_sizes: usize| {
837        Error::invalid_input(format!(
838            "Got too many segments for the provided chunk lengths. Processed {} chunks out of {} expected",
839            processed_chunks, total_chunk_sizes
840        ))
841    };
842
843    let mut segment_offset = 0_u64;
844
845    for (chunk_index, chunk_size) in chunk_sizes_vec.iter().enumerate() {
846        let chunk_size = *chunk_size;
847        let mut sequence = RowIdSequence(Vec::new());
848        let mut remaining = chunk_size;
849
850        while remaining > 0 {
851            let remaining_in_segment = segment_iter
852                .peek()
853                .map_or(0, |segment| segment.len() as u64 - segment_offset);
854
855            // Step 1: Handle segment remaining to be empty(also empty seg) - skip and continue
856            if remaining_in_segment == 0 {
857                if segment_iter.next().is_some() {
858                    segment_offset = 0;
859                    continue;
860                } else {
861                    // No more segments available
862                    if allow_incomplete {
863                        break;
864                    } else {
865                        return Err(too_few_segments_error(chunk_index, chunk_size, remaining));
866                    }
867                }
868            }
869
870            // Step 2: Handle still remaining segment based on size comparison
871            match remaining_in_segment.cmp(&remaining) {
872                std::cmp::Ordering::Greater => {
873                    // Segment is larger than remaining space - slice it
874                    let segment = segment_iter
875                        .peek()
876                        .ok_or_else(|| too_few_segments_error(chunk_index, chunk_size, remaining))?
877                        .slice(segment_offset as usize, remaining as usize);
878                    sequence.extend(RowIdSequence(vec![segment]));
879                    segment_offset += remaining;
880                    remaining = 0;
881                }
882                std::cmp::Ordering::Equal | std::cmp::Ordering::Less => {
883                    // UNIFIED HANDLING: Both equal and less cases subtract from remaining
884                    // Equal case: remaining -= remaining_in_segment (remaining becomes 0)
885                    // Less case: remaining -= remaining_in_segment (remaining becomes positive)
886                    let segment = segment_iter
887                        .next()
888                        .ok_or_else(|| too_few_segments_error(chunk_index, chunk_size, remaining))?
889                        .slice(segment_offset as usize, remaining_in_segment as usize);
890                    sequence.extend(RowIdSequence(vec![segment]));
891                    segment_offset = 0;
892                    remaining -= remaining_in_segment;
893                }
894            }
895        }
896
897        chunked_sequences.push(sequence);
898    }
899
900    if segment_iter.peek().is_some() {
901        return Err(too_many_segments_error(
902            chunked_sequences.len(),
903            total_chunks,
904        ));
905    }
906
907    Ok(chunked_sequences)
908}
909
910/// Selects the row ids from a sequence based on the provided offsets.
911pub fn select_row_ids<'a>(
912    sequence: &'a RowIdSequence,
913    offsets: &'a ReadBatchParams,
914) -> Result<Vec<u64>> {
915    let out_of_bounds_err = |offset: u32| {
916        Error::invalid_input(format!(
917            "Index out of bounds: {} for sequence of length {}",
918            offset,
919            sequence.len()
920        ))
921    };
922
923    match offsets {
924        ReadBatchParams::Indices(indices) => {
925            let indices = indices.values();
926            if indices.windows(2).all(|pair| pair[0] <= pair[1]) {
927                // `select` drops out-of-bounds indices instead of erroring.
928                if let Some(&last) = indices.last()
929                    && last as u64 >= sequence.len()
930                {
931                    return Err(out_of_bounds_err(last));
932                }
933                return Ok(sequence
934                    .select(indices.iter().map(|&index| index as usize))
935                    .collect());
936            }
937            indices
938                .iter()
939                .map(|index| {
940                    sequence
941                        .get(*index as usize)
942                        .ok_or_else(|| out_of_bounds_err(*index))
943                })
944                .collect()
945        }
946        ReadBatchParams::Range(range) => {
947            if range.end > sequence.len() as usize {
948                return Err(out_of_bounds_err(range.end as u32));
949            }
950            let sequence = sequence.slice(range.start, range.end - range.start);
951            Ok(sequence.iter().collect())
952        }
953        ReadBatchParams::Ranges(ranges) => {
954            let num_rows = ranges
955                .iter()
956                .map(|r| (r.end - r.start) as usize)
957                .sum::<usize>();
958            let mut result = Vec::with_capacity(num_rows);
959            for range in ranges.as_ref() {
960                if range.end > sequence.len() {
961                    return Err(out_of_bounds_err(range.end as u32));
962                }
963                let sequence =
964                    sequence.slice(range.start as usize, (range.end - range.start) as usize);
965                result.extend(sequence.iter());
966            }
967            Ok(result)
968        }
969
970        ReadBatchParams::RangeFull => Ok(sequence.iter().collect()),
971        ReadBatchParams::RangeTo(to) => {
972            if to.end > sequence.len() as usize {
973                return Err(out_of_bounds_err(to.end as u32));
974            }
975            let len = to.end;
976            let sequence = sequence.slice(0, len);
977            Ok(sequence.iter().collect())
978        }
979        ReadBatchParams::RangeFrom(from) => {
980            let sequence = sequence.slice(from.start, sequence.len() as usize - from.start);
981            Ok(sequence.iter().collect())
982        }
983    }
984}
985
986#[cfg(test)]
987mod test {
988    use super::*;
989
990    use pretty_assertions::assert_eq;
991    use test::bitmap::Bitmap;
992
993    #[test]
994    fn test_row_id_sequence_from_range() {
995        let sequence = RowIdSequence::from(0..10);
996        assert_eq!(sequence.len(), 10);
997        assert_eq!(sequence.is_empty(), false);
998
999        let iter = sequence.iter();
1000        assert_eq!(iter.collect::<Vec<_>>(), (0..10).collect::<Vec<_>>());
1001    }
1002
1003    #[rstest::rstest]
1004    #[case::sorted_contiguous(vec![0, 1, 2, 3])]
1005    #[case::sorted_with_gaps(vec![0, 2, 4])]
1006    #[case::sparse(vec![0, 1_000_000])]
1007    #[case::unsorted(vec![12, 11, 10])]
1008    fn test_row_id_sequence_try_from_iter(#[case] row_ids: Vec<u64>) {
1009        let sequence = RowIdSequence::try_from_iter(row_ids.clone()).unwrap();
1010        assert_eq!(sequence.len(), row_ids.len() as u64);
1011        assert_eq!(sequence.iter().collect::<Vec<_>>(), row_ids);
1012    }
1013
1014    #[test]
1015    fn test_row_id_sequence_try_from_iter_contiguous_is_a_range() {
1016        let sequence = RowIdSequence::try_from_iter(0..10).unwrap();
1017        assert_eq!(sequence.0, vec![U64Segment::Range(0..10)]);
1018    }
1019
1020    #[test]
1021    fn test_row_id_sequence_try_from_iter_empty() {
1022        let sequence = RowIdSequence::try_from_iter(std::iter::empty()).unwrap();
1023        assert_eq!(sequence.len(), 0);
1024        assert!(sequence.is_empty());
1025    }
1026
1027    #[rstest::rstest]
1028    #[case::adjacent(vec![1, 1, 2])]
1029    #[case::separated(vec![1, 2, 3, 1])]
1030    #[case::unsorted(vec![5, 3, 5])]
1031    fn test_row_id_sequence_try_from_iter_rejects_duplicates(#[case] row_ids: Vec<u64>) {
1032        // Without validation these encode to a shorter sequence with a spurious
1033        // hole rather than failing, so assert the error rather than the output.
1034        let error = RowIdSequence::try_from_iter(row_ids).unwrap_err();
1035        assert!(
1036            matches!(error, Error::InvalidInput { .. }),
1037            "expected InvalidInput, got {:?}",
1038            error
1039        );
1040        assert!(
1041            error.to_string().contains("must be unique"),
1042            "unexpected message: {}",
1043            error
1044        );
1045    }
1046
1047    #[test]
1048    fn test_row_id_sequence_extend() {
1049        let mut sequence = RowIdSequence::from(0..10);
1050        sequence.extend(RowIdSequence::from(10..20));
1051        assert_eq!(sequence.0, vec![U64Segment::Range(0..20)]);
1052
1053        let mut sequence = RowIdSequence::from(0..10);
1054        sequence.extend(RowIdSequence::from(20..30));
1055        assert_eq!(
1056            sequence.0,
1057            vec![U64Segment::Range(0..10), U64Segment::Range(20..30)]
1058        );
1059    }
1060
1061    #[test]
1062    fn test_row_id_sequence_delete() {
1063        let mut sequence = RowIdSequence::from(0..10);
1064        sequence.delete(vec![1, 3, 5, 7, 9]);
1065        let mut expected_bitmap = Bitmap::new_empty(9);
1066        for i in [0, 2, 4, 6, 8] {
1067            expected_bitmap.set(i as usize);
1068        }
1069        assert_eq!(
1070            sequence.0,
1071            vec![U64Segment::RangeWithBitmap {
1072                range: 0..9,
1073                bitmap: expected_bitmap
1074            },]
1075        );
1076
1077        let mut sequence = RowIdSequence::from(0..10);
1078        sequence.extend(RowIdSequence::from(12..20));
1079        sequence.delete(vec![0, 9, 10, 11, 12, 13]);
1080        assert_eq!(
1081            sequence.0,
1082            vec![U64Segment::Range(1..9), U64Segment::Range(14..20),]
1083        );
1084
1085        let mut sequence = RowIdSequence::from(0..10);
1086        sequence.delete(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1087        assert_eq!(sequence.0, vec![U64Segment::Range(0..0)]);
1088    }
1089
1090    #[test]
1091    fn test_row_id_slice() {
1092        // The type of sequence isn't that relevant to the implementation, so
1093        // we can just have a single one with all the segment types.
1094        let sequence = RowIdSequence(vec![
1095            U64Segment::Range(30..35), // 5
1096            U64Segment::RangeWithHoles {
1097                // 8
1098                range: 50..60,
1099                holes: vec![53, 54].into(),
1100            },
1101            U64Segment::SortedArray(vec![7, 9].into()), // 2
1102            U64Segment::RangeWithBitmap {
1103                range: 0..5,
1104                bitmap: [true, false, true, false, true].as_slice().into(),
1105            },
1106            U64Segment::Array(vec![35, 39].into()),
1107            U64Segment::Range(40..50),
1108        ]);
1109
1110        // All possible offsets and lengths
1111        for offset in 0..sequence.len() as usize {
1112            for len in 0..sequence.len() as usize {
1113                if offset + len > sequence.len() as usize {
1114                    continue;
1115                }
1116                let slice = sequence.slice(offset, len);
1117
1118                let actual = slice.iter().collect::<Vec<_>>();
1119                let expected = sequence.iter().skip(offset).take(len).collect::<Vec<_>>();
1120                assert_eq!(
1121                    actual, expected,
1122                    "Failed for offset {} and len {}",
1123                    offset, len
1124                );
1125
1126                let (claimed_size, claimed_max) = slice.iter().size_hint();
1127                assert_eq!(claimed_max, Some(claimed_size)); // Exact size hint
1128                assert_eq!(claimed_size, actual.len()); // Correct size hint
1129            }
1130        }
1131    }
1132
1133    #[test]
1134    fn test_row_id_slice_empty() {
1135        let sequence = RowIdSequence::from(0..10);
1136        let slice = sequence.slice(10, 0);
1137        assert_eq!(slice.iter().collect::<Vec<_>>(), Vec::<u64>::new());
1138    }
1139
1140    #[test]
1141    fn test_row_id_sequence_rechunk() {
1142        fn assert_rechunked(
1143            input: Vec<RowIdSequence>,
1144            chunk_sizes: Vec<u64>,
1145            expected: Vec<RowIdSequence>,
1146        ) {
1147            let chunked = rechunk_sequences(input, chunk_sizes, false).unwrap();
1148            assert_eq!(chunked, expected);
1149        }
1150
1151        // Small pieces to larger ones
1152        let many_segments = vec![
1153            RowIdSequence(vec![U64Segment::Range(0..5), U64Segment::Range(35..40)]),
1154            RowIdSequence::from(10..18),
1155            RowIdSequence::from(18..28),
1156            RowIdSequence::from(28..30),
1157        ];
1158        let fewer_segments = vec![
1159            RowIdSequence(vec![U64Segment::Range(0..5), U64Segment::Range(35..40)]),
1160            RowIdSequence::from(10..30),
1161        ];
1162        assert_rechunked(
1163            many_segments.clone(),
1164            fewer_segments.iter().map(|seq| seq.len()).collect(),
1165            fewer_segments.clone(),
1166        );
1167
1168        // Large pieces to smaller ones
1169        assert_rechunked(
1170            fewer_segments,
1171            many_segments.iter().map(|seq| seq.len()).collect(),
1172            many_segments.clone(),
1173        );
1174
1175        // Equal pieces
1176        assert_rechunked(
1177            many_segments.clone(),
1178            many_segments.iter().map(|seq| seq.len()).collect(),
1179            many_segments.clone(),
1180        );
1181
1182        // Too few segments -> error
1183        let result = rechunk_sequences(many_segments.clone(), vec![100], false);
1184        assert!(result.is_err());
1185
1186        // Too many segments -> error
1187        let result = rechunk_sequences(many_segments, vec![5], false);
1188        assert!(result.is_err());
1189    }
1190
1191    #[test]
1192    fn test_select_row_ids() {
1193        // All forms of offsets
1194        let offsets = [
1195            ReadBatchParams::Indices(vec![1, 3, 9, 5, 7, 6].into()),
1196            ReadBatchParams::Indices(vec![1, 3, 5, 6, 7, 9].into()),
1197            ReadBatchParams::Range(2..8),
1198            ReadBatchParams::RangeFull,
1199            ReadBatchParams::RangeTo(..5),
1200            ReadBatchParams::RangeFrom(5..),
1201            ReadBatchParams::Ranges(vec![2..3, 5..10].into()),
1202        ];
1203
1204        // Sequences with all segment types. These have at least 10 elements,
1205        // so they are valid for all the above offsets.
1206        let sequences = [
1207            RowIdSequence(vec![
1208                U64Segment::Range(0..5),
1209                U64Segment::RangeWithHoles {
1210                    range: 50..60,
1211                    holes: vec![53, 54].into(),
1212                },
1213                U64Segment::SortedArray(vec![7, 9].into()),
1214            ]),
1215            RowIdSequence(vec![
1216                U64Segment::RangeWithBitmap {
1217                    range: 0..5,
1218                    bitmap: [true, false, true, false, true].as_slice().into(),
1219                },
1220                U64Segment::Array(vec![30, 20, 10].into()),
1221                U64Segment::Range(40..50),
1222            ]),
1223        ];
1224
1225        for params in offsets {
1226            for sequence in &sequences {
1227                let row_ids = select_row_ids(sequence, &params).unwrap();
1228                let flat_sequence = sequence.iter().collect::<Vec<_>>();
1229
1230                // Transform params into bounded ones
1231                let selection: Vec<usize> = match &params {
1232                    ReadBatchParams::RangeFull => (0..flat_sequence.len()).collect(),
1233                    ReadBatchParams::RangeTo(to) => (0..to.end).collect(),
1234                    ReadBatchParams::RangeFrom(from) => (from.start..flat_sequence.len()).collect(),
1235                    ReadBatchParams::Range(range) => range.clone().collect(),
1236                    ReadBatchParams::Ranges(ranges) => ranges
1237                        .iter()
1238                        .flat_map(|r| r.start as usize..r.end as usize)
1239                        .collect(),
1240                    ReadBatchParams::Indices(indices) => {
1241                        indices.values().iter().map(|i| *i as usize).collect()
1242                    }
1243                };
1244
1245                let expected = selection
1246                    .into_iter()
1247                    .map(|i| flat_sequence[i])
1248                    .collect::<Vec<_>>();
1249                assert_eq!(
1250                    row_ids, expected,
1251                    "Failed for params {:?} on the sequence {:?}",
1252                    &params, sequence
1253                );
1254            }
1255        }
1256    }
1257
1258    #[test]
1259    fn test_select_row_ids_out_of_bounds() {
1260        let offsets = [
1261            ReadBatchParams::Indices(vec![1, 1000, 4].into()),
1262            ReadBatchParams::Indices(vec![1, 4, 1000].into()),
1263            ReadBatchParams::Range(2..1000),
1264            ReadBatchParams::RangeTo(..1000),
1265        ];
1266
1267        let sequence = RowIdSequence::from(0..10);
1268
1269        for params in offsets {
1270            let result = select_row_ids(&sequence, &params);
1271            assert!(result.is_err());
1272            assert!(matches!(result.unwrap_err(), Error::InvalidInput { .. }));
1273        }
1274    }
1275
1276    #[test]
1277    fn test_row_id_sequence_to_treemap() {
1278        let sequence = RowIdSequence(vec![
1279            U64Segment::Range(0..5),
1280            U64Segment::RangeWithHoles {
1281                range: 50..60,
1282                holes: vec![53, 54].into(),
1283            },
1284            U64Segment::SortedArray(vec![7, 9].into()),
1285            U64Segment::RangeWithBitmap {
1286                range: 10..15,
1287                bitmap: [true, false, true, false, true].as_slice().into(),
1288            },
1289            U64Segment::Array(vec![35, 39].into()),
1290            U64Segment::Range(40..50),
1291        ]);
1292
1293        let tree_map = RowAddrTreeMap::from(&sequence);
1294        let expected = vec![
1295            0, 1, 2, 3, 4, 7, 9, 10, 12, 14, 35, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
1296            51, 52, 55, 56, 57, 58, 59,
1297        ]
1298        .into_iter()
1299        .collect::<RowAddrTreeMap>();
1300        assert_eq!(tree_map, expected);
1301    }
1302
1303    #[test]
1304    fn test_row_id_sequence_to_treemap_overlapping_segments() {
1305        // Compaction can concatenate segments whose ranges overlap but whose
1306        // selected ids are disjoint (here: even ids, then odd ids over 0..6).
1307        // The tree map must contain every id the sequence yields.
1308        let sequence = RowIdSequence(vec![
1309            U64Segment::RangeWithBitmap {
1310                range: 0..6,
1311                bitmap: [true, false, true, false, true, false].as_slice().into(),
1312            },
1313            U64Segment::RangeWithBitmap {
1314                range: 0..6,
1315                bitmap: [false, true, false, true, false, true].as_slice().into(),
1316            },
1317        ]);
1318
1319        let expected = sequence.iter().collect::<RowAddrTreeMap>();
1320        assert_eq!(expected, (0..6).collect::<RowAddrTreeMap>());
1321        assert_eq!(RowAddrTreeMap::from(&sequence), expected);
1322    }
1323
1324    #[test]
1325    fn test_row_addr_mask() {
1326        // 0, 1, 2, 3, 4
1327        // 50, 51, 52, 55, 56, 57, 58, 59
1328        // 7, 9
1329        // 10, 12, 14
1330        // 35, 39
1331        let sequence = RowIdSequence(vec![
1332            U64Segment::Range(0..5),
1333            U64Segment::RangeWithHoles {
1334                range: 50..60,
1335                holes: vec![53, 54].into(),
1336            },
1337            U64Segment::SortedArray(vec![7, 9].into()),
1338            U64Segment::RangeWithBitmap {
1339                range: 10..15,
1340                bitmap: [true, false, true, false, true].as_slice().into(),
1341            },
1342            U64Segment::Array(vec![35, 39].into()),
1343        ]);
1344
1345        // Masking one in each segment
1346        let values_to_remove = [4, 55, 7, 12, 39];
1347        let positions_to_remove = sequence
1348            .iter()
1349            .enumerate()
1350            .filter_map(|(i, val)| {
1351                if values_to_remove.contains(&val) {
1352                    Some(i as u32)
1353                } else {
1354                    None
1355                }
1356            })
1357            .collect::<Vec<_>>();
1358        let mut sequence = sequence;
1359        sequence.mask(positions_to_remove).unwrap();
1360        let expected = RowIdSequence(vec![
1361            U64Segment::Range(0..4),
1362            U64Segment::RangeWithBitmap {
1363                range: 50..60,
1364                bitmap: [
1365                    true, true, true, false, false, false, true, true, true, true,
1366                ]
1367                .as_slice()
1368                .into(),
1369            },
1370            U64Segment::Range(9..10),
1371            U64Segment::RangeWithBitmap {
1372                range: 10..15,
1373                bitmap: [true, false, false, false, true].as_slice().into(),
1374            },
1375            U64Segment::Array(vec![35].into()),
1376        ]);
1377        assert_eq!(sequence, expected);
1378    }
1379
1380    #[test]
1381    fn test_row_addr_mask_everything() {
1382        let mut sequence = RowIdSequence(vec![
1383            U64Segment::Range(0..5),
1384            U64Segment::SortedArray(vec![7, 9].into()),
1385        ]);
1386        sequence.mask(0..sequence.len() as u32).unwrap();
1387        let expected = RowIdSequence(vec![]);
1388        assert_eq!(sequence, expected);
1389    }
1390
1391    #[test]
1392    fn test_selection() {
1393        let sequence = RowIdSequence(vec![
1394            U64Segment::Range(0..5),
1395            U64Segment::RangeWithHoles {
1396                range: 10..16,
1397                holes: vec![12].into(),
1398            },
1399            U64Segment::RangeWithBitmap {
1400                range: 20..28,
1401                bitmap: [true, false, true, true, false, true, false, true]
1402                    .as_slice()
1403                    .into(),
1404            },
1405            U64Segment::SortedArray(vec![40, 42, 45].into()),
1406            U64Segment::Array(vec![60, 50, 70].into()),
1407        ]);
1408        let live = sequence.iter().collect::<Vec<_>>();
1409        let selection = sequence.select(vec![2, 4, 13, 14, 57].into_iter());
1410        assert_eq!(
1411            selection.collect::<Vec<_>>(),
1412            vec![live[2], live[4], live[13], live[14]]
1413        );
1414
1415        for chunk_size in [1, 3, 7, 16] {
1416            let mut cursor = sequence.cursor();
1417            let mut chunked = Vec::new();
1418            for start in (0..live.len()).step_by(chunk_size) {
1419                let end = (start + chunk_size).min(live.len());
1420                chunked.extend(sequence.select_range_with_cursor(&mut cursor, start..end));
1421            }
1422            assert_eq!(chunked, live);
1423        }
1424
1425        let mut cursor = sequence.cursor();
1426        assert_eq!(
1427            sequence.select_range_with_cursor(&mut cursor, 6..19),
1428            live[6..19]
1429        );
1430        assert_eq!(
1431            sequence.select_range_with_cursor(&mut cursor, 1..8),
1432            live[1..8]
1433        );
1434        assert_eq!(
1435            sequence.select_range_with_cursor(&mut cursor, live.len() - 2..live.len() + 5),
1436            live[live.len() - 2..]
1437        );
1438    }
1439
1440    #[test]
1441    fn test_selection_over_bitmap_segments() {
1442        let mut bitmap = Bitmap::new_full(40);
1443        for hole in [3, 4, 17, 39] {
1444            bitmap.clear(hole);
1445        }
1446        let sequence = RowIdSequence(vec![
1447            U64Segment::RangeWithBitmap {
1448                range: 100..140,
1449                bitmap,
1450            },
1451            U64Segment::Range(200..205),
1452        ]);
1453        let live: Vec<u64> = sequence.iter().collect();
1454        assert_eq!(live.len(), 41);
1455
1456        // Every index, one cursor pass.
1457        let all = sequence.select(0..live.len()).collect::<Vec<_>>();
1458        assert_eq!(all, live);
1459        // Sparse, repeated, and past-the-end indices agree with the full pass.
1460        let picks = vec![0, 2, 3, 3, 15, 16, 35, 36, 40, 99];
1461        let got = sequence.select(picks.iter().copied()).collect::<Vec<_>>();
1462        let want: Vec<u64> = picks.iter().filter_map(|&i| live.get(i).copied()).collect();
1463        assert_eq!(got, want);
1464
1465        let mut cursor = sequence.cursor();
1466        let mut chunked = Vec::new();
1467        for range in [0..7, 7..30, 30..live.len()] {
1468            chunked.extend(sequence.select_range_with_cursor(&mut cursor, range));
1469        }
1470        assert_eq!(chunked, live);
1471        assert_eq!(
1472            sequence.select_range_with_cursor(&mut cursor, 2..6),
1473            live[2..6]
1474        );
1475    }
1476
1477    #[test]
1478    fn test_dense_range_cursor_selection() {
1479        let mut bitmap = Bitmap::new_full(40);
1480        for hole in [3, 4, 17, 39] {
1481            bitmap.clear(hole);
1482        }
1483        let sequence = RowIdSequence(vec![U64Segment::RangeWithBitmap {
1484            range: 100..140,
1485            bitmap,
1486        }]);
1487        let expected = sequence.iter().collect::<Vec<_>>();
1488        let (mut cursor, use_dense_range_expansion) = sequence.cursor_with_dense_range_expansion();
1489        assert!(use_dense_range_expansion);
1490        assert_eq!(cursor.segment_len, Some(expected.len()));
1491
1492        let mut actual = Vec::new();
1493        for selection in [0..7, 7..8, 8..31, 31..expected.len() + 5] {
1494            actual.extend(sequence.select_dense_range_with_cursor(&mut cursor, selection));
1495        }
1496        assert_eq!(actual, expected);
1497        assert_eq!(
1498            sequence.select_dense_range_with_cursor(&mut cursor, 2..9),
1499            expected[2..9]
1500        );
1501
1502        let mut sparse_bitmap = Bitmap::new_empty(40);
1503        for value in (0..40).step_by(2) {
1504            sparse_bitmap.set(value);
1505        }
1506        let sparse = RowIdSequence(vec![U64Segment::RangeWithBitmap {
1507            range: 0..40,
1508            bitmap: sparse_bitmap,
1509        }]);
1510        let (sparse_cursor, use_dense_range_expansion) = sparse.cursor_with_dense_range_expansion();
1511        assert!(!use_dense_range_expansion);
1512        assert_eq!(sparse_cursor.segment_len, Some(20));
1513
1514        let mut multiple_segments = sequence.clone();
1515        multiple_segments.extend(RowIdSequence::from(200..205));
1516        let (multiple_cursor, use_dense_range_expansion) =
1517            multiple_segments.cursor_with_dense_range_expansion();
1518        assert!(!use_dense_range_expansion);
1519        assert_eq!(multiple_cursor.segment_len, None);
1520    }
1521
1522    #[test]
1523    fn test_selection_over_a_large_bitmap_segment() {
1524        // A restart-per-index scan of this segment takes tens of seconds, so a
1525        // regression to that shows up as a test that no longer finishes quickly.
1526        const ROWS: usize = 1_000_000;
1527        let mut bitmap = Bitmap::new_full(ROWS);
1528        for hole in (0..ROWS).step_by(17) {
1529            bitmap.clear(hole);
1530        }
1531        let sequence = RowIdSequence(vec![
1532            U64Segment::Range(0..8),
1533            U64Segment::RangeWithBitmap {
1534                range: 1_000..(1_000 + ROWS as u64),
1535                bitmap,
1536            },
1537        ]);
1538        let live: Vec<u64> = sequence.iter().collect();
1539
1540        let all = sequence.select(0..live.len()).collect::<Vec<_>>();
1541        assert_eq!(all, live);
1542
1543        // Byte-boundary and tail indices, read through one cursor.
1544        let mut picks: Vec<usize> = [0, 7, 8, 9, 15, 16, 63, 64, 65]
1545            .into_iter()
1546            .chain((0..live.len()).step_by(9973))
1547            .chain([live.len() - 1, live.len()])
1548            .collect();
1549        picks.sort_unstable();
1550        let got = sequence.select(picks.iter().copied()).collect::<Vec<_>>();
1551        let want: Vec<u64> = picks.iter().filter_map(|&i| live.get(i).copied()).collect();
1552        assert_eq!(got, want);
1553
1554        let tail_start = live.len() - 100_000;
1555        let mut cursor = sequence.cursor();
1556        assert_eq!(
1557            sequence.select_range_with_cursor(&mut cursor, tail_start..live.len()),
1558            live[tail_start..]
1559        );
1560
1561        for chunk_size in [1, 7, 8, 9, 1_024, 4_097] {
1562            let mut cursor = sequence.cursor();
1563            let mut chunked = Vec::with_capacity(live.len() - tail_start);
1564            let mut start = tail_start;
1565            while start < live.len() {
1566                let end = (start + chunk_size).min(live.len());
1567                chunked.extend(sequence.select_range_with_cursor(&mut cursor, start..end));
1568                start = end;
1569            }
1570            assert_eq!(chunked, live[tail_start..]);
1571        }
1572    }
1573
1574    #[test]
1575    #[should_panic(expected = "Selection is not sorted")]
1576    fn test_selection_unsorted() {
1577        let sequence = RowIdSequence(vec![
1578            U64Segment::Range(0..5),
1579            U64Segment::Range(10..15),
1580            U64Segment::Range(20..25),
1581        ]);
1582        let _ = sequence
1583            .select(vec![2, 4, 3].into_iter())
1584            .collect::<Vec<_>>();
1585    }
1586
1587    #[test]
1588    fn test_mask_to_offset_ranges() {
1589        // Tests with a simple range segment
1590        let sequence = RowIdSequence(vec![U64Segment::Range(0..10)]);
1591        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 2, 4, 6, 8]));
1592        let ranges = sequence.mask_to_offset_ranges(&mask);
1593        assert_eq!(ranges, vec![0..1, 2..3, 4..5, 6..7, 8..9]);
1594
1595        let sequence = RowIdSequence(vec![U64Segment::Range(40..60)]);
1596        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[54]));
1597        let ranges = sequence.mask_to_offset_ranges(&mask);
1598        assert_eq!(ranges, vec![14..15]);
1599
1600        let sequence = RowIdSequence(vec![U64Segment::Range(40..60)]);
1601        let mask = RowAddrMask::from_block(RowAddrTreeMap::from_iter(&[54]));
1602        let ranges = sequence.mask_to_offset_ranges(&mask);
1603        assert_eq!(ranges, vec![0..14, 15..20]);
1604
1605        // Test with a range segment with holes
1606        // 0, 1, 3, 4, 5, 7, 8, 9
1607        let sequence = RowIdSequence(vec![U64Segment::RangeWithHoles {
1608            range: 0..10,
1609            holes: vec![2, 6].into(),
1610        }]);
1611        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 2, 4, 6, 8]));
1612        let ranges = sequence.mask_to_offset_ranges(&mask);
1613        assert_eq!(ranges, vec![0..1, 3..4, 6..7]);
1614
1615        let sequence = RowIdSequence(vec![U64Segment::RangeWithHoles {
1616            range: 40..60,
1617            holes: vec![47, 43].into(),
1618        }]);
1619        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[44]));
1620        let ranges = sequence.mask_to_offset_ranges(&mask);
1621        assert_eq!(ranges, vec![3..4]);
1622
1623        let sequence = RowIdSequence(vec![U64Segment::RangeWithHoles {
1624            range: 40..60,
1625            holes: vec![47, 43].into(),
1626        }]);
1627        let mask = RowAddrMask::from_block(RowAddrTreeMap::from_iter(&[44]));
1628        let ranges = sequence.mask_to_offset_ranges(&mask);
1629        assert_eq!(ranges, vec![0..3, 4..18]);
1630
1631        // Test with a range segment with bitmap
1632        // 0, 1, 4, 5, 6, 7
1633        let sequence = RowIdSequence(vec![U64Segment::RangeWithBitmap {
1634            range: 0..10,
1635            bitmap: [
1636                true, true, false, false, true, true, true, true, false, false,
1637            ]
1638            .as_slice()
1639            .into(),
1640        }]);
1641        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 2, 4, 6, 8]));
1642        let ranges = sequence.mask_to_offset_ranges(&mask);
1643        assert_eq!(ranges, vec![0..1, 2..3, 4..5]);
1644
1645        let sequence = RowIdSequence(vec![U64Segment::RangeWithBitmap {
1646            range: 40..45,
1647            bitmap: [true, true, false, false, true].as_slice().into(),
1648        }]);
1649        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[44]));
1650        let ranges = sequence.mask_to_offset_ranges(&mask);
1651        assert_eq!(ranges, vec![2..3]);
1652
1653        let sequence = RowIdSequence(vec![U64Segment::RangeWithBitmap {
1654            range: 40..45,
1655            bitmap: [true, true, false, false, true].as_slice().into(),
1656        }]);
1657        let mask = RowAddrMask::from_block(RowAddrTreeMap::from_iter(&[44]));
1658        let ranges = sequence.mask_to_offset_ranges(&mask);
1659        assert_eq!(ranges, vec![0..2]);
1660
1661        // Test with a sorted array segment
1662        let sequence = RowIdSequence(vec![U64Segment::SortedArray(vec![0, 2, 4, 6, 8].into())]);
1663        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 6, 8]));
1664        let ranges = sequence.mask_to_offset_ranges(&mask);
1665        assert_eq!(ranges, vec![0..1, 3..5]);
1666
1667        let sequence = RowIdSequence(vec![U64Segment::Array(vec![8, 2, 6, 0, 4].into())]);
1668        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 6, 8]));
1669        let ranges = sequence.mask_to_offset_ranges(&mask);
1670        assert_eq!(ranges, vec![0..1, 2..4]);
1671
1672        // Test with multiple segments
1673        // 0, 1, 2, 3, 4, 100, 101, 102, 104, 44, 46, 78
1674        // *, -, *, -, -, ***, ---, ---, ***, --, **, --
1675        // 0, 1, 2, 3, 4,   5,   6,   7,   8,  9, 10, 11
1676        let sequence = RowIdSequence(vec![
1677            U64Segment::Range(0..5),
1678            U64Segment::RangeWithHoles {
1679                range: 100..105,
1680                holes: vec![103].into(),
1681            },
1682            U64Segment::SortedArray(vec![44, 46, 78].into()),
1683        ]);
1684        let mask = RowAddrMask::from_allowed(RowAddrTreeMap::from_iter(&[0, 2, 46, 100, 104]));
1685        let ranges = sequence.mask_to_offset_ranges(&mask);
1686        assert_eq!(ranges, vec![0..1, 2..3, 5..6, 8..9, 10..11]);
1687
1688        // Test with empty mask (should select everything)
1689        let sequence = RowIdSequence(vec![U64Segment::Range(0..10)]);
1690        let mask = RowAddrMask::default();
1691        let ranges = sequence.mask_to_offset_ranges(&mask);
1692        assert_eq!(ranges, vec![0..10]);
1693
1694        // Test with allow nothing mask
1695        let sequence = RowIdSequence(vec![U64Segment::Range(0..10)]);
1696        let mask = RowAddrMask::allow_nothing();
1697        let ranges = sequence.mask_to_offset_ranges(&mask);
1698        assert_eq!(ranges, vec![]);
1699    }
1700
1701    #[test]
1702    fn test_row_id_sequence_rechunk_with_empty_segments() {
1703        // equal case (segment exactly fills remaining space)
1704        let input_sequences = vec![
1705            RowIdSequence::from(0..2),   // [0, 1] - 2 elements
1706            RowIdSequence::from(20..23), // [20, 21, 22] - 3 elements
1707        ];
1708        let chunk_sizes = vec![2, 3]; // First chunk wants 2, second wants 3
1709
1710        let result = rechunk_sequences(input_sequences, chunk_sizes, false).unwrap();
1711        assert_eq!(result.len(), 2);
1712        assert_eq!(result[0].len(), 2);
1713        assert_eq!(result[1].len(), 3);
1714
1715        let first_chunk: Vec<u64> = result[0].iter().collect();
1716        let second_chunk: Vec<u64> = result[1].iter().collect();
1717        assert_eq!(first_chunk, vec![0, 1]);
1718        assert_eq!(second_chunk, vec![20, 21, 22]);
1719
1720        // less case (segment smaller than remaining space)
1721        let input_sequences = vec![
1722            RowIdSequence::from(0..2),   // [0, 1] - 2 elements (less than remaining)
1723            RowIdSequence::from(20..21), // [20] - 1 element (less than remaining)
1724            RowIdSequence::from(30..32), // [30, 31] - 2 elements (exactly fills remaining)
1725        ];
1726        let chunk_sizes = vec![5]; // Request 5 elements, have exactly 5
1727
1728        let result = rechunk_sequences(input_sequences, chunk_sizes, false).unwrap();
1729        assert_eq!(result.len(), 1);
1730        assert_eq!(result[0].len(), 5);
1731
1732        let elements: Vec<u64> = result[0].iter().collect();
1733        assert_eq!(elements, vec![0, 1, 20, 30, 31]);
1734
1735        // empty segment in the middle
1736        let input_sequences = vec![
1737            RowIdSequence::from(0..2),   // [0, 1] - 2 elements
1738            RowIdSequence::from(10..10), // [] - 0 elements (empty)
1739            RowIdSequence::from(20..22), // [20, 21] - 2 elements
1740        ];
1741        let chunk_sizes = vec![3, 1];
1742        let result = rechunk_sequences(input_sequences, chunk_sizes, false).unwrap();
1743
1744        assert_eq!(result.len(), 2);
1745        assert_eq!(result[0].len(), 3);
1746        assert_eq!(result[1].len(), 1);
1747
1748        let first_chunk_elements: Vec<u64> = result[0].iter().collect();
1749        let second_chunk_elements: Vec<u64> = result[1].iter().collect();
1750        assert_eq!(first_chunk_elements, vec![0, 1, 20]);
1751        assert_eq!(second_chunk_elements, vec![21]);
1752
1753        // multiple empty segments
1754        let input_sequences = vec![
1755            RowIdSequence::from(0..1),   // [0] - 1 element
1756            RowIdSequence::from(10..10), // [] - 0 elements (empty)
1757            RowIdSequence::from(20..20), // [] - 0 elements (empty)
1758            RowIdSequence::from(30..32), // [30, 31] - 2 elements
1759        ];
1760        let chunk_sizes = vec![3];
1761        let result = rechunk_sequences(input_sequences, chunk_sizes, false).unwrap();
1762
1763        assert_eq!(result.len(), 1);
1764        assert_eq!(result[0].len(), 3);
1765
1766        let elements: Vec<u64> = result[0].iter().collect();
1767        assert_eq!(elements, vec![0, 30, 31]);
1768
1769        // empty segment at chunk boundary
1770        let input_sequences = vec![
1771            RowIdSequence::from(0..3), // [0, 1, 2] - 3 elements (exactly fills first chunk)
1772            RowIdSequence::from(10..10), // [] - 0 elements (empty, at boundary)
1773            RowIdSequence::from(20..22), // [20, 21] - 2 elements (for second chunk)
1774        ];
1775        let chunk_sizes = vec![3, 2];
1776        let result = rechunk_sequences(input_sequences, chunk_sizes, false).unwrap();
1777
1778        assert_eq!(result.len(), 2);
1779        assert_eq!(result[0].len(), 3);
1780        assert_eq!(result[1].len(), 2);
1781
1782        let first_chunk_elements: Vec<u64> = result[0].iter().collect();
1783        let second_chunk_elements: Vec<u64> = result[1].iter().collect();
1784        assert_eq!(first_chunk_elements, vec![0, 1, 2]);
1785        assert_eq!(second_chunk_elements, vec![20, 21]);
1786
1787        // empty segments with allow_incomplete = true
1788        let input_sequences = vec![
1789            RowIdSequence::from(0..2),   // [0, 1] - 2 elements
1790            RowIdSequence::from(10..10), // [] - 0 elements (empty)
1791        ];
1792        let chunk_sizes = vec![5]; // Request more than available
1793        let result = rechunk_sequences(input_sequences, chunk_sizes, true).unwrap();
1794
1795        assert_eq!(result.len(), 1);
1796        assert_eq!(result[0].len(), 2);
1797
1798        let elements: Vec<u64> = result[0].iter().collect();
1799        assert_eq!(elements, vec![0, 1]);
1800    }
1801
1802    #[test]
1803    fn test_row_id_range_empty() {
1804        let seq = RowIdSequence::from(0u64..0);
1805        assert_eq!(seq.row_id_range(), None);
1806    }
1807
1808    #[test]
1809    fn test_row_id_range_single_contiguous() {
1810        let seq = RowIdSequence::from(10u64..20);
1811        assert_eq!(seq.row_id_range(), Some(10..=19));
1812    }
1813
1814    #[test]
1815    fn test_row_id_range_unsorted_array() {
1816        // Array variant: range() returns min..=max as bounding box
1817        let seq = RowIdSequence::from([50u64, 10, 30].as_slice());
1818        let r = seq.row_id_range().unwrap();
1819        assert!(*r.start() <= 10);
1820        assert!(*r.end() >= 50);
1821    }
1822
1823    #[test]
1824    fn test_row_id_range_multi_segment() {
1825        // Two disjoint ranges; bounding box should span both
1826        let mut seq = RowIdSequence::from(0u64..5);
1827        seq.extend(RowIdSequence::from(100u64..105));
1828        let r = seq.row_id_range().unwrap();
1829        assert_eq!(*r.start(), 0);
1830        assert_eq!(*r.end(), 104);
1831    }
1832}