[thin_dump (rust)] First pass at thin_dump.

Doesn't include --repair.

This includes <def> and <ref> sections for shared regions.
This commit is contained in:
Joe Thornber
2020-09-28 15:42:07 +01:00
parent a88ae3ca18
commit e9fbcc31de
9 changed files with 571 additions and 4 deletions

View File

@@ -550,6 +550,11 @@ pub trait NodeVisitor<V: Unpack> {
values: &[V],
) -> Result<()>;
// Nodes may be shared and thus visited multiple times. The walker avoids
// doing repeated IO, but it does call this method to keep the visitor up to
// date.
fn visit_again(&self, path: &Vec<u64>, b: u64) -> Result<()>;
fn end_walk(&self) -> Result<()>;
}
@@ -654,7 +659,11 @@ impl BTreeWalker {
// This node has already been checked ...
match self.failed(bs[i]) {
None => {
// ... it was clean so we can ignore.
// ... it was clean.
if let Err(e) = visitor.visit_again(path, bs[i]) {
// ... but the visitor isn't happy
errs.push(e.clone());
}
}
Some(e) => {
// ... there was an error
@@ -773,7 +782,7 @@ impl BTreeWalker {
if let Some(e) = self.failed(root) {
Err(e.clone())
} else {
Ok(())
visitor.visit_again(path, root)
}
} else {
let root = self.engine.read(root).map_err(|_| io_err(path))?;
@@ -878,7 +887,11 @@ where
// This node has already been checked ...
match w.failed(bs[i]) {
None => {
// ... it was clean so we can ignore.
// ... it was clean.
if let Err(e) = visitor.visit_again(path, bs[i]) {
// ... but the visitor isn't happy
errs.push(e.clone());
}
}
Some(e) => {
// ... there was an error
@@ -953,7 +966,7 @@ where
if let Some(e) = w.failed(root) {
Err(e.clone())
} else {
Ok(())
visitor.visit_again(path, root)
}
} else {
let root = w.engine.read(root).map_err(|_| io_err(path))?;
@@ -997,6 +1010,10 @@ impl<V: Unpack + Copy> NodeVisitor<V> for ValueCollector<V> {
Ok(())
}
fn visit_again(&self, _path: &Vec<u64>, _b: u64) -> Result<()> {
Ok(())
}
fn end_walk(&self) -> Result<()> {
Ok(())
}
@@ -1060,6 +1077,10 @@ impl<V: Unpack + Clone> NodeVisitor<V> for ValuePathCollector<V> {
Ok(())
}
fn visit_again(&self, _path: &Vec<u64>, _b: u64) -> Result<()> {
Ok(())
}
fn end_walk(&self) -> Result<()> {
Ok(())
}

View File

@@ -225,6 +225,10 @@ pub trait SpaceMap {
fn get_nr_blocks(&self) -> Result<u64>;
fn get_nr_allocated(&self) -> Result<u64>;
fn get(&self, b: u64) -> Result<u32>;
// Returns the old ref count
fn set(&mut self, b: u64, v: u32) -> Result<u32>;
fn inc(&mut self, begin: u64, len: u64) -> Result<()>;
}
@@ -265,6 +269,20 @@ where
Ok(self.counts[b as usize].into())
}
fn set(&mut self, b: u64, v: u32) -> Result<u32> {
let old = self.counts[b as usize];
assert!(v < 0xff); // FIXME: we can't assume this
self.counts[b as usize] = V::from(v as u8);
if old == V::from(0u8) && v != 0 {
self.nr_allocated += 1;
} else if old != V::from(0u8) && v == 0 {
self.nr_allocated -= 1;
}
Ok(old.into())
}
fn inc(&mut self, begin: u64, len: u64) -> Result<()> {
for b in begin..(begin + len) {
if self.counts[b as usize] == V::from(0u8) {
@@ -325,6 +343,24 @@ impl SpaceMap for RestrictedSpaceMap {
}
}
fn set(&mut self, b: u64, v: u32) -> Result<u32> {
let old = self.counts.contains(b as usize);
if v > 0 {
if !old {
self.nr_allocated += 1;
}
self.counts.insert(b as usize);
} else {
if old {
self.nr_allocated -= 1;
}
self.counts.set(b as usize, false);
}
Ok(if old {1} else {0})
}
fn inc(&mut self, begin: u64, len: u64) -> Result<()> {
for b in begin..(begin + len) {
if !self.counts.contains(b as usize) {