use basic::{PageType, Encoding};
use errors::Result;
use file::metadata::ColumnChunkMetaData;
use file::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: compressed_page,
uncompressed_size: 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]);
}
}