Skip to main content

parquet/arrow/record_reader/
definition_levels.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use arrow_array::builder::BooleanBufferBuilder;
19use arrow_buffer::Buffer;
20use arrow_buffer::bit_chunk_iterator::UnalignedBitChunk;
21use arrow_buffer::bit_util::compress;
22use bytes::Bytes;
23
24use crate::arrow::buffer::bit_util::count_set_bits;
25use crate::basic::Encoding;
26use crate::column::reader::decoder::{
27    ColumnLevelDecoder, DefinitionLevelDecoder, DefinitionLevelDecoderImpl,
28};
29use crate::errors::{ParquetError, Result};
30use crate::schema::types::ColumnDescPtr;
31
32enum BufferInner {
33    /// Compute levels and null mask
34    Full {
35        levels: Vec<i16>,
36        nulls: BooleanBufferBuilder,
37        max_level: i16,
38    },
39    /// Only compute null bitmask - requires max level to be 1
40    ///
41    /// This is an optimisation for the common case of a nullable scalar column, as decoding
42    /// the definition level data is only required when decoding nested structures
43    ///
44    Mask { nulls: BooleanBufferBuilder },
45}
46
47pub struct DefinitionLevelBuffer {
48    inner: BufferInner,
49
50    /// The length of this buffer
51    ///
52    /// Note: `buffer` and `builder` may contain more elements
53    len: usize,
54}
55
56impl DefinitionLevelBuffer {
57    pub fn new(desc: &ColumnDescPtr, null_mask_only: bool) -> Self {
58        let inner = match null_mask_only {
59            true => {
60                assert_eq!(
61                    desc.max_def_level(),
62                    1,
63                    "max definition level must be 1 to only compute null bitmask"
64                );
65
66                assert_eq!(
67                    desc.max_rep_level(),
68                    0,
69                    "max repetition level must be 0 to only compute null bitmask"
70                );
71
72                BufferInner::Mask {
73                    nulls: BooleanBufferBuilder::new(0),
74                }
75            }
76            false => BufferInner::Full {
77                levels: Vec::new(),
78                nulls: BooleanBufferBuilder::new(0),
79                max_level: desc.max_def_level(),
80            },
81        };
82
83        Self { inner, len: 0 }
84    }
85
86    /// Returns the built level data
87    pub fn consume_levels(&mut self) -> Option<Vec<i16>> {
88        match &mut self.inner {
89            BufferInner::Full { levels, .. } => Some(std::mem::take(levels)),
90            BufferInner::Mask { .. } => None,
91        }
92    }
93
94    /// Returns the built null bitmask, or None if all values are valid
95    pub fn consume_bitmask(&mut self) -> Option<Buffer> {
96        self.len = 0;
97        let nulls = match &mut self.inner {
98            BufferInner::Full { nulls, .. } => nulls,
99            BufferInner::Mask { nulls } => nulls,
100        };
101
102        // Always call finish() to reset the builder state for the next batch.
103        let buffer = nulls.finish().into_inner();
104
105        // If no bitmap was constructed, return None
106        if buffer.is_empty() {
107            return None;
108        }
109
110        Some(buffer)
111    }
112
113    pub fn nulls(&self) -> &BooleanBufferBuilder {
114        match &self.inner {
115            BufferInner::Full { nulls, .. } => nulls,
116            BufferInner::Mask { nulls } => nulls,
117        }
118    }
119
120    /// Returns the raw definition levels accumulated so far, if available.
121    /// Only available when the buffer is in Full mode (nested columns).
122    pub fn levels(&self) -> Option<&[i16]> {
123        match &self.inner {
124            BufferInner::Full { levels, .. } => Some(levels.as_slice()),
125            BufferInner::Mask { .. } => None,
126        }
127    }
128}
129
130/// Build a filtered validity bitmap from definition/repetition levels.
131///
132/// For each level entry where `d >= include_threshold` (when set) and
133/// `r <= max_rep` (when `rep_filter` is provided), appends one bit to
134/// `bitmap`: set when `d >= value_level`, unset otherwise.
135///
136/// Returns the number of bits appended.
137///
138/// This is the shared implementation behind the compact bitmap (leaf
139/// readers with selective padding) and the struct validity bitmap.
140/// Processing uses 64-level chunks with [`compress`] for word-at-a-time
141/// packing.
142pub(crate) fn build_filtered_validity_bitmap(
143    def_levels: &[i16],
144    rep_filter: Option<(&[i16], i16)>,
145    include_threshold: Option<i16>,
146    value_level: i16,
147    bitmap: &mut BooleanBufferBuilder,
148) -> usize {
149    const CHUNKS: usize = u64::BITS as usize;
150    // Fast path: no filtering — every def level produces a bit.
151    if include_threshold.is_none() && rep_filter.is_none() {
152        let (chunks, remainder) = def_levels.as_chunks::<CHUNKS>();
153        for chunk in chunks {
154            let mut word: u64 = 0;
155            for (i, &d) in chunk.iter().enumerate() {
156                word |= ((d >= value_level) as u64) << i;
157            }
158            bitmap.append_word(word, u64::BITS as usize);
159        }
160        for &d in remainder {
161            bitmap.append(d >= value_level);
162        }
163        return def_levels.len();
164    }
165
166    // Filtered path: build include mask + value mask per chunk, compress.
167    let mut item_count: usize = 0;
168    let (chunks, remainder) = def_levels.as_chunks::<CHUNKS>();
169    let remainder_offset = def_levels.len() - remainder.len();
170
171    for (chunk_idx, chunk) in chunks.iter().enumerate() {
172        let base = chunk_idx * u64::BITS as usize;
173        let mut include_mask: u64 = 0;
174        let mut value_mask: u64 = 0;
175        for (i, &d) in chunk.iter().enumerate() {
176            let include = include_threshold.is_none_or(|threshold| threshold <= d)
177                && rep_filter.is_none_or(|(reps, max_rep)| reps[base + i] <= max_rep);
178            include_mask |= (include as u64) << i;
179            value_mask |= ((d >= value_level) as u64) << i;
180        }
181
182        let count = include_mask.count_ones() as usize;
183        let compact = compress(value_mask, include_mask);
184        bitmap.append_word(compact, count);
185        item_count += count;
186    }
187
188    for idx in remainder_offset..def_levels.len() {
189        let d = def_levels[idx];
190        if let Some(threshold) = include_threshold
191            && d < threshold
192        {
193            continue;
194        }
195        if let Some((reps, max_rep)) = rep_filter
196            && reps[idx] > max_rep
197        {
198            continue;
199        }
200        bitmap.append(d >= value_level);
201        item_count += 1;
202    }
203
204    item_count
205}
206
207enum MaybePacked {
208    Packed(PackedDecoder),
209    Fallback(DefinitionLevelDecoderImpl),
210}
211
212pub struct DefinitionLevelBufferDecoder {
213    max_level: i16,
214    decoder: MaybePacked,
215}
216
217impl DefinitionLevelBufferDecoder {
218    pub fn new(max_level: i16, packed: bool) -> Self {
219        let decoder = match packed {
220            true => MaybePacked::Packed(PackedDecoder::new()),
221            false => MaybePacked::Fallback(DefinitionLevelDecoderImpl::new(max_level)),
222        };
223
224        Self { max_level, decoder }
225    }
226}
227
228impl ColumnLevelDecoder for DefinitionLevelBufferDecoder {
229    type Buffer = DefinitionLevelBuffer;
230
231    fn set_data(&mut self, encoding: Encoding, data: Bytes) -> Result<()> {
232        match &mut self.decoder {
233            MaybePacked::Packed(d) => d.set_data(encoding, data),
234            MaybePacked::Fallback(d) => d.set_data(encoding, data)?,
235        }
236        Ok(())
237    }
238}
239
240impl DefinitionLevelDecoder for DefinitionLevelBufferDecoder {
241    fn read_def_levels(
242        &mut self,
243        writer: &mut Self::Buffer,
244        num_levels: usize,
245    ) -> Result<(usize, usize)> {
246        match (&mut writer.inner, &mut self.decoder) {
247            (
248                BufferInner::Full {
249                    levels,
250                    nulls,
251                    max_level,
252                },
253                MaybePacked::Fallback(decoder),
254            ) => {
255                assert_eq!(self.max_level, *max_level);
256
257                let start = levels.len();
258                let (values_read, levels_read) = decoder.read_def_levels(levels, num_levels)?;
259
260                // Safety: slice iterator has a trusted length
261                unsafe {
262                    nulls
263                        .extend_trusted_len(levels[start..].iter().map(|level| level == max_level));
264                }
265
266                Ok((values_read, levels_read))
267            }
268            (BufferInner::Mask { nulls }, MaybePacked::Packed(decoder)) => {
269                assert_eq!(self.max_level, 1);
270
271                // Fast path: if all requested levels are valid (max definition level),
272                // we can skip RLE decoding and just append all-ones to the bitmap.
273                // This is faster than decoding RLE data.
274                if let Some(count) = decoder.try_consume_all_valid(num_levels)? {
275                    nulls.append_n(count, true);
276                    return Ok((count, count)); // values_read == levels_read when all valid
277                }
278
279                // Normal path: decode RLE data into the bitmap
280                let start = nulls.len();
281                let levels_read = decoder.read(nulls, num_levels)?;
282
283                let values_read = count_set_bits(nulls.as_slice(), start..start + levels_read);
284                Ok((values_read, levels_read))
285            }
286            _ => unreachable!("inconsistent null mask"),
287        }
288    }
289
290    fn skip_def_levels(&mut self, num_levels: usize) -> Result<(usize, usize)> {
291        match &mut self.decoder {
292            MaybePacked::Fallback(decoder) => decoder.skip_def_levels(num_levels),
293            MaybePacked::Packed(decoder) => decoder.skip(num_levels),
294        }
295    }
296}
297
298/// An optimized decoder for decoding [RLE] and [BIT_PACKED] data with a bit width of 1
299/// directly into a bitmask
300///
301/// This is significantly faster than decoding the data into `[i16]` and then computing
302/// a bitmask from this, as not only can it skip this buffer allocation and construction,
303/// but it can exploit properties of the encoded data to reduce work further
304///
305/// In particular:
306///
307/// * Packed runs are already bitmask encoded and can simply be appended
308/// * Runs of 1 or 0 bits can be efficiently appended with byte (or larger) operations
309///
310/// [RLE]: https://github.com/apache/parquet-format/blob/master/Encodings.md#run-length-encoding--bit-packing-hybrid-rle--3
311/// [BIT_PACKED]: https://github.com/apache/parquet-format/blob/master/Encodings.md#bit-packed-deprecated-bit_packed--4
312struct PackedDecoder {
313    data: Bytes,
314    data_offset: usize,
315    rle_left: usize,
316    rle_value: bool,
317    packed_count: usize,
318    packed_offset: usize,
319}
320
321impl PackedDecoder {
322    fn next_rle_block(&mut self) -> Result<()> {
323        let indicator_value = self.decode_header()?;
324        if indicator_value & 1 == 1 {
325            let len = (indicator_value >> 1) as usize;
326            self.packed_count = len * 8;
327            self.packed_offset = 0;
328        } else {
329            self.rle_left = (indicator_value >> 1) as usize;
330            let byte = *self.data.as_ref().get(self.data_offset).ok_or_else(|| {
331                ParquetError::EOF(
332                    "unexpected end of file whilst decoding definition levels rle value".into(),
333                )
334            })?;
335
336            self.data_offset += 1;
337            self.rle_value = byte != 0;
338        }
339        Ok(())
340    }
341
342    /// Decodes a VLQ encoded little endian integer and returns it
343    fn decode_header(&mut self) -> Result<i64> {
344        let mut offset = 0;
345        let mut v: i64 = 0;
346        while offset < 10 {
347            let byte = *self
348                .data
349                .as_ref()
350                .get(self.data_offset + offset)
351                .ok_or_else(|| {
352                    ParquetError::EOF(
353                        "unexpected end of file whilst decoding definition levels rle header"
354                            .into(),
355                    )
356                })?;
357
358            v |= ((byte & 0x7F) as i64) << (offset * 7);
359            offset += 1;
360            if byte & 0x80 == 0 {
361                self.data_offset += offset;
362                return Ok(v);
363            }
364        }
365        Err(general_err!("too many bytes for VLQ"))
366    }
367}
368
369impl PackedDecoder {
370    fn new() -> Self {
371        Self {
372            data: Bytes::from(vec![]),
373            data_offset: 0,
374            rle_left: 0,
375            rle_value: false,
376            packed_count: 0,
377            packed_offset: 0,
378        }
379    }
380
381    fn set_data(&mut self, encoding: Encoding, data: Bytes) {
382        self.rle_left = 0;
383        self.rle_value = false;
384        self.packed_offset = 0;
385        self.packed_count = match encoding {
386            Encoding::RLE => 0,
387            #[expect(deprecated)]
388            Encoding::BIT_PACKED => data.len() * 8,
389            _ => unreachable!("invalid level encoding: {}", encoding),
390        };
391        self.data = data;
392        self.data_offset = 0;
393    }
394
395    /// Try to consume `len` levels if all are valid (max definition level).
396    ///
397    /// Returns `Ok(Some(count))` if successfully consumed `count` all-valid levels.
398    /// Returns `Ok(None)` if there are any nulls or packed data that prevents fast path.
399    ///
400    /// Note: On `None`, the decoder state may have advanced to the next RLE block,
401    /// but only if `rle_left` was zero (i.e., the block would have been loaded
402    /// on the next read anyway).
403    fn try_consume_all_valid(&mut self, len: usize) -> Result<Option<usize>> {
404        // If no active run and no packed data pending, try to parse the next RLE block
405        if self.rle_left == 0 && self.packed_count == self.packed_offset {
406            if self.data_offset < self.data.len() {
407                self.next_rle_block()?;
408            } else {
409                // No more data available
410                return Ok(None);
411            }
412        }
413
414        // Fast path only works when we have an active RLE run of true values
415        // that covers the entire requested length.
416        if self.rle_left >= len && self.rle_value {
417            self.rle_left -= len;
418            return Ok(Some(len));
419        }
420
421        // Any other case (null run, packed data, or insufficient length)
422        // falls back to normal path
423        Ok(None)
424    }
425
426    fn read(&mut self, buffer: &mut BooleanBufferBuilder, len: usize) -> Result<usize> {
427        let mut read = 0;
428        while read != len {
429            if self.rle_left != 0 {
430                let to_read = self.rle_left.min(len - read);
431                buffer.append_n(to_read, self.rle_value);
432                self.rle_left -= to_read;
433                read += to_read;
434            } else if self.packed_count != self.packed_offset {
435                let to_read = (self.packed_count - self.packed_offset).min(len - read);
436                let offset = self.data_offset * 8 + self.packed_offset;
437                buffer.append_packed_range(offset..offset + to_read, self.data.as_ref());
438                self.packed_offset += to_read;
439                read += to_read;
440
441                if self.packed_offset == self.packed_count {
442                    self.data_offset += self.packed_count / 8;
443                }
444            } else if self.data_offset == self.data.len() {
445                break;
446            } else {
447                self.next_rle_block()?
448            }
449        }
450        Ok(read)
451    }
452
453    /// Skips `level_num` definition levels
454    ///
455    /// Returns the number of values skipped and the number of levels skipped
456    fn skip(&mut self, level_num: usize) -> Result<(usize, usize)> {
457        let mut skipped_value = 0;
458        let mut skipped_level = 0;
459        while skipped_level != level_num {
460            if self.rle_left != 0 {
461                let to_skip = self.rle_left.min(level_num - skipped_level);
462                self.rle_left -= to_skip;
463                skipped_level += to_skip;
464                if self.rle_value {
465                    skipped_value += to_skip;
466                }
467            } else if self.packed_count != self.packed_offset {
468                let to_skip =
469                    (self.packed_count - self.packed_offset).min(level_num - skipped_level);
470                let offset = self.data_offset * 8 + self.packed_offset;
471                let bit_chunk = UnalignedBitChunk::new(self.data.as_ref(), offset, to_skip);
472                skipped_value += bit_chunk.count_ones();
473                self.packed_offset += to_skip;
474                skipped_level += to_skip;
475                if self.packed_offset == self.packed_count {
476                    self.data_offset += self.packed_count / 8;
477                }
478            } else if self.data_offset == self.data.len() {
479                break;
480            } else {
481                self.next_rle_block()?
482            }
483        }
484        Ok((skipped_value, skipped_level))
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use super::*;
491
492    use crate::encodings::rle::RleEncoder;
493    use rand::{RngExt, rng};
494
495    #[test]
496    fn test_build_validity_bitmap_unfiltered_word_chunk() {
497        // 65 levels forces the unfiltered path to process one full u64 word
498        // with append_word, plus a remainder bit.
499        let def_levels = (0..65)
500            .map(|i| if i % 3 == 0 { 2 } else { 1 })
501            .collect::<Vec<_>>();
502        let mut bitmap = BooleanBufferBuilder::new(0);
503
504        assert_eq!(
505            build_filtered_validity_bitmap(&def_levels, None, None, 2, &mut bitmap),
506            def_levels.len()
507        );
508
509        let bitmap = bitmap.finish();
510        for (idx, def) in def_levels.iter().enumerate() {
511            assert_eq!(bitmap.value(idx), *def >= 2);
512        }
513    }
514
515    #[test]
516    fn test_packed_decoder() {
517        let mut rng = rng();
518        let len: usize = rng.random_range(512..1024);
519
520        let mut expected = BooleanBufferBuilder::new(len);
521        let mut encoder = RleEncoder::new(1, 1024);
522        for _ in 0..len {
523            let bool = rng.random_bool(0.8);
524            encoder.put(bool as u64);
525            expected.append(bool);
526        }
527        assert_eq!(expected.len(), len);
528
529        let encoded = encoder.consume();
530        let mut decoder = PackedDecoder::new();
531        decoder.set_data(Encoding::RLE, encoded.into());
532
533        // Decode data in random length intervals
534        let mut decoded = BooleanBufferBuilder::new(len);
535        loop {
536            let remaining = len - decoded.len();
537            if remaining == 0 {
538                break;
539            }
540
541            let to_read = rng.random_range(1..=remaining);
542            decoder.read(&mut decoded, to_read).unwrap();
543        }
544
545        assert_eq!(decoded.len(), len);
546        assert_eq!(decoded.as_slice(), expected.as_slice());
547    }
548
549    #[test]
550    fn test_packed_decoder_skip() {
551        let mut rng = rng();
552        let len: usize = rng.random_range(512..1024);
553
554        let mut expected = BooleanBufferBuilder::new(len);
555        let mut encoder = RleEncoder::new(1, 1024);
556
557        let mut total_value = 0;
558        for _ in 0..len {
559            let bool = rng.random_bool(0.8);
560            encoder.put(bool as u64);
561            expected.append(bool);
562            if bool {
563                total_value += 1;
564            }
565        }
566        assert_eq!(expected.len(), len);
567
568        let encoded = encoder.consume();
569        let mut decoder = PackedDecoder::new();
570        decoder.set_data(Encoding::RLE, encoded.into());
571
572        let mut skip_value = 0;
573        let mut read_value = 0;
574        let mut skip_level = 0;
575        let mut read_level = 0;
576
577        loop {
578            let offset = skip_level + read_level;
579            let remaining_levels = len - offset;
580            if remaining_levels == 0 {
581                break;
582            }
583            let to_read_or_skip_level = rng.random_range(1..=remaining_levels);
584            if rng.random_bool(0.5) {
585                let (skip_val_num, skip_level_num) = decoder.skip(to_read_or_skip_level).unwrap();
586                skip_value += skip_val_num;
587                skip_level += skip_level_num
588            } else {
589                let mut decoded = BooleanBufferBuilder::new(to_read_or_skip_level);
590                let read_level_num = decoder.read(&mut decoded, to_read_or_skip_level).unwrap();
591                read_level += read_level_num;
592                for i in 0..read_level_num {
593                    assert!(!decoded.is_empty());
594                    //check each read bit
595                    let read_bit = decoded.get_bit(i);
596                    if read_bit {
597                        read_value += 1;
598                    }
599                    let expect_bit = expected.get_bit(i + offset);
600                    assert_eq!(read_bit, expect_bit);
601                }
602            }
603        }
604        assert_eq!(read_level + skip_level, len);
605        assert_eq!(read_value + skip_value, total_value);
606    }
607
608    #[test]
609    fn test_try_consume_all_valid() {
610        // Test with all-valid data (all 1s) - single RLE run
611        let len = 100;
612        let mut encoder = RleEncoder::new(1, 1024);
613        for _ in 0..len {
614            encoder.put(1); // all valid
615        }
616        let encoded = encoder.consume();
617        let mut decoder = PackedDecoder::new();
618        decoder.set_data(Encoding::RLE, encoded.into());
619
620        // try_consume_all_valid now parses the RLE block itself, no need to read first
621        let result = decoder.try_consume_all_valid(len).unwrap();
622        assert_eq!(result, Some(len));
623
624        // Test with all-null data (all 0s)
625        let mut encoder = RleEncoder::new(1, 1024);
626        for _ in 0..len {
627            encoder.put(0); // all null
628        }
629        let encoded = encoder.consume();
630        let mut decoder = PackedDecoder::new();
631        decoder.set_data(Encoding::RLE, encoded.into());
632
633        // Should return None because rle_value is false (all nulls)
634        let result = decoder.try_consume_all_valid(len).unwrap();
635        assert_eq!(result, None);
636
637        // Test when requesting more than available in current RLE run
638        let mut encoder = RleEncoder::new(1, 1024);
639        for _ in 0..10 {
640            encoder.put(1); // small run of valid
641        }
642        for _ in 0..10 {
643            encoder.put(0); // followed by nulls
644        }
645        let encoded = encoder.consume();
646        let mut decoder = PackedDecoder::new();
647        decoder.set_data(Encoding::RLE, encoded.into());
648
649        // Request more than the valid run - should return None
650        // (because we don't look ahead to next block)
651        let result = decoder.try_consume_all_valid(20).unwrap();
652        assert_eq!(result, None);
653
654        // Reset decoder and try requesting within the run
655        decoder.set_data(Encoding::RLE, {
656            let mut encoder = RleEncoder::new(1, 1024);
657            for _ in 0..10 {
658                encoder.put(1);
659            }
660            for _ in 0..10 {
661                encoder.put(0);
662            }
663            encoder.consume().into()
664        });
665
666        let result = decoder.try_consume_all_valid(5).unwrap();
667        assert_eq!(result, Some(5));
668
669        // After skipping 5, we should have 5 left in the valid RLE run
670        let result = decoder.try_consume_all_valid(5).unwrap();
671        assert_eq!(result, Some(5));
672
673        // Now the valid run is exhausted, next call should parse the null run and return None
674        let result = decoder.try_consume_all_valid(5).unwrap();
675        assert_eq!(result, None);
676    }
677}