use basic::{Encoding, PageType};
use errors::Result;
use file::{metadata::ColumnChunkMetaData, statistics::Statistics};
use util::memory::ByteBufferPtr;
pub enum Page {
DataPage {
buf: ByteBufferPtr,
num_values: u32,
encoding: Encoding,
def_level_encoding: Encoding,
rep_level_encoding: Encoding,
statistics: Option<Statistics>,
},
DataPageV2 {
buf: ByteBufferPtr,
num_values: u32,
encoding: Encoding,
num_nulls: u32,
num_rows: u32,
def_levels_byte_len: u32,
rep_levels_byte_len: u32,
is_compressed: bool,
statistics: Option<Statistics>,
},
DictionaryPage {
buf: ByteBufferPtr,
num_values: u32,
encoding: Encoding,
is_sorted: bool,
},
}
impl Page {
pub fn page_type(&self) -> PageType {
match self {
&Page::DataPage { .. } => PageType::DATA_PAGE,
&Page::DataPageV2 { .. } => PageType::DATA_PAGE_V2,
&Page::DictionaryPage { .. } => PageType::DICTIONARY_PAGE,
}
}
pub fn buffer(&self) -> &ByteBufferPtr {
match self {
&Page::DataPage { ref buf, .. } => &buf,
&Page::DataPageV2 { ref buf, .. } => &buf,
&Page::DictionaryPage { ref buf, .. } => &buf,
}
}
pub fn num_values(&self) -> u32 {
match self {
&Page::DataPage { num_values, .. } => num_values,
&Page::DataPageV2 { num_values, .. } => num_values,
&Page::DictionaryPage { num_values, .. } => num_values,
}
}
pub fn encoding(&self) -> Encoding {
match self {
&Page::DataPage { encoding, .. } => encoding,
&Page::DataPageV2 { encoding, .. } => encoding,
&Page::DictionaryPage { encoding, .. } => encoding,
}
}
pub fn statistics(&self) -> Option<&Statistics> {
match self {
&Page::DataPage { ref statistics, .. } => statistics.as_ref(),
&Page::DataPageV2 { ref statistics, .. } => statistics.as_ref(),
&Page::DictionaryPage { .. } => None,
}
}
}
pub struct CompressedPage {
compressed_page: Page,
uncompressed_size: usize,
}
impl CompressedPage {
pub fn new(compressed_page: Page, uncompressed_size: usize) -> Self {
Self {
compressed_page,
uncompressed_size,
}
}
pub fn page_type(&self) -> PageType { self.compressed_page.page_type() }
pub fn compressed_page(&self) -> &Page { &self.compressed_page }
pub fn uncompressed_size(&self) -> usize { self.uncompressed_size }
pub fn compressed_size(&self) -> usize { self.compressed_page.buffer().len() }
pub fn num_values(&self) -> u32 { self.compressed_page.num_values() }
pub fn encoding(&self) -> Encoding { self.compressed_page.encoding() }
pub fn data(&self) -> &[u8] { self.compressed_page.buffer().data() }
}
pub struct PageWriteSpec {
pub page_type: PageType,
pub uncompressed_size: usize,
pub compressed_size: usize,
pub num_values: u32,
pub offset: u64,
pub bytes_written: u64,
}
impl PageWriteSpec {
pub fn new() -> Self {
Self {
page_type: PageType::DATA_PAGE,
uncompressed_size: 0,
compressed_size: 0,
num_values: 0,
offset: 0,
bytes_written: 0,
}
}
}
pub trait PageReader {
fn get_next_page(&mut self) -> Result<Option<Page>>;
}
pub trait PageWriter {
fn write_page(&mut self, page: CompressedPage) -> Result<PageWriteSpec>;
fn write_metadata(&mut self, metadata: &ColumnChunkMetaData) -> Result<()>;
fn close(&mut self) -> Result<()>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_page() {
let data_page = Page::DataPage {
buf: ByteBufferPtr::new(vec![0, 1, 2]),
num_values: 10,
encoding: Encoding::PLAIN,
def_level_encoding: Encoding::RLE,
rep_level_encoding: Encoding::RLE,
statistics: Some(Statistics::int32(Some(1), Some(2), None, 1, true)),
};
assert_eq!(data_page.page_type(), PageType::DATA_PAGE);
assert_eq!(data_page.buffer().data(), vec![0, 1, 2].as_slice());
assert_eq!(data_page.num_values(), 10);
assert_eq!(data_page.encoding(), Encoding::PLAIN);
assert_eq!(
data_page.statistics(),
Some(&Statistics::int32(Some(1), Some(2), None, 1, true))
);
let data_page_v2 = Page::DataPageV2 {
buf: ByteBufferPtr::new(vec![0, 1, 2]),
num_values: 10,
encoding: Encoding::PLAIN,
num_nulls: 5,
num_rows: 20,
def_levels_byte_len: 30,
rep_levels_byte_len: 40,
is_compressed: false,
statistics: Some(Statistics::int32(Some(1), Some(2), None, 1, true)),
};
assert_eq!(data_page_v2.page_type(), PageType::DATA_PAGE_V2);
assert_eq!(data_page_v2.buffer().data(), vec![0, 1, 2].as_slice());
assert_eq!(data_page_v2.num_values(), 10);
assert_eq!(data_page_v2.encoding(), Encoding::PLAIN);
assert_eq!(
data_page_v2.statistics(),
Some(&Statistics::int32(Some(1), Some(2), None, 1, true))
);
let dict_page = Page::DictionaryPage {
buf: ByteBufferPtr::new(vec![0, 1, 2]),
num_values: 10,
encoding: Encoding::PLAIN,
is_sorted: false,
};
assert_eq!(dict_page.page_type(), PageType::DICTIONARY_PAGE);
assert_eq!(dict_page.buffer().data(), vec![0, 1, 2].as_slice());
assert_eq!(dict_page.num_values(), 10);
assert_eq!(dict_page.encoding(), Encoding::PLAIN);
assert_eq!(dict_page.statistics(), None);
}
#[test]
fn test_compressed_page() {
let data_page = Page::DataPage {
buf: ByteBufferPtr::new(vec![0, 1, 2]),
num_values: 10,
encoding: Encoding::PLAIN,
def_level_encoding: Encoding::RLE,
rep_level_encoding: Encoding::RLE,
statistics: Some(Statistics::int32(Some(1), Some(2), None, 1, true)),
};
let cpage = CompressedPage::new(data_page, 5);
assert_eq!(cpage.page_type(), PageType::DATA_PAGE);
assert_eq!(cpage.uncompressed_size(), 5);
assert_eq!(cpage.compressed_size(), 3);
assert_eq!(cpage.num_values(), 10);
assert_eq!(cpage.encoding(), Encoding::PLAIN);
assert_eq!(cpage.data(), &[0, 1, 2]);
}
}