[btree_damage_tracker] track the paths

This commit is contained in:
Joe Thornber 2013-05-20 12:31:47 +01:00
parent e60c84392d
commit d7c1eabfc0
2 changed files with 92 additions and 7 deletions

View File

@ -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 &current_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_;
};

View File

@ -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();
}
//----------------------------------------------------------------