From 087a4711a59c62bec090f8feae5bc90e1f5d64d9 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Wed, 9 Dec 2020 18:40:06 +0800 Subject: [PATCH] [array (rust)] Implement array basis --- src/pdata/array.rs | 39 ++++++++++++++ src/pdata/array_block.rs | 70 ++++++++++++++++++++++++ src/pdata/array_walker.rs | 108 ++++++++++++++++++++++++++++++++++++++ src/pdata/mod.rs | 3 ++ 4 files changed, 220 insertions(+) create mode 100644 src/pdata/array.rs create mode 100644 src/pdata/array_block.rs create mode 100644 src/pdata/array_walker.rs diff --git a/src/pdata/array.rs b/src/pdata/array.rs new file mode 100644 index 0000000..d8299c2 --- /dev/null +++ b/src/pdata/array.rs @@ -0,0 +1,39 @@ +use nom::{number::complete::*, IResult}; +use std::fmt; + +use crate::pdata::unpack::*; + +//------------------------------------------ + +// TODO: build a data structure representating an array? + +// FIXME: rename this struct +pub struct ArrayBlockEntry { + pub block: u64, +} + +impl Unpack for ArrayBlockEntry { + fn disk_size() -> u32 { + 8 + } + + fn unpack(i: &[u8]) -> IResult<&[u8], ArrayBlockEntry> { + let (i, n) = le_u64(i)?; + let block = n; + + Ok(( + i, + ArrayBlockEntry { + block, + } + )) + } +} + +impl fmt::Display for ArrayBlockEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.block) + } +} + +//------------------------------------------ diff --git a/src/pdata/array_block.rs b/src/pdata/array_block.rs new file mode 100644 index 0000000..0cf7069 --- /dev/null +++ b/src/pdata/array_block.rs @@ -0,0 +1,70 @@ +use anyhow::anyhow; +use anyhow::Result; +use nom::{multi::count, number::complete::*, IResult}; + +use crate::pdata::unpack::Unpack; + +//------------------------------------------ + +pub struct ArrayBlockHeader { + pub csum: u32, + pub max_entries: u32, + pub nr_entries: u32, + pub value_size: u32, + pub blocknr: u64, +} + +impl Unpack for ArrayBlockHeader { + fn disk_size() -> u32 { + 24 + } + + fn unpack(data: &[u8]) -> IResult<&[u8], ArrayBlockHeader> { + let (i, csum) = le_u32(data)?; + let (i, max_entries) = le_u32(i)?; + let (i, nr_entries) = le_u32(i)?; + let (i, value_size) = le_u32(i)?; + let (i, blocknr) = le_u64(i)?; + + Ok(( + i, + ArrayBlockHeader { + csum, + max_entries, + nr_entries, + value_size, + blocknr + }, + )) + } +} + +pub struct ArrayBlock { + pub header: ArrayBlockHeader, + pub values: Vec, +} + +impl ArrayBlock { + pub fn get_header(&self) -> &ArrayBlockHeader { + &self.header + } +} + +fn convert_result<'a, V>(r: IResult<&'a [u8], V>) -> Result<(&'a [u8], V)> { + r.map_err(|_| anyhow!("parse error")) +} + +pub fn unpack_array_block( + data: &[u8], +) -> Result> { + // TODO: collect errors + let (i, header) = ArrayBlockHeader::unpack(data).map_err(|_e| anyhow!("Couldn't parse header"))?; + let (_i, values) = convert_result(count(V::unpack, header.nr_entries as usize)(i))?; + + Ok(ArrayBlock { + header, + values, + }) +} + +//------------------------------------------ diff --git a/src/pdata/array_walker.rs b/src/pdata/array_walker.rs new file mode 100644 index 0000000..6322c50 --- /dev/null +++ b/src/pdata/array_walker.rs @@ -0,0 +1,108 @@ +use std::sync::Arc; + +use crate::io_engine::*; +use crate::pdata::array::*; +use crate::pdata::array_block::*; +use crate::pdata::btree::*; +use crate::pdata::btree_walker::*; +use crate::pdata::unpack::*; + +//------------------------------------------ + +pub struct ArrayWalker { + engine: Arc, + ignore_non_fatal: bool +} + +// FIXME: define another Result type for array visiting? +pub trait ArrayBlockVisitor { + fn visit( + &self, + index: u64, + v: V, + ) -> anyhow::Result<()>; +} + +struct BlockValueVisitor { + engine: Arc, + array_block_visitor: Box>, +} + +impl BlockValueVisitor { + pub fn new>( + e: Arc, + v: Box, + ) -> BlockValueVisitor { + BlockValueVisitor { + engine: e, + array_block_visitor: v, + } + } + + pub fn visit_array_block( + &self, + index: u64, + array_block: ArrayBlock, + ) { + let begin = index * u64::from(array_block.header.nr_entries); + for i in 0..array_block.header.nr_entries { + self.array_block_visitor.visit(begin + u64::from(i), array_block.values[i as usize]).unwrap(); + } + } +} + +impl NodeVisitor for BlockValueVisitor { + // FIXME: return errors + fn visit( + &self, + path: &Vec, + _kr: &KeyRange, + _h: &NodeHeader, + keys: &[u64], + values: &[ArrayBlockEntry], + ) -> Result<()> { + for n in 0..keys.len() { + let index = keys[n]; + let b = self.engine.read(values[n].block).map_err(|_| io_err(path))?; + let array_block = unpack_array_block::(b.get_data()).map_err(|_| io_err(path))?; + self.visit_array_block(index, array_block); + } + Ok(()) + } + + // FIXME: stub + fn visit_again(&self, _path: &Vec, _b: u64) -> Result<()> { + Ok(()) + } + + // FIXME: stub + fn end_walk(&self) -> Result<()> { + Ok(()) + } +} + +impl ArrayWalker { + pub fn new(engine: Arc, ignore_non_fatal: bool) -> ArrayWalker { + let r: ArrayWalker = ArrayWalker { + engine, + ignore_non_fatal, + }; + r + } + + // FIXME: pass the visitor by reference? + // FIXME: redefine the Result type for array visiting? + pub fn walk(&self, visitor: Box, root: u64) -> Result<()> + where + BV: 'static + ArrayBlockVisitor, + V: Unpack, + { + let w = BTreeWalker::new(self.engine.clone(), self.ignore_non_fatal); + let mut path = Vec::new(); // FIXME: eliminate this line? + path.push(0); + let v = BlockValueVisitor::::new(self.engine.clone(), visitor); + w.walk(&mut path, &v, root) + } +} + +//------------------------------------------ diff --git a/src/pdata/mod.rs b/src/pdata/mod.rs index 26a7318..370d244 100644 --- a/src/pdata/mod.rs +++ b/src/pdata/mod.rs @@ -1,3 +1,6 @@ +pub mod array; +pub mod array_block; +pub mod array_walker; pub mod btree; pub mod btree_builder; pub mod btree_merge;