[btree_damage_tracker] track the paths
This commit is contained in:
parent
e60c84392d
commit
d7c1eabfc0
@ -82,6 +82,29 @@ namespace persistent_data {
|
||||
block_address damage_begin_;
|
||||
};
|
||||
|
||||
// As we walk a btree we need to know if we've moved into a
|
||||
// different sub tree (by looking at the btree_path).
|
||||
class path_tracker {
|
||||
public:
|
||||
// returns the old path if the tree has changed.
|
||||
boost::optional<btree_path> next_path(btree_path const &p) {
|
||||
if (p != path_) {
|
||||
btree_path tmp(path_);
|
||||
path_ = p;
|
||||
return boost::optional<btree_path>(tmp);
|
||||
}
|
||||
|
||||
return boost::optional<btree_path>();
|
||||
}
|
||||
|
||||
btree_path const ¤t_path() const {
|
||||
return path_;
|
||||
}
|
||||
|
||||
private:
|
||||
btree_path path_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
// This class implements consistency checking for the btrees. It
|
||||
@ -125,16 +148,23 @@ namespace persistent_data {
|
||||
|
||||
bool visit_internal(node_location const &loc,
|
||||
btree_detail::node_ref<uint64_traits> const &n) {
|
||||
update_path(loc.path);
|
||||
|
||||
return check_internal(loc, n);
|
||||
}
|
||||
|
||||
bool visit_internal_leaf(node_location const &loc,
|
||||
btree_detail::node_ref<uint64_traits> const &n) {
|
||||
update_path(loc.path);
|
||||
|
||||
return check_leaf(loc, n);
|
||||
}
|
||||
|
||||
bool visit_leaf(node_location const &loc,
|
||||
btree_detail::node_ref<ValueTraits> const &n) {
|
||||
update_path(loc.path);
|
||||
|
||||
|
||||
bool r = check_leaf(loc, n);
|
||||
|
||||
// If anything goes wrong with the checks, we skip
|
||||
@ -359,28 +389,27 @@ namespace persistent_data {
|
||||
void good_internal(block_address b) {
|
||||
maybe_range64 mr = dt_.good_internal(b);
|
||||
if (mr)
|
||||
issue_damage(*mr);
|
||||
issue_damage(path_tracker_.current_path(), *mr);
|
||||
}
|
||||
|
||||
void good_leaf(block_address b, block_address e) {
|
||||
maybe_range64 mr = dt_.good_leaf(b, e);
|
||||
|
||||
if (mr)
|
||||
issue_damage(*mr);
|
||||
issue_damage(path_tracker_.current_path(), *mr);
|
||||
}
|
||||
|
||||
// FIXME: duplicate code
|
||||
void end_walk() {
|
||||
maybe_range64 mr = dt_.end();
|
||||
if (mr)
|
||||
issue_damage(*mr);
|
||||
issue_damage(path_tracker_.current_path(), *mr);
|
||||
}
|
||||
|
||||
void issue_damage(range64 const &r) {
|
||||
// FIXME: we don't really know what level
|
||||
// the damage is coming from
|
||||
void issue_damage(btree_path const &path, range64 const &r) {
|
||||
damage d(r, build_damage_desc());
|
||||
clear_damage_desc();
|
||||
damage_visitor_.visit(btree_path(), d);
|
||||
damage_visitor_.visit(path, d);
|
||||
}
|
||||
|
||||
std::string build_damage_desc() const {
|
||||
@ -399,6 +428,22 @@ namespace persistent_data {
|
||||
|
||||
//--------------------------------
|
||||
|
||||
void update_path(btree_path const &path) {
|
||||
boost::optional<btree_path> old_path = path_tracker_.next_path(path);
|
||||
if (old_path) {
|
||||
// we need to emit any errors that
|
||||
// were accrued against the old
|
||||
// path.
|
||||
|
||||
// FIXME: duplicate code with end_walk()
|
||||
maybe_range64 mr = dt_.end();
|
||||
if (mr)
|
||||
issue_damage(*old_path, *mr);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
block_counter &counter_;
|
||||
bool avoid_repeated_visits_;
|
||||
|
||||
@ -408,6 +453,7 @@ namespace persistent_data {
|
||||
std::set<block_address> seen_;
|
||||
boost::optional<uint64_t> last_leaf_key_[Levels];
|
||||
|
||||
path_tracker path_tracker_;
|
||||
damage_tracker dt_;
|
||||
std::list<std::string> damage_reasons_;
|
||||
};
|
||||
|
@ -420,6 +420,26 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
void expect_values_except(unsigned nr_sub_trees, unsigned nr_values,
|
||||
btree_path const &path, range<uint64_t> keys) {
|
||||
for (unsigned i = 0; i < nr_sub_trees; i++)
|
||||
expect_sub_tree_values_except(i, nr_values, path, keys);
|
||||
}
|
||||
|
||||
void expect_sub_tree_values_except(unsigned sub_tree, unsigned nr_values,
|
||||
btree_path const &path, range<uint64_t> keys) {
|
||||
for (unsigned i = 0; i < nr_values; i++) {
|
||||
uint64_t key[2] = {sub_tree, i};
|
||||
|
||||
if (sub_tree == path[0] && keys.contains(i))
|
||||
continue;
|
||||
|
||||
btree_path p2;
|
||||
p2.push_back(sub_tree);
|
||||
EXPECT_CALL(value_visitor_, visit(Eq(p2), Eq(key_to_value(key))));
|
||||
}
|
||||
}
|
||||
|
||||
void expect_damage(btree_path path, range<uint64_t> keys) {
|
||||
EXPECT_CALL(damage_visitor_, visit(Eq(path), DamagedKeys(keys))).Times(1);
|
||||
}
|
||||
@ -599,4 +619,23 @@ TEST_F(BTreeDamageVisitor2Tests, populated_tree_with_no_damage)
|
||||
run();
|
||||
}
|
||||
|
||||
TEST_F(BTreeDamageVisitor2Tests, damaged_leaf)
|
||||
{
|
||||
insert_values(10, 1000);
|
||||
tree_complete();
|
||||
|
||||
auto leaf1 = [] (node_info const &n) {
|
||||
return (n.leaf && n.path.size() == 1 && n.path[0] == 1);
|
||||
};
|
||||
|
||||
node_info n = layout_->random_node(leaf1);
|
||||
cerr << "node: " << n << endl;
|
||||
trash_block(n.b);
|
||||
|
||||
expect_damage(n.path, n.keys);
|
||||
expect_values_except(10, 1000, n.path, n.keys);
|
||||
|
||||
run();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user