Some more work on btree_damage_visitor

This commit is contained in:
Joe Thornber 2013-05-08 16:38:38 +01:00
parent a7adefbae8
commit ab66e9f8e3
2 changed files with 145 additions and 18 deletions

View File

@ -2,11 +2,36 @@
#define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H
#include "persistent-data/data-structures/btree.h"
#include "persistent-data/range.h"
//----------------------------------------------------------------
namespace persistent_data {
namespace btree_detail {
struct damage {
typedef boost::shared_ptr<damage> ptr;
damage(unsigned level,
range<uint64_t> lost_keys,
std::string const &desc)
: level_(level),
lost_keys_(lost_keys),
desc_(desc) {
}
// Does _not_ compare the descriptions
bool operator ==(damage const &rhs) const {
return (level_ == rhs.level_) &&
(lost_keys_ == rhs.lost_keys_);
}
unsigned level_;
range<uint64_t> lost_keys_;
std::string desc_;
};
}
//----------------------------------------------------------------
// This class implements consistency checking for the btrees. It
@ -61,6 +86,15 @@ namespace persistent_data {
return check_leaf(loc, n);
}
typedef typename btree<Levels, ValueTraits>::visitor::error_outcome error_outcome;
error_outcome error_accessing_node(node_location const &l, block_address b,
std::string const &what) {
report_damage(what);
return btree<Levels, ValueTraits>::visitor::EXCEPTION_HANDLED;
}
private:
bool check_internal(node_location const &loc,
btree_detail::node_ref<uint64_traits> const &n) {
@ -115,13 +149,14 @@ namespace persistent_data {
}
template <typename node>
bool check_block_nr(node const &n) const {
bool check_block_nr(node const &n) {
if (n.get_location() != n.get_block_nr()) {
std::ostringstream out;
out << "block number mismatch: actually "
<< n.get_location()
<< ", claims " << n.get_block_nr();
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -129,19 +164,19 @@ namespace persistent_data {
}
template <typename node>
bool check_max_entries(node const &n) const {
bool check_max_entries(node const &n) {
size_t elt_size = sizeof(uint64_t) + n.get_value_size();
if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) {
std::ostringstream out;
out << "max entries too large: " << n.get_max_entries();
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
if (n.get_max_entries() % 3) {
std::ostringstream out;
out << "max entries is not divisible by 3: " << n.get_max_entries();
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -149,13 +184,13 @@ namespace persistent_data {
}
template <typename node>
bool check_nr_entries(node const &n, bool is_root) const {
bool check_nr_entries(node const &n, bool is_root) {
if (n.get_nr_entries() > n.get_max_entries()) {
std::ostringstream out;
out << "bad nr_entries: "
<< n.get_nr_entries() << " < "
<< n.get_max_entries();
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -167,7 +202,7 @@ namespace persistent_data {
<< ", expected at least "
<< min
<< "(max_entries = " << n.get_max_entries() << ")";
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -175,7 +210,7 @@ namespace persistent_data {
}
template <typename node>
bool check_ordered_keys(node const &n) const {
bool check_ordered_keys(node const &n) {
unsigned nr_entries = n.get_nr_entries();
if (nr_entries == 0)
@ -188,7 +223,7 @@ namespace persistent_data {
if (k <= last_key) {
ostringstream out;
out << "keys are out of order, " << k << " <= " << last_key;
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
last_key = k;
@ -198,7 +233,7 @@ namespace persistent_data {
}
template <typename node>
bool check_parent_key(boost::optional<uint64_t> key, node const &n) const {
bool check_parent_key(boost::optional<uint64_t> key, node const &n) {
if (!key)
return true;
@ -206,7 +241,7 @@ namespace persistent_data {
ostringstream out;
out << "parent key mismatch: parent was " << *key
<< ", but lowest in node was " << n.key_at(0);
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -222,7 +257,7 @@ namespace persistent_data {
ostringstream out;
out << "the last key of the previous leaf was " << *last_leaf_key_[level]
<< " and the first key of this leaf is " << n.key_at(0);
//errs_->add_child(out.str());
report_damage(n, out.str());
return false;
}
@ -236,8 +271,22 @@ namespace persistent_data {
last_leaf_key_[level] = boost::optional<uint64_t>();
}
template <typename node>
void report_damage(node const &n, std::string const &desc) {
range<uint64_t> lost_keys;
damage d(0, lost_keys, desc);
damage_visitor_.visit(d);
}
void report_damage(std::string const &desc) {
range<uint64_t> lost_keys;
damage d(0, lost_keys, desc);
damage_visitor_.visit(d);
}
block_counter &counter_;
bool avoid_repeated_visits_;
ValueVisitor &value_visitor_;
DamageVisitor &damage_visitor_;

View File

@ -2,9 +2,10 @@
#include "test_utils.h"
#include "persistent-data/transaction_manager.h"
#include "persistent-data/space-maps/core.h"
#include "persistent-data/data-structures/btree_damage_visitor.h"
#include "persistent-data/endian_utils.h"
#include "persistent-data/space-maps/core.h"
#include "persistent-data/transaction_manager.h"
using namespace std;
using namespace persistent_data;
@ -17,22 +18,99 @@ namespace {
block_address const BLOCK_SIZE = 4096;
block_address const NR_BLOCKS = 102400;
struct thing {
uint32_t x;
uint64_t y;
};
struct thing_disk {
le32 x;
le64 y;
};
struct thing_traits {
typedef thing_disk disk_type;
typedef thing value_type;
typedef persistent_data::no_op_ref_counter<value_type> ref_counter;
static void unpack(thing_disk const &disk, thing &value) {
value.x = to_cpu<uint32_t>(disk.x);
value.y = to_cpu<uint64_t>(disk.y);
}
static void pack(thing const &value, thing_disk &disk) {
disk.x = to_disk<le32>(value.x);
disk.y = to_disk<le64>(value.y);
}
};
class value_visitor_mock {
public:
MOCK_METHOD1(visit, void(thing const &));
};
class damage_visitor_mock {
public:
MOCK_METHOD1(visit, void(btree_detail::damage const &));
};
class BTreeDamageVisitorTests : public Test {
public:
BTreeDamageVisitorTests()
: bm_(create_bm<BLOCK_SIZE>(NR_BLOCKS)) {
: bm_(create_bm<BLOCK_SIZE>(NR_BLOCKS)),
sm_(new core_map(NR_BLOCKS)),
tm_(new transaction_manager(bm_, sm_)),
tree_(new btree<2, thing_traits>(tm_, rc_)) {
}
void zero_block(block_address b) {
::test::zero_block(bm_, b);
}
with_temp_directory dir_;
block_manager<>::ptr bm_;
space_map::ptr sm_;
transaction_manager::ptr tm_;
thing_traits::ref_counter rc_;
btree<2, thing_traits>::ptr tree_;
value_visitor_mock value_visitor_;
damage_visitor_mock damage_visitor_;
};
}
//----------------------------------------------------------------
TEST_F(BTreeDamageVisitorTests, null_test)
TEST_F(BTreeDamageVisitorTests, visiting_an_empty_btree_visits_nothing)
{
block_counter counter;
EXPECT_CALL(value_visitor_, visit(_)).Times(0);
EXPECT_CALL(damage_visitor_, visit(_)).Times(0);
btree_damage_visitor<value_visitor_mock, damage_visitor_mock, 2, thing_traits>
visitor(counter, value_visitor_, damage_visitor_);
tree_->visit_depth_first(visitor);
}
TEST_F(BTreeDamageVisitorTests, visiting_an_tree_with_a_trashed_root)
{
zero_block(tree_->get_root());
EXPECT_CALL(value_visitor_, visit(_)).Times(0);
EXPECT_CALL(damage_visitor_, visit(Eq(damage(0, range<uint64_t>(), "foo")))).Times(1);
block_counter counter;
btree_damage_visitor<value_visitor_mock, damage_visitor_mock, 2, thing_traits>
visitor(counter, value_visitor_, damage_visitor_);
tree_->visit_depth_first(visitor);
}
#if 0
uint64_t key[2] = {1, 2};
thing value = {0, 0};
tree_->insert(key, value);
#endif
//----------------------------------------------------------------