[thin_check (rust)] Reimplement CoreSpaceMap
We now use a simple vector of elements that can hold 'nr thin devs'. Much faster.
This commit is contained in:
		| @@ -1,6 +1,6 @@ | |||||||
| use anyhow::{anyhow, Result}; | use anyhow::{anyhow, Result}; | ||||||
| use nom::{number::complete::*, IResult}; | use nom::{number::complete::*, IResult}; | ||||||
| use std::collections::BTreeMap; | use std::sync::{Arc, Mutex}; | ||||||
|  |  | ||||||
| use crate::block_manager::*; | use crate::block_manager::*; | ||||||
| use crate::pdata::btree::Unpack; | use crate::pdata::btree::Unpack; | ||||||
| @@ -150,97 +150,49 @@ impl Unpack for Bitmap { | |||||||
|  |  | ||||||
| //------------------------------------------ | //------------------------------------------ | ||||||
|  |  | ||||||
| const ENTRIES_PER_WORD: u64 = 32; | pub trait SpaceMap { | ||||||
|  |     fn get(&self, b: u64) -> Result<u32>; | ||||||
| pub struct CoreSpaceMap { |     fn inc(&mut self, begin: u64, len: u64) -> Result<()>; | ||||||
|     nr_entries: u64, |  | ||||||
|     bits: Vec<u64>, |  | ||||||
|     overflow: BTreeMap<u64, u32>, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl CoreSpaceMap { | pub struct CoreSpaceMap<T> { | ||||||
|     pub fn new(nr_entries: u64) -> CoreSpaceMap { |     counts: Vec<T>, | ||||||
|         let nr_words = (nr_entries + ENTRIES_PER_WORD - 1) / ENTRIES_PER_WORD; | } | ||||||
|  |  | ||||||
|  | impl<V> CoreSpaceMap<V> | ||||||
|  | where | ||||||
|  |     V: Copy + Default + std::ops::AddAssign + From<u8>, | ||||||
|  | { | ||||||
|  |     pub fn new(nr_entries: u64) -> CoreSpaceMap<V> { | ||||||
|         CoreSpaceMap { |         CoreSpaceMap { | ||||||
|             nr_entries, |             counts: vec![V::default(); nr_entries as usize], | ||||||
|             bits: vec![0; nr_words as usize], |         } | ||||||
|             overflow: BTreeMap::new(), |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|     fn check_bounds(&self, b: u64) -> Result<()> { | impl<V> SpaceMap for CoreSpaceMap<V> | ||||||
|         if b >= self.nr_entries { | where | ||||||
|             return Err(anyhow!("space map index out of bounds")); |     V: Copy + Default + std::ops::AddAssign + From<u8> + Into<u32>, | ||||||
|  |     { | ||||||
|  |     fn get(&self, b: u64) -> Result<u32> { | ||||||
|  |         Ok(self.counts[b as usize].into()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn inc(&mut self, begin: u64, len: u64) -> Result<()> { | ||||||
|  |         for b in begin..(begin + len) { | ||||||
|  |             self.counts[b as usize] += V::from(1u8); | ||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_index(b: u64) -> (usize, usize) { |  | ||||||
|         ( |  | ||||||
|             (b / ENTRIES_PER_WORD) as usize, |  | ||||||
|             ((b & (ENTRIES_PER_WORD - 1)) as usize) * 2, |  | ||||||
|         ) |  | ||||||
| } | } | ||||||
|  |  | ||||||
|     fn get_bits(&self, b: u64) -> Result<u32> { | pub fn core_sm(nr_entries: u64, max_count: u32) -> Arc<Mutex<dyn SpaceMap + Send>> { | ||||||
|         self.check_bounds(b)?; |     if max_count <= u8::MAX as u32 { | ||||||
|  |         Arc::new(Mutex::new(CoreSpaceMap::<u8>::new(nr_entries))) | ||||||
|         let result; |     } else if max_count <= u16::MAX as u32 { | ||||||
|         let (w, bit) = CoreSpaceMap::get_index(b); |         Arc::new(Mutex::new(CoreSpaceMap::<u16>::new(nr_entries))) | ||||||
|         unsafe { |  | ||||||
|             let word = self.bits.get_unchecked(w); |  | ||||||
|             result = (*word >> bit) & 0x3; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(result as u32) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn get(&self, b: u64) -> Result<u32> { |  | ||||||
|         let result = self.get_bits(b)?; |  | ||||||
|         if result < 3 { |  | ||||||
|             Ok(result) |  | ||||||
|     } else { |     } else { | ||||||
|             match self.overflow.get(&b) { |         Arc::new(Mutex::new(CoreSpaceMap::<u32>::new(nr_entries))) | ||||||
|                 None => Err(anyhow!( |  | ||||||
|                     "internal error: missing overflow entry in space map" |  | ||||||
|                 )), |  | ||||||
|                 Some(result) => Ok(*result), |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn inc(&mut self, b: u64) -> Result<()> { |  | ||||||
|         self.check_bounds(b)?; |  | ||||||
|  |  | ||||||
|         let (w, bit) = CoreSpaceMap::get_index(b); |  | ||||||
|         let count; |  | ||||||
|  |  | ||||||
|         unsafe { |  | ||||||
|             let word = self.bits.get_unchecked_mut(w); |  | ||||||
|             count = (*word >> bit) & 0x3; |  | ||||||
|  |  | ||||||
|             if count < 3 { |  | ||||||
|                 // bump up the bits |  | ||||||
|                 *word = (*word & !(0x3 << bit)) | (((count + 1) as u64) << bit); |  | ||||||
|  |  | ||||||
|                 if count == 2 { |  | ||||||
|                     // insert overflow entry |  | ||||||
|                     self.overflow.insert(b, 1); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if count >= 3 { |  | ||||||
|             if let Some(count) = self.overflow.get_mut(&b) { |  | ||||||
|                 *count = *count + 1; |  | ||||||
|             } else { |  | ||||||
|                 return Err(anyhow!( |  | ||||||
|                     "internal error: missing overflow entry in space map" |  | ||||||
|                 )); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -67,7 +67,7 @@ impl Unpack for BlockTime { | |||||||
| } | } | ||||||
|  |  | ||||||
| struct BottomLevelVisitor { | struct BottomLevelVisitor { | ||||||
|     data_sm: Arc<Mutex<CoreSpaceMap>>, |     data_sm: Arc<Mutex<dyn SpaceMap + Send>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl NodeVisitor<BlockTime> for BottomLevelVisitor { | impl NodeVisitor<BlockTime> for BottomLevelVisitor { | ||||||
| @@ -75,9 +75,23 @@ impl NodeVisitor<BlockTime> for BottomLevelVisitor { | |||||||
|         // FIXME: do other checks |         // FIXME: do other checks | ||||||
|  |  | ||||||
|         if let Node::Leaf {header: _h, keys: _k, values} = node { |         if let Node::Leaf {header: _h, keys: _k, values} = node { | ||||||
|  |             if values.len() > 0 { | ||||||
|                 let mut data_sm = self.data_sm.lock().unwrap(); |                 let mut data_sm = self.data_sm.lock().unwrap(); | ||||||
|             for bt in values { |  | ||||||
|                data_sm.inc(bt.block)?; |                 let mut start = values[0].block; | ||||||
|  |                 let mut len = 1; | ||||||
|  |                  | ||||||
|  |                 for n in 1..values.len() { | ||||||
|  |                    if values[n].block == start + len { | ||||||
|  |                        len += 1; | ||||||
|  |                    } else { | ||||||
|  |                        data_sm.inc(start, len)?; | ||||||
|  |                        start = values[n].block; | ||||||
|  |                        len = 1; | ||||||
|  |                    } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 data_sm.inc(start, len)?; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -256,10 +270,12 @@ pub fn check(dev: &Path) -> Result<()> { | |||||||
|     eprintln!("{:?}", sb); |     eprintln!("{:?}", sb); | ||||||
|  |  | ||||||
|     // device details |     // device details | ||||||
|  |     let nr_devs; | ||||||
|     { |     { | ||||||
|         let mut visitor = DeviceVisitor::new(); |         let mut visitor = DeviceVisitor::new(); | ||||||
|         let mut w = BTreeWalker::new(engine.clone(), false); |         let mut w = BTreeWalker::new(engine.clone(), false); | ||||||
|         w.walk(&mut visitor, sb.details_root)?; |         w.walk(&mut visitor, sb.details_root)?; | ||||||
|  |         nr_devs = visitor.devs.len(); | ||||||
|         println!("found {} devices", visitor.devs.len()); |         println!("found {} devices", visitor.devs.len()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -282,7 +298,7 @@ pub fn check(dev: &Path) -> Result<()> { | |||||||
|         ))); |         ))); | ||||||
|  |  | ||||||
|         let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; |         let root = unpack::<SMRoot>(&sb.data_sm_root[0..])?; | ||||||
|         let data_sm = Arc::new(Mutex::new(CoreSpaceMap::new(root.nr_blocks))); |         let data_sm = core_sm(root.nr_blocks, nr_devs as u32); | ||||||
|  |  | ||||||
|         for (thin_id, root) in roots { |         for (thin_id, root) in roots { | ||||||
|             let mut w = BTreeWalker::new_with_seen(engine.clone(), seen.clone(), false); |             let mut w = BTreeWalker::new_with_seen(engine.clone(), seen.clone(), false); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user