Some more work on btree_damage_visitor
This commit is contained in:
parent
a7adefbae8
commit
ab66e9f8e3
@ -2,11 +2,36 @@
|
|||||||
#define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H
|
#define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H
|
||||||
|
|
||||||
#include "persistent-data/data-structures/btree.h"
|
#include "persistent-data/data-structures/btree.h"
|
||||||
|
#include "persistent-data/range.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
namespace persistent_data {
|
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
|
// This class implements consistency checking for the btrees. It
|
||||||
@ -61,6 +86,15 @@ namespace persistent_data {
|
|||||||
return check_leaf(loc, n);
|
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:
|
private:
|
||||||
bool check_internal(node_location const &loc,
|
bool check_internal(node_location const &loc,
|
||||||
btree_detail::node_ref<uint64_traits> const &n) {
|
btree_detail::node_ref<uint64_traits> const &n) {
|
||||||
@ -115,13 +149,14 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename node>
|
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()) {
|
if (n.get_location() != n.get_block_nr()) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "block number mismatch: actually "
|
out << "block number mismatch: actually "
|
||||||
<< n.get_location()
|
<< n.get_location()
|
||||||
<< ", claims " << n.get_block_nr();
|
<< ", claims " << n.get_block_nr();
|
||||||
//errs_->add_child(out.str());
|
|
||||||
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,19 +164,19 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename node>
|
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();
|
size_t elt_size = sizeof(uint64_t) + n.get_value_size();
|
||||||
if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) {
|
if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "max entries too large: " << n.get_max_entries();
|
out << "max entries too large: " << n.get_max_entries();
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n.get_max_entries() % 3) {
|
if (n.get_max_entries() % 3) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "max entries is not divisible by 3: " << n.get_max_entries();
|
out << "max entries is not divisible by 3: " << n.get_max_entries();
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,13 +184,13 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename node>
|
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()) {
|
if (n.get_nr_entries() > n.get_max_entries()) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "bad nr_entries: "
|
out << "bad nr_entries: "
|
||||||
<< n.get_nr_entries() << " < "
|
<< n.get_nr_entries() << " < "
|
||||||
<< n.get_max_entries();
|
<< n.get_max_entries();
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +202,7 @@ namespace persistent_data {
|
|||||||
<< ", expected at least "
|
<< ", expected at least "
|
||||||
<< min
|
<< min
|
||||||
<< "(max_entries = " << n.get_max_entries() << ")";
|
<< "(max_entries = " << n.get_max_entries() << ")";
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +210,7 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename node>
|
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();
|
unsigned nr_entries = n.get_nr_entries();
|
||||||
|
|
||||||
if (nr_entries == 0)
|
if (nr_entries == 0)
|
||||||
@ -188,7 +223,7 @@ namespace persistent_data {
|
|||||||
if (k <= last_key) {
|
if (k <= last_key) {
|
||||||
ostringstream out;
|
ostringstream out;
|
||||||
out << "keys are out of order, " << k << " <= " << last_key;
|
out << "keys are out of order, " << k << " <= " << last_key;
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
last_key = k;
|
last_key = k;
|
||||||
@ -198,7 +233,7 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename node>
|
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)
|
if (!key)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -206,7 +241,7 @@ namespace persistent_data {
|
|||||||
ostringstream out;
|
ostringstream out;
|
||||||
out << "parent key mismatch: parent was " << *key
|
out << "parent key mismatch: parent was " << *key
|
||||||
<< ", but lowest in node was " << n.key_at(0);
|
<< ", but lowest in node was " << n.key_at(0);
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +257,7 @@ namespace persistent_data {
|
|||||||
ostringstream out;
|
ostringstream out;
|
||||||
out << "the last key of the previous leaf was " << *last_leaf_key_[level]
|
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);
|
<< " and the first key of this leaf is " << n.key_at(0);
|
||||||
//errs_->add_child(out.str());
|
report_damage(n, out.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,8 +271,22 @@ namespace persistent_data {
|
|||||||
last_leaf_key_[level] = boost::optional<uint64_t>();
|
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_;
|
block_counter &counter_;
|
||||||
bool avoid_repeated_visits_;
|
bool avoid_repeated_visits_;
|
||||||
|
|
||||||
ValueVisitor &value_visitor_;
|
ValueVisitor &value_visitor_;
|
||||||
DamageVisitor &damage_visitor_;
|
DamageVisitor &damage_visitor_;
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#include "test_utils.h"
|
#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/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 std;
|
||||||
using namespace persistent_data;
|
using namespace persistent_data;
|
||||||
@ -17,22 +18,99 @@ namespace {
|
|||||||
block_address const BLOCK_SIZE = 4096;
|
block_address const BLOCK_SIZE = 4096;
|
||||||
block_address const NR_BLOCKS = 102400;
|
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 {
|
class BTreeDamageVisitorTests : public Test {
|
||||||
public:
|
public:
|
||||||
BTreeDamageVisitorTests()
|
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_;
|
with_temp_directory dir_;
|
||||||
block_manager<>::ptr bm_;
|
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
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user