From 08c5fde04fdfa529d893b320325129c63a9cf35c Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 13 May 2013 11:27:38 +0100 Subject: [PATCH] btree_damage_tracker --- .../data-structures/btree_damage_visitor.h | 93 +++++++++++++++- unit-tests/damage_tracker_t.cc | 101 ++++++++++++++++++ 2 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 unit-tests/damage_tracker_t.cc diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index d6c7cba..9a73846 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -30,6 +30,68 @@ namespace persistent_data { range lost_keys_; std::string desc_; }; + + class damage_tracker { + public: + damage_tracker() + : damaged_(false), + damage_begin_(0) { + } + + typedef range range64; + typedef boost::optional maybe_range64; + + void bad_node() { + damaged_ = true; + } + + maybe_range64 good_internal(block_address begin) { + maybe_range64 r; + + if (damaged_) { + r = maybe_range64(range64(damage_begin_, begin)); + damaged_ = false; + } + + damage_begin_ = begin; + return r; + } + + // remembe 'end' is the one-past-the-end value, so + // take the last key in the leaf and add one. + maybe_range64 good_leaf(block_address begin, block_address end) { + maybe_range64 r; + + if (damaged_) { + r = maybe_range64(range64(damage_begin_, begin)); + damaged_ = false; + } + + damage_begin_ = end; + return r; + } + + maybe_range64 end() { + if (damaged_) + return maybe_range64(damage_begin_); + else + return maybe_range64(); + } + + private: + bool damaged_; + block_address damage_begin_; + }; + + inline + std::ostream &operator <<(std::ostream &out, damage_tracker::maybe_range64 const &mr) { + if (mr) + out << "Just " << *mr; + else + out << "Nothing"; + + return out; + } } //---------------------------------------------------------------- @@ -68,7 +130,8 @@ namespace persistent_data { : counter_(counter), avoid_repeated_visits_(true), value_visitor_(value_visitor), - damage_visitor_(damage_visitor) { + damage_visitor_(damage_visitor), + key_end_(0) { } bool visit_internal(node_location const &loc, @@ -121,6 +184,8 @@ namespace persistent_data { if (loc.sub_root) new_root(loc.level); + update_key_end(n.key_at(n.get_nr_entries() - 1) + 1ull); + return true; } @@ -139,7 +204,11 @@ namespace persistent_data { if (loc.sub_root) new_root(loc.level); - return check_leaf_key(loc.level, n); + bool r = check_leaf_key(loc.level, n); + if (r) + update_key_end(n.key_at(n.get_nr_entries() - 1) + 1ull); + + return r; } return false; @@ -285,19 +354,33 @@ namespace persistent_data { last_leaf_key_[level] = boost::optional(); } + void update_key_end(uint64_t end) { + key_end_ = max(end, key_end_); + } + template void report_damage(node const &n, std::string const &desc) { - range lost_keys; + range lost_keys(key_end_); damage d(0, lost_keys, desc); + + cerr << "damage: keys = " << lost_keys << " " << desc << endl; damage_visitor_.visit(d); } + //-------------------------------- + + // damage tracking + void report_damage(std::string const &desc) { - range lost_keys; + range lost_keys(key_end_); damage d(0, lost_keys, desc); + + cerr << "damage: keys = " << lost_keys << " " << desc << endl; damage_visitor_.visit(d); } + //-------------------------------- + block_counter &counter_; bool avoid_repeated_visits_; @@ -306,6 +389,8 @@ namespace persistent_data { std::set seen_; boost::optional last_leaf_key_[Levels]; + + uint64_t key_end_; }; } diff --git a/unit-tests/damage_tracker_t.cc b/unit-tests/damage_tracker_t.cc new file mode 100644 index 0000000..a191294 --- /dev/null +++ b/unit-tests/damage_tracker_t.cc @@ -0,0 +1,101 @@ +#include "gmock/gmock.h" + +#include "test_utils.h" + +#include "persistent-data/data-structures/btree_damage_visitor.h" + +using namespace std; +using namespace persistent_data; +using namespace test; +using namespace testing; + +//---------------------------------------------------------------- + +namespace { + typedef range range64; + typedef damage_tracker::maybe_range64 mr64; + + class DamageTrackerTests : public Test { + public: + void assert_no_damage(mr64 const &mr) const { + ASSERT_THAT(mr, Eq(mr64())); + } + + void assert_damage(mr64 const &mr, range64 const &expected) const { + ASSERT_THAT(mr, Eq(mr64(expected))); + } + + damage_tracker dt; + }; +}; + +//---------------------------------------------------------------- + +TEST_F(DamageTrackerTests, good_leaf) +{ + assert_no_damage(dt.good_leaf(0, 10)); + assert_no_damage(dt.end()); +} + +TEST_F(DamageTrackerTests, bad_node) +{ + dt.bad_node(); + assert_damage(dt.end(), range64(0ull)); +} + +TEST_F(DamageTrackerTests, good_bad) +{ + dt.good_leaf(0, 10); + dt.bad_node(); + assert_damage(dt.end(), range64(10ull)); +} + +TEST_F(DamageTrackerTests, bad_good) +{ + dt.bad_node(); + assert_damage(dt.good_leaf(10, 20), range64(0ull, 10ull)); +} + +TEST_F(DamageTrackerTests, good_bad_good) +{ + dt.good_leaf(0, 10); + dt.bad_node(); + assert_damage(dt.good_leaf(20, 30), range64(10ull, 20ull)); + assert_no_damage(dt.end()); +} + +TEST_F(DamageTrackerTests, bad_good_bad) +{ + dt.bad_node(); + dt.good_leaf(10, 20); + dt.bad_node(); + assert_damage(dt.end(), range64(20ull)); +} + +TEST_F(DamageTrackerTests, gi_bl_gl) +{ + dt.good_internal(0); + dt.bad_node(); + assert_damage(dt.good_leaf(10, 20), range64(0ull, 10ull)); + assert_no_damage(dt.end()); +} + +TEST_F(DamageTrackerTests, gi_gl_bl_bi) +{ + dt.good_internal(0); + dt.good_leaf(0, 10); + dt.bad_node(); + dt.bad_node(); + assert_damage(dt.end(), range64(10ull)); +} + +TEST_F(DamageTrackerTests, gi_bi_gi_bl_gl) +{ + dt.good_internal(0); + dt.bad_node(); + assert_damage(dt.good_internal(10), range64(0ull, 10ull)); + dt.bad_node(); + assert_damage(dt.good_leaf(15, 20), range64(10ull, 15ull)); +} + +//----------------------------------------------------------------