[thin_check (rust)] Fix race in btree walking.
The seen bitset was locked once to test, and separately to insert.
This commit is contained in:
parent
4e4b7ca2b1
commit
b915257e10
@ -3,8 +3,8 @@ use fixedbitset::FixedBitSet;
|
|||||||
use nom::{number::complete::*, IResult};
|
use nom::{number::complete::*, IResult};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::io_engine::*;
|
|
||||||
use crate::checksum;
|
use crate::checksum;
|
||||||
|
use crate::io_engine::*;
|
||||||
|
|
||||||
// FIXME: check that keys are in ascending order between nodes.
|
// FIXME: check that keys are in ascending order between nodes.
|
||||||
|
|
||||||
@ -20,9 +20,7 @@ pub trait Unpack {
|
|||||||
|
|
||||||
pub fn unpack<U: Unpack>(data: &[u8]) -> Result<U> {
|
pub fn unpack<U: Unpack>(data: &[u8]) -> Result<U> {
|
||||||
match U::unpack(data) {
|
match U::unpack(data) {
|
||||||
Err(_e) => {
|
Err(_e) => Err(anyhow!("couldn't parse SMRoot")),
|
||||||
Err(anyhow!("couldn't parse SMRoot"))
|
|
||||||
},
|
|
||||||
Ok((_i, v)) => Ok(v),
|
Ok((_i, v)) => Ok(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,16 +220,27 @@ impl BTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_seen(&self, b: u64) -> bool {
|
||||||
|
let mut seen = self.seen.lock().unwrap();
|
||||||
|
if !seen[b as usize] {
|
||||||
|
seen.insert(b as usize);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn walk_nodes<NV, V>(&mut self, visitor: &mut NV, bs: &[u64]) -> Result<()>
|
fn walk_nodes<NV, V>(&mut self, visitor: &mut NV, bs: &[u64]) -> Result<()>
|
||||||
where
|
where
|
||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
let mut blocks = Vec::new();
|
let mut blocks = Vec::new();
|
||||||
let seen = self.seen.lock().unwrap();
|
let mut seen = self.seen.lock().unwrap();
|
||||||
for b in bs {
|
for b in bs {
|
||||||
if !seen[*b as usize] {
|
if !seen[*b as usize] {
|
||||||
blocks.push(Block::new(*b));
|
blocks.push(Block::new(*b));
|
||||||
|
seen.insert(*b as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(seen);
|
drop(seen);
|
||||||
@ -250,10 +259,6 @@ impl BTreeWalker {
|
|||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
let mut seen = self.seen.lock().unwrap();
|
|
||||||
seen.insert(b.loc as usize);
|
|
||||||
drop(seen);
|
|
||||||
|
|
||||||
let bt = checksum::metadata_block_type(b.get_data());
|
let bt = checksum::metadata_block_type(b.get_data());
|
||||||
if bt != checksum::BT::NODE {
|
if bt != checksum::BT::NODE {
|
||||||
return Err(anyhow!("checksum failed for node {}, {:?}", b.loc, bt));
|
return Err(anyhow!("checksum failed for node {}, {:?}", b.loc, bt));
|
||||||
@ -279,18 +284,26 @@ impl BTreeWalker {
|
|||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
|
if self.is_seen(root.loc) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
self.walk_node(visitor, &root, true)
|
self.walk_node(visitor, &root, true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk<NV, V>(&mut self, visitor: &mut NV, root: u64) -> Result<()>
|
pub fn walk<NV, V>(&mut self, visitor: &mut NV, root: u64) -> Result<()>
|
||||||
where
|
where
|
||||||
NV: NodeVisitor<V>,
|
NV: NodeVisitor<V>,
|
||||||
V: Unpack,
|
V: Unpack,
|
||||||
{
|
{
|
||||||
|
if self.is_seen(root) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
let mut root = Block::new(root);
|
let mut root = Block::new(root);
|
||||||
self.engine.read(&mut root)?;
|
self.engine.read(&mut root)?;
|
||||||
self.walk_node(visitor, &root, true)
|
self.walk_node(visitor, &root, true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user