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}