diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index 5a96d5d..94e255b 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -2,6 +2,7 @@ #define PERSISTENT_DATA_DATA_STRUCTURES_DAMAGE_VISITOR_H #include "persistent-data/data-structures/btree.h" +#include "persistent-data/data-structures/btree_node_checker.h" #include "persistent-data/run.h" //---------------------------------------------------------------- @@ -222,44 +223,55 @@ namespace persistent_data { bool check_internal(node_location const &loc, btree_detail::node_ref const &n) { - if (!already_visited(n) && - check_block_nr(n) && - check_value_size(n) && - check_max_entries(n) && - check_nr_entries(n, loc.is_sub_root()) && - check_ordered_keys(n) && - check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { - if (loc.is_sub_root()) - new_root(loc.level()); + if (already_visited(n)) + return false; + else if (!checker_.check_block_nr(n) || + !checker_.check_value_size(n) || + !checker_.check_max_entries(n) || + !checker_.check_nr_entries(n, loc.is_sub_root()) || + !checker_.check_ordered_keys(n) || + !checker_.check_parent_key(n, loc.is_sub_root() ? boost::optional() : loc.key)) { + report_damage(checker_.get_last_error_string()); - good_internal(n.key_at(0)); - return true; + return false; } - return false; + if (loc.is_sub_root()) + new_root(loc.level()); + + good_internal(n.key_at(0)); + + return true; } template bool check_leaf(node_location const &loc, btree_detail::node_ref const &n) { - if (!already_visited(n) && - check_block_nr(n) && - check_value_size(n) && - check_max_entries(n) && - check_nr_entries(n, loc.is_sub_root()) && - check_ordered_keys(n) && - check_parent_key(loc.is_sub_root() ? boost::optional() : loc.key, n)) { - if (loc.is_sub_root()) - new_root(loc.level()); + if (already_visited(n)) + return false; + else if (!checker_.check_block_nr(n) || + !checker_.check_value_size(n) || + !checker_.check_max_entries(n) || + !checker_.check_nr_entries(n, loc.is_sub_root()) || + !checker_.check_ordered_keys(n) || + !checker_.check_parent_key(n, loc.is_sub_root() ? boost::optional() : loc.key)) { + report_damage(checker_.get_last_error_string()); - bool r = check_leaf_key(loc.level(), n); - if (r && n.get_nr_entries() > 0) - good_leaf(n.key_at(0), n.key_at(n.get_nr_entries() - 1) + 1); - - return r; + return false; } - return false; + if (loc.is_sub_root()) + new_root(loc.level()); + + bool r = checker_.check_leaf_key(n, last_leaf_key_[loc.level()]); + if (!r) + report_damage(checker_.get_last_error_string()); + else if (n.get_nr_entries() > 0) { + last_leaf_key_[loc.level()] = n.key_at(n.get_nr_entries() - 1); + good_leaf(n.key_at(0), n.key_at(n.get_nr_entries() - 1) + 1); + } + + return r; } template @@ -276,140 +288,6 @@ namespace persistent_data { return false; } - template - 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(); - - report_damage(out.str()); - return false; - } - - return true; - } - - template - bool check_value_size(node const &n) { - if (!n.value_sizes_match()) { - report_damage(n.value_mismatch_string()); - return false; - } - - return true; - } - - template - 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() - << " (block " << n.get_location() << ")"; - report_damage(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() - << " (block " << n.get_location() << ")"; - report_damage(out.str()); - return false; - } - - return true; - } - - template - 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() - << " (block " << n.get_location() << ")"; - report_damage(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_node: " - << n.get_nr_entries() - << ", expected at least " - << min - << " (block " << n.get_location() - << ", max_entries = " << n.get_max_entries() << ")"; - report_damage(out.str()); - return false; - } - - return true; - } - - template - bool check_ordered_keys(node const &n) { - 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 - << " (block " << n.get_location() << ")"; - report_damage(out.str()); - return false; - } - last_key = k; - } - - return true; - } - - template - bool check_parent_key(boost::optional key, node const &n) { - 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) - << " (block " << n.get_location() << ")"; - report_damage(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) - << " (block " << n.get_location() << ")"; - report_damage(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. @@ -487,6 +365,7 @@ namespace persistent_data { std::set seen_; boost::optional last_leaf_key_[Levels]; + btree_node_checker checker_; path_tracker path_tracker_; damage_tracker dt_; std::list damage_reasons_;