[thin_check (rust)] speed up CoreSpaceMap

This commit is contained in:
Joe Thornber 2020-08-08 12:36:13 +01:00
parent ec8f7b7fa8
commit 7cf239b878

View File

@ -1,7 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use fixedbitset::FixedBitSet;
use nom::{number::complete::*, IResult}; use nom::{number::complete::*, IResult};
use std::collections::HashMap; use std::collections::BTreeMap;
use crate::block_manager::*; use crate::block_manager::*;
use crate::pdata::btree::Unpack; use crate::pdata::btree::Unpack;
@ -151,49 +150,49 @@ impl Unpack for Bitmap {
//------------------------------------------ //------------------------------------------
const ENTRIES_PER_WORD: u64 = 32;
pub struct CoreSpaceMap { pub struct CoreSpaceMap {
nr_entries: u64, nr_entries: u64,
bits: FixedBitSet, bits: Vec<u64>,
overflow: HashMap<u64, u32>, overflow: BTreeMap<u64, u32>,
} }
impl CoreSpaceMap { impl CoreSpaceMap {
pub fn new(nr_entries: u64) -> CoreSpaceMap { pub fn new(nr_entries: u64) -> CoreSpaceMap {
let bits = FixedBitSet::with_capacity(nr_entries as usize * 2); let nr_words = (nr_entries + ENTRIES_PER_WORD - 1) / ENTRIES_PER_WORD;
CoreSpaceMap { CoreSpaceMap {
nr_entries, nr_entries,
bits, bits: vec![0; nr_words as usize],
overflow: HashMap::new(), overflow: BTreeMap::new(),
} }
} }
fn get_bits(&self, b: u64) -> Result<u32> { fn check_bounds(&self, b: u64) -> Result<()> {
if b >= self.nr_entries { if b >= self.nr_entries {
return Err(anyhow!("space map index out of bounds")); return Err(anyhow!("space map index out of bounds"));
} }
Ok(())
let low_bit = self.bits.contains((b * 2) as usize);
let high_bit = self.bits.contains((b * 2 + 1) as usize);
let mut result = 0u32;
if high_bit {
result += 2;
}
if low_bit {
result += 1;
}
Ok(result)
} }
fn set_bits(&mut self, b: u64, count: u32) -> Result<()> { fn get_index(b: u64) -> (usize, usize) {
if count > 3 { (
return Err(anyhow!("internal error: bits entry should be <= 3")); (b / ENTRIES_PER_WORD) as usize,
((b & (ENTRIES_PER_WORD - 1)) as usize) * 2,
)
}
fn get_bits(&self, b: u64) -> Result<u32> {
self.check_bounds(b)?;
let result;
let (w, bit) = CoreSpaceMap::get_index(b);
unsafe {
let word = self.bits.get_unchecked(w);
result = (*word >> bit) & 0x3;
} }
self.bits.set((b * 2) as usize, (count & 0x1) != 0); Ok(result as u32)
self.bits.set((b * 2 + 1) as usize, (count & 0x2) != 0);
Ok(())
} }
pub fn get(&self, b: u64) -> Result<u32> { pub fn get(&self, b: u64) -> Result<u32> {
@ -211,23 +210,34 @@ impl CoreSpaceMap {
} }
pub fn inc(&mut self, b: u64) -> Result<()> { pub fn inc(&mut self, b: u64) -> Result<()> {
let old = self.get(b)?; self.check_bounds(b)?;
if old < 3 { let (w, bit) = CoreSpaceMap::get_index(b);
// bump up the bits let count;
self.set_bits(b, old + 1)?;
if old == 2 { unsafe {
// insert overflow entry let word = self.bits.get_unchecked_mut(w);
self.overflow.insert(b, 1); 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"
));
} }
} else if let Some(count) = self.overflow.get_mut(&b) {
// increment the overflow
*count += 1;
} else {
return Err(anyhow!(
"internal error: missing overflow entry in space map"
));
} }
Ok(()) Ok(())