[thin_check (rust)] fix bug in key range splitting.

Ranges were not being ommitted when a block was ommitted due to
being shared and already visited.
This commit is contained in:
Joe Thornber 2020-09-22 10:47:23 +01:00
parent 819fc6d54c
commit f4c3098e02

View File

@ -14,8 +14,6 @@ use crate::pdata::space_map::*;
use crate::pdata::unpack::*; use crate::pdata::unpack::*;
use crate::pack::vm; use crate::pack::vm;
// FIXME: check that keys are in ascending order between nodes.
//------------------------------------------ //------------------------------------------
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -218,6 +216,8 @@ fn split_key_ranges(path: &Vec<u64>, kr: &KeyRange, keys: &[u64]) -> Result<Vec<
//------------------------------------------ //------------------------------------------
// We compress and base64 encode paths to make them easy to
// cut and paste between programs (eg, thin_explore -p <path>)
pub fn encode_node_path(path: &[u64]) -> String { pub fn encode_node_path(path: &[u64]) -> String {
let mut buffer: Vec<u8> = Vec::with_capacity(128); let mut buffer: Vec<u8> = Vec::with_capacity(128);
let mut cursor = std::io::Cursor::new(&mut buffer); let mut cursor = std::io::Cursor::new(&mut buffer);
@ -225,7 +225,7 @@ pub fn encode_node_path(path: &[u64]) -> String {
// The first entry is normally the superblock (0), so we // The first entry is normally the superblock (0), so we
// special case this. // special case this.
if path[0] == 0 { if path.len() > 0 && path[0] == 0 {
let count = ((path.len() as u8) - 1) << 1; let count = ((path.len() as u8) - 1) << 1;
cursor.write_u8(count as u8).unwrap(); cursor.write_u8(count as u8).unwrap();
vm::pack_u64s(&mut cursor, &path[1..]).unwrap(); vm::pack_u64s(&mut cursor, &path[1..]).unwrap();
@ -241,7 +241,7 @@ pub fn encode_node_path(path: &[u64]) -> String {
pub fn decode_node_path(text: &str) -> anyhow::Result<Vec<u64>> { pub fn decode_node_path(text: &str) -> anyhow::Result<Vec<u64>> {
let mut buffer = vec![0; 128]; let mut buffer = vec![0; 128];
let bytes = &mut buffer[0..BASE64.decode_len(text.len()).unwrap()]; let bytes = &mut buffer[0..BASE64.decode_len(text.len()).unwrap()];
let len = BASE64.decode_mut(text.as_bytes(), &mut bytes[0..]).map_err(|_| anyhow!("bad node path. Unable to base64 decode."))?; BASE64.decode_mut(text.as_bytes(), &mut bytes[0..]).map_err(|_| anyhow!("bad node path. Unable to base64 decode."))?;
let mut input = std::io::Cursor::new(bytes); let mut input = std::io::Cursor::new(bytes);
@ -254,19 +254,20 @@ pub fn decode_node_path(text: &str) -> anyhow::Result<Vec<u64>> {
count >>= 1; count >>= 1;
let count = count as usize; let count = count as usize;
let mut path;
if count == 0 { if count == 0 {
return Ok(Vec::new()); path = vec![];
} else {
let mut output = Vec::with_capacity(count * 8);
let mut cursor = std::io::Cursor::new(&mut output);
let mut vm = vm::VM::new();
let written = vm.exec(&mut input, &mut cursor, count * 8)?;
assert_eq!(written, count * 8);
let mut cursor = std::io::Cursor::new(&mut output);
path = vm::unpack_u64s(&mut cursor, count)?;
} }
let mut output = Vec::with_capacity(count * 8);
let mut cursor = std::io::Cursor::new(&mut output);
let mut vm = vm::VM::new();
let written = vm.exec(&mut input, &mut cursor, count * 8)?;
assert_eq!(written, count * 8);
let mut cursor = std::io::Cursor::new(&mut output);
let mut path = vm::unpack_u64s(&mut cursor, count)?;
if prepend_zero { if prepend_zero {
let mut full_path = vec![0u64]; let mut full_path = vec![0u64];
@ -286,11 +287,15 @@ fn test_encode_path() {
Test(vec![1]), Test(vec![1]),
Test(vec![1, 2]), Test(vec![1, 2]),
Test(vec![1, 2, 3, 4]), Test(vec![1, 2, 3, 4]),
Test(vec![0]),
Test(vec![0, 0]),
Test(vec![0, 1]),
Test(vec![0, 1, 2]),
Test(vec![0, 123, 201231, 3102983012]),
]; ];
for t in tests { for t in tests {
let encoded = encode_node_path(&t.0[0..]); let encoded = encode_node_path(&t.0[0..]);
eprintln!("encoded = '{}'", &encoded);
let decoded = decode_node_path(&encoded).unwrap(); let decoded = decode_node_path(&encoded).unwrap();
assert_eq!(decoded, &t.0[0..]); assert_eq!(decoded, &t.0[0..]);
} }
@ -609,23 +614,26 @@ impl BTreeWalker {
&self, &self,
path: &mut Vec<u64>, path: &mut Vec<u64>,
visitor: &NV, visitor: &NV,
kr: &[KeyRange], krs: &[KeyRange],
bs: &[u64], bs: &[u64],
) -> Vec<BTreeError> ) -> Vec<BTreeError>
where where
NV: NodeVisitor<V>, NV: NodeVisitor<V>,
V: Unpack, V: Unpack,
{ {
assert_eq!(krs.len(), bs.len());
let mut errs: Vec<BTreeError> = Vec::new(); let mut errs: Vec<BTreeError> = Vec::new();
let mut blocks = Vec::with_capacity(bs.len()); let mut blocks = Vec::with_capacity(bs.len());
for b in bs { let mut filtered_krs = Vec::with_capacity(bs.len());
if self.sm_inc(*b) == 0 { for i in 0..bs.len() {
if self.sm_inc(bs[i]) == 0 {
// Node not yet seen // Node not yet seen
blocks.push(*b); blocks.push(bs[i]);
filtered_krs.push(krs[i].clone());
} else { } else {
// This node has already been checked ... // This node has already been checked ...
match self.failed(*b) { match self.failed(bs[i]) {
None => { None => {
// ... it was clean so we can ignore. // ... it was clean so we can ignore.
} }
@ -641,7 +649,7 @@ impl BTreeWalker {
Err(_) => { Err(_) => {
// IO completely failed, error every block // IO completely failed, error every block
for (i, b) in blocks.iter().enumerate() { for (i, b) in blocks.iter().enumerate() {
let e = io_err(path).keys_context(&kr[i]); let e = io_err(path).keys_context(&filtered_krs[i]);
errs.push(e.clone()); errs.push(e.clone());
self.set_fail(*b, e); self.set_fail(*b, e);
} }
@ -651,11 +659,11 @@ impl BTreeWalker {
for rb in rblocks { for rb in rblocks {
match rb { match rb {
Err(_) => { Err(_) => {
let e = io_err(path).keys_context(&kr[i]); let e = io_err(path).keys_context(&filtered_krs[i]);
errs.push(e.clone()); errs.push(e.clone());
self.set_fail(blocks[i], e); self.set_fail(blocks[i], e);
} }
Ok(b) => match self.walk_node(path, visitor, &kr[i], &b, false) { Ok(b) => match self.walk_node(path, visitor, &filtered_krs[i], &b, false) {
Err(e) => { Err(e) => {
errs.push(e); errs.push(e);
} }
@ -875,7 +883,7 @@ where
pub fn walk_threaded<NV, V>( pub fn walk_threaded<NV, V>(
path: &mut Vec<u64>, path: &mut Vec<u64>,
w: Arc<BTreeWalker>, w: Arc<BTreeWalker>,
pool: &ThreadPool, _pool: &ThreadPool,
visitor: Arc<NV>, visitor: Arc<NV>,
root: u64, root: u64,
) -> Result<()> ) -> Result<()>
@ -913,7 +921,7 @@ impl<V: Unpack + Copy> NodeVisitor<V> for ValueCollector<V> {
} }
pub fn btree_to_map<V: Unpack + Copy>( pub fn btree_to_map<V: Unpack + Copy>(
path: &mut Vec<u64>, _path: &mut Vec<u64>,
engine: Arc<dyn IoEngine + Send + Sync>, engine: Arc<dyn IoEngine + Send + Sync>,
ignore_non_fatal: bool, ignore_non_fatal: bool,
root: u64, root: u64,