From 23ef3b387d97c7df760b43f2ec2fc340a44d810c Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Wed, 8 May 2013 12:00:24 +0100 Subject: [PATCH] Start btree_damage_visitor. --- .../data-structures/btree_damage_visitor.h | 251 ++++++++++++++++++ unit-tests/Makefile.in | 1 + unit-tests/btree_damage_visitor_t.cc | 38 +++ 3 files changed, 290 insertions(+) create mode 100644 persistent-data/data-structures/btree_damage_visitor.h create mode 100644 unit-tests/btree_damage_visitor_t.cc diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h new file mode 100644 index 0000000..14340e8 --- /dev/null +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -0,0 +1,251 @@ +#ifndef PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H +#define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H + +#include "persistent-data/data-structures/btree.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + + //---------------------------------------------------------------- + + // This class implements consistency checking for the btrees. It + // also allows the caller to visit all accessible values. + + // Derive from this if you want some additional checks. It's worth + // summarising what is checked: + + // + // Implemented + // ----------- + // + // - block_nr + // - nr_entries < max_entries + // - max_entries fits in block + // - max_entries is divisible by 3 + // - nr_entries > minimum (except for root nodes) + // + // Not implemented + // --------------- + // + // - leaf | internal flags (this can be inferred from siblings) + + //---------------------------------------------------------------- + + template + class btree_damage_visitor : public btree::visitor { + public: + typedef btree_detail::node_location node_location; + + btree_damage_visitor(block_counter &counter, + ValueVisitor &value_visitor, + DamageVisitor &damage_visitor) + : counter_(counter), + avoid_repeated_visits_(true), + value_visitor_(value_visitor), + damage_visitor_(damage_visitor) { + } + + bool visit_internal(node_location const &loc, + btree_detail::node_ref const &n) { + return check_internal(loc, n); + } + + bool visit_internal_leaf(node_location const &loc, + btree_detail::node_ref const &n) { + return check_leaf(loc, n); + } + + bool visit_leaf(node_location const &loc, + btree_detail::node_ref const &n) { + return check_leaf(loc, n); + } + + private: + bool check_internal(node_location const &loc, + btree_detail::node_ref const &n) { + if (!already_visited(n) && + check_block_nr(n) && + check_max_entries(n) && + check_nr_entries(n, loc.sub_root) && + check_ordered_keys(n) && + check_parent_key(loc.sub_root ? optional() : loc.key, n)) { + if (loc.sub_root) + new_root(loc.level); + + return true; + } + + return false; + } + + template + bool check_leaf(node_location const &loc, + btree_detail::node_ref const &n) { + if (!already_visited(n) && + check_block_nr(n) && + check_max_entries(n) && + check_nr_entries(n, loc.sub_root) && + check_ordered_keys(n) && + check_parent_key(loc.sub_root ? optional() : loc.key, n)) { + if (loc.sub_root) + new_root(loc.level); + + return check_leaf_key(loc.level, n); + } + + return false; + } + + + template + bool already_visited(node const &n) { + block_address b = n.get_location(); + + counter_.inc(b); + + if (avoid_repeated_visits_) { + if (seen_.count(b) > 0) + return true; + + seen_.insert(b); + } + + return false; + } + + template + bool check_block_nr(node const &n) const { + 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()); + return false; + } + + return true; + } + + template + bool check_max_entries(node const &n) const { + 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()); + 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()); + return false; + } + + return true; + } + + template + bool check_nr_entries(node const &n, bool is_root) const { + 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()); + return false; + } + + block_address min = n.get_max_entries() / 3; + if (!is_root && (n.get_nr_entries() < min)) { + ostringstream out; + out << "too few entries in btree: " + << n.get_nr_entries() + << ", expected at least " + << min + << "(max_entries = " << n.get_max_entries() << ")"; + //errs_->add_child(out.str()); + return false; + } + + return true; + } + + template + bool check_ordered_keys(node const &n) const { + unsigned nr_entries = n.get_nr_entries(); + + if (nr_entries == 0) + return true; // can only happen if a root node + + uint64_t last_key = n.key_at(0); + + for (unsigned i = 1; i < nr_entries; i++) { + uint64_t k = n.key_at(i); + if (k <= last_key) { + ostringstream out; + out << "keys are out of order, " << k << " <= " << last_key; + //errs_->add_child(out.str()); + return false; + } + last_key = k; + } + + return true; + } + + template + bool check_parent_key(boost::optional key, node const &n) const { + if (!key) + return true; + + if (*key > n.key_at(0)) { + ostringstream out; + out << "parent key mismatch: parent was " << *key + << ", but lowest in node was " << n.key_at(0); + //errs_->add_child(out.str()); + return false; + } + + return true; + } + + template + bool check_leaf_key(unsigned level, node const &n) { + if (n.get_nr_entries() == 0) + return true; // can only happen if a root node + + if (last_leaf_key_[level] && *last_leaf_key_[level] >= n.key_at(0)) { + 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()); + return false; + } + + last_leaf_key_[level] = n.key_at(n.get_nr_entries() - 1); + return true; + } + + void new_root(unsigned level) { + // we're starting a new subtree, so should + // reset the last_leaf value. + last_leaf_key_[level] = boost::optional(); + } + + block_counter &counter_; + bool avoid_repeated_visits_; + ValueVisitor &value_visitor_; + DamageVisitor &damage_visitor_; + + std::set seen_; + boost::optional last_leaf_key_[Levels]; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in index 101efc8..41c9968 100644 --- a/unit-tests/Makefile.in +++ b/unit-tests/Makefile.in @@ -47,6 +47,7 @@ TEST_SOURCE=\ unit-tests/bitset_t.cc \ unit-tests/block_t.cc \ unit-tests/btree_t.cc \ + unit-tests/btree_damage_visitor_t.cc \ unit-tests/buffer_t.cc \ unit-tests/cache_t.cc \ unit-tests/endian_t.cc \ diff --git a/unit-tests/btree_damage_visitor_t.cc b/unit-tests/btree_damage_visitor_t.cc new file mode 100644 index 0000000..7ddec54 --- /dev/null +++ b/unit-tests/btree_damage_visitor_t.cc @@ -0,0 +1,38 @@ +#include "gmock/gmock.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" + +using namespace std; +using namespace persistent_data; +using namespace test; +using namespace testing; + +//---------------------------------------------------------------- + +namespace { + block_address const BLOCK_SIZE = 4096; + block_address const NR_BLOCKS = 102400; + + class BTreeDamageVisitorTests : public Test { + public: + BTreeDamageVisitorTests() + : bm_(create_bm(NR_BLOCKS)) { + } + + with_temp_directory dir_; + block_manager<>::ptr bm_; + }; +} + +//---------------------------------------------------------------- + +TEST_F(BTreeDamageVisitorTests, null_test) +{ + +} + +//----------------------------------------------------------------