diff --git a/src/cache/check.rs b/src/cache/check.rs index 01882e2..ac05336 100644 --- a/src/cache/check.rs +++ b/src/cache/check.rs @@ -8,7 +8,7 @@ use crate::cache::hint::*; use crate::cache::mapping::*; use crate::cache::superblock::*; use crate::io_engine::{AsyncIoEngine, IoEngine, SyncIoEngine}; -use crate::pdata::array; +use crate::pdata::array::{self, ArrayBlock, ArrayError}; use crate::pdata::array_walker::*; use crate::pdata::bitset_walker::*; @@ -54,23 +54,40 @@ mod format1 { if m.oblock >= self.nr_origin_blocks { return Err(array::value_err(format!("mapping beyond end of the origin device"))); } - let mut seen_oblocks = self.seen_oblocks.lock().unwrap(); if seen_oblocks.contains(&m.oblock) { return Err(array::value_err(format!("origin block already mapped"))); } seen_oblocks.insert(m.oblock); - Ok(()) } } impl ArrayVisitor for MappingChecker { - fn visit(&self, _index: u64, m: Mapping) -> array::Result<()> { - self.check_flags(&m)?; - self.check_oblock(&m)?; + fn visit(&self, _index: u64, b: ArrayBlock) -> array::Result<()> { + let mut errs: Vec = Vec::new(); - Ok(()) + for i in 0..b.header.nr_entries as usize { + let m = b.values[i]; + + if let Err(e) = self.check_flags(&m) { + errs.push(e); + } + if let Err(e) = self.check_oblock(&m) { + errs.push(e); + } + } + + // FIXME: duplicate to BTreeWalker::build_aggregrate() + match errs.len() { + 0 => Ok(()), + 1 => { + Err(errs[0].clone()) + } + _ => { + Err(array::aggregate_error(errs)) + } + } } } } @@ -129,12 +146,32 @@ mod format2 { } impl ArrayVisitor for MappingChecker { - fn visit(&self, index: u64, m: Mapping) -> array::Result<()> { + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { let mut inner = self.inner.lock().unwrap(); - self.check_flags(&m, inner.dirty_bits.contains(index as usize))?; - self.check_oblock(&m, &mut inner.seen_oblocks)?; + let mut errs: Vec = Vec::new(); - Ok(()) + let begin = index as usize * b.header.max_entries as usize; + for i in 0..b.header.nr_entries { + let m = b.values[i as usize]; + + if let Err(e) = self.check_flags(&m, inner.dirty_bits.contains(begin + i as usize)) { + errs.push(e); + } + if let Err(e) = self.check_oblock(&m, &mut inner.seen_oblocks) { + errs.push(e); + } + } + + // FIXME: duplicate to BTreeWalker::build_aggregrate() + match errs.len() { + 0 => Ok(()), + 1 => { + Err(errs[0].clone()) + } + _ => { + Err(array::aggregate_error(errs)) + } + } } } } @@ -150,7 +187,7 @@ impl HintChecker { } impl ArrayVisitor for HintChecker { - fn visit(&self, _index: u64, _hint: Hint) -> array::Result<()> { + fn visit(&self, _index: u64, _b: ArrayBlock) -> array::Result<()> { // TODO: check hints Ok(()) } diff --git a/src/cache/dump.rs b/src/cache/dump.rs index 9a21eed..235ef8a 100644 --- a/src/cache/dump.rs +++ b/src/cache/dump.rs @@ -8,7 +8,7 @@ use crate::cache::mapping::Mapping; use crate::cache::superblock::*; use crate::cache::xml::{self, MetadataVisitor}; use crate::io_engine::{AsyncIoEngine, IoEngine, SyncIoEngine}; -use crate::pdata::array; +use crate::pdata::array::{self, ArrayBlock}; use crate::pdata::array_walker::*; //------------------------------------------ @@ -46,12 +46,17 @@ mod format1 { } impl<'a> ArrayVisitor for MappingEmitter<'a> { - fn visit(&self, index: u64, m: Mapping) -> array::Result<()> { - if m.is_valid() { + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { + for i in 0..b.header.nr_entries as usize { + let map = b.values[i]; + if !map.is_valid() { + continue; + } + let m = xml::Map { cblock: index as u32, - oblock: m.oblock, - dirty: m.is_dirty(), + oblock: map.oblock, + dirty: map.is_dirty(), }; let mut inner = self.inner.lock().unwrap(); @@ -79,7 +84,7 @@ mod format2 { impl DirtyVisitor { pub fn new(nr_entries: usize) -> Self { DirtyVisitor { - nr_entries, + nr_entries, // number of bits bits: Mutex::new(FixedBitSet::with_capacity(nr_entries)), } } @@ -90,13 +95,19 @@ mod format2 { } impl ArrayVisitor for DirtyVisitor { - fn visit(&self, index: u64, bits: u64) -> array::Result<()> { - for i in 0..64u64 { - if (index + i) >= self.nr_entries as u64 { - break; - } + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { + let mut pos = index as usize * (b.header.max_entries as usize) << 6; + for i in 0..b.header.nr_entries as usize { + let bits = b.values[i]; - self.bits.lock().unwrap().set((index + i) as usize, bits & (1 << i) != 0); + for bi in 0..64u64 { + if pos >= self.nr_entries { + break; + } + + self.bits.lock().unwrap().set(pos, bits & (1 << bi) != 0); + pos += 1; + } } Ok(()) } @@ -133,20 +144,25 @@ mod format2 { } impl<'a> ArrayVisitor for MappingEmitter<'a> { - fn visit(&self, index: u64, m: Mapping) -> array::Result<()> { - if m.is_valid() { + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { + for i in 0..b.header.nr_entries as usize { + let map = b.values[i]; + + if !map.is_valid() { + continue; + } + let mut inner = self.inner.lock().unwrap(); let dirty = inner.dirty_bits.contains(index as usize); let m = xml::Map { cblock: index as u32, - oblock: m.oblock, + oblock: map.oblock, dirty, }; inner.valid_mappings.set(index as usize, true); inner.visitor.mapping(&m).map_err(|e| array::value_err(format!("{}", e)))?; } - Ok(()) } } @@ -169,10 +185,16 @@ impl<'a> HintEmitter<'a> { } impl<'a> ArrayVisitor for HintEmitter<'a> { - fn visit(&self, index: u64, hint: Hint) -> array::Result<()> { - if self.valid_mappings.contains(index as usize) { + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { + let mut cblock = index as u32 * b.header.max_entries; + for i in 0..b.header.nr_entries as usize { + if !self.valid_mappings.contains(cblock as usize) { + continue; + } + + let hint = b.values[i]; let h = xml::Hint { - cblock: index as u32, + cblock, data: hint.hint.to_vec(), }; @@ -181,6 +203,8 @@ impl<'a> ArrayVisitor for HintEmitter<'a> { .unwrap() .hint(&h) .map_err(|e| array::value_err(format!("{}", e)))?; + + cblock += 1; } Ok(()) diff --git a/src/pdata/array_walker.rs b/src/pdata/array_walker.rs index fe0dcda..a9f033b 100644 --- a/src/pdata/array_walker.rs +++ b/src/pdata/array_walker.rs @@ -14,7 +14,7 @@ pub struct ArrayWalker { } pub trait ArrayVisitor { - fn visit(&self, index: u64, v: V) -> array::Result<()>; + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()>; } //------------------------------------------ @@ -37,28 +37,6 @@ impl<'a, V: Unpack + Copy> BlockValueVisitor<'a, V> { array_errs: Mutex::new(Vec::new()), } } - - fn visit_array_block(&self, index: u64, array_block: ArrayBlock) -> array::Result<()>{ - let mut errs: Vec = Vec::new(); - - let begin = index * array_block.header.max_entries as u64; - for i in 0..array_block.header.nr_entries { - if let Err(e) = self.array_visitor.visit(begin + i as u64, array_block.values[i as usize]) { - errs.push(e); // TODO: add path or keys context? - } - } - - // FIXME: duplicate to BTreeWalker::build_aggregrate() - match errs.len() { - 0 => Ok(()), - 1 => { - Err(errs[0].clone()) - } - _ => { - Err(array::aggregate_error(errs)) - } - } - } } impl<'a, V: Unpack + Copy> NodeVisitor for BlockValueVisitor<'a, V> { @@ -89,7 +67,7 @@ impl<'a, V: Unpack + Copy> NodeVisitor for BlockValueVisitor<'a, V> { path.push(values[n]); match unpack_array_block::(&path, b.get_data()) { Ok(array_block) => { - if let Err(e) = self.visit_array_block(*index, array_block) { + if let Err(e) = self.array_visitor.visit(*index, array_block) { self.array_errs.lock().unwrap().push(e); } }, diff --git a/src/pdata/bitset_walker.rs b/src/pdata/bitset_walker.rs index a75bae9..7cc7b7f 100644 --- a/src/pdata/bitset_walker.rs +++ b/src/pdata/bitset_walker.rs @@ -2,7 +2,7 @@ use fixedbitset::FixedBitSet; use std::sync::{Arc, Mutex}; use crate::io_engine::IoEngine; -use crate::pdata::array; +use crate::pdata::array::{self, ArrayBlock}; use crate::pdata::array_walker::{ArrayVisitor, ArrayWalker}; struct BitsetVisitor<'a> { @@ -20,23 +20,28 @@ impl<'a> BitsetVisitor<'a> { } impl<'a> ArrayVisitor for BitsetVisitor<'a> { - fn visit(&self, index: u64, bits: u64) -> array::Result<()> { - let begin: u64 = index << 6; - if begin > self.nr_entries { - return Err(array::value_err("bitset size exceeds expectation".to_string())); - } + fn visit(&self, index: u64, b: ArrayBlock) -> array::Result<()> { + let mut begin = index as usize * (b.header.max_entries as usize) << 6; - let end: u64 = std::cmp::min(begin + 64, self.nr_entries); - let mut mask = 1; - for i in begin..end { - self.bits.lock().unwrap().set(i as usize, bits & mask != 0); - mask <<= 1; + for i in 0..b.header.nr_entries as usize { + if begin > self.nr_entries as usize { + return Err(array::value_err("bitset size exceeds expectation".to_string())); + } + + let end: usize = std::cmp::min(begin + 64, self.nr_entries as usize); + let mut mask = 1; + let bits = b.values[i]; + + for bi in begin..end { + self.bits.lock().unwrap().set(bi, bits & mask != 0); + mask <<= 1; + } + begin += 64; } Ok(()) } } -// TODO: remap errors // TODO: multi-threaded is possible pub fn read_bitset( engine: Arc,