mito2/sst/parquet/
page_reader.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Parquet page reader.
16
17use std::collections::VecDeque;
18
19use parquet::column::page::{Page, PageMetadata, PageReader};
20use parquet::errors::Result;
21
22/// A reader that reads all pages from a cache.
23pub(crate) struct RowGroupCachedReader {
24    /// Cached pages.
25    pages: VecDeque<Page>,
26}
27
28impl RowGroupCachedReader {
29    /// Returns a new reader from pages of a column in a row group.
30    pub(crate) fn new(pages: &[Page]) -> Self {
31        Self {
32            pages: pages.iter().cloned().collect(),
33        }
34    }
35}
36
37impl PageReader for RowGroupCachedReader {
38    fn get_next_page(&mut self) -> Result<Option<Page>> {
39        Ok(self.pages.pop_front())
40    }
41
42    fn peek_next_page(&mut self) -> Result<Option<PageMetadata>> {
43        Ok(self.pages.front().map(page_to_page_meta))
44    }
45
46    fn skip_next_page(&mut self) -> Result<()> {
47        // When the `SerializedPageReader` is in `SerializedPageReaderState::Pages` state, it never pops
48        // the dictionary page. So it always return the dictionary page as the first page. See:
49        // https://github.com/apache/arrow-rs/blob/1d6feeacebb8d0d659d493b783ba381940973745/parquet/src/file/serialized_reader.rs#L766-L770
50        // But the `GenericColumnReader` will read the dictionary page before skipping records so it won't skip dictionary page.
51        // So we don't need to handle the dictionary page specifically in this method.
52        // https://github.com/apache/arrow-rs/blob/65f7be856099d389b0d0eafa9be47fad25215ee6/parquet/src/column/reader.rs#L322-L331
53        self.pages.pop_front();
54        Ok(())
55    }
56}
57
58impl Iterator for RowGroupCachedReader {
59    type Item = Result<Page>;
60    fn next(&mut self) -> Option<Self::Item> {
61        self.get_next_page().transpose()
62    }
63}
64
65/// Get [PageMetadata] from `page`.
66///
67/// The conversion is based on [decode_page()](https://github.com/apache/arrow-rs/blob/1d6feeacebb8d0d659d493b783ba381940973745/parquet/src/file/serialized_reader.rs#L438-L481)
68/// and [PageMetadata](https://github.com/apache/arrow-rs/blob/65f7be856099d389b0d0eafa9be47fad25215ee6/parquet/src/column/page.rs#L279-L301).
69fn page_to_page_meta(page: &Page) -> PageMetadata {
70    match page {
71        Page::DataPage { num_values, .. } => PageMetadata {
72            num_rows: None,
73            num_levels: Some(*num_values as usize),
74            is_dict: false,
75        },
76        Page::DataPageV2 {
77            num_values,
78            num_rows,
79            ..
80        } => PageMetadata {
81            num_rows: Some(*num_rows as usize),
82            num_levels: Some(*num_values as usize),
83            is_dict: false,
84        },
85        Page::DictionaryPage { .. } => PageMetadata {
86            num_rows: None,
87            num_levels: None,
88            is_dict: true,
89        },
90    }
91}