From 347003e6f330800236b511971f6ef8a9348964c3 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 1 Mar 2012 14:57:09 +0000 Subject: [PATCH] stop btree_checker throwing. Instead it records the errors and steps around the bad parts of the tree. --- btree_checker.h | 149 +++++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 66 deletions(-) diff --git a/btree_checker.h b/btree_checker.h index d1e1425..f7d2512 100644 --- a/btree_checker.h +++ b/btree_checker.h @@ -65,63 +65,21 @@ namespace persistent_data { bool sub_root, optional key, btree_detail::node_ref const &n) { - if (already_visited(n)) - return false; - - check_sum(n); - - if (sub_root) - new_root(level); - - check_block_nr(n); - check_max_entries(n); - check_nr_entries(n, sub_root); - check_ordered_keys(n); - check_parent_key(sub_root ? optional() : key, n); - return true; + return check_internal(level, sub_root, key, n); } bool visit_internal_leaf(unsigned level, bool sub_root, optional key, btree_detail::node_ref const &n) { - if (already_visited(n)) - return false; - - check_sum(n); - - if (sub_root) - new_root(level); - - check_block_nr(n); - check_max_entries(n); - check_nr_entries(n, sub_root); - check_ordered_keys(n); - check_parent_key(sub_root ? optional() : key, n); - check_leaf_key(level, n); - - return true; + return check_leaf(level, sub_root, key, n); } bool visit_leaf(unsigned level, bool sub_root, optional key, btree_detail::node_ref const &n) { - if (already_visited(n)) - return false; - - check_sum(n); - - if (sub_root) - new_root(level); - - check_block_nr(n); - check_max_entries(n); - check_nr_entries(n, sub_root); - check_ordered_keys(n); - check_parent_key(sub_root ? optional() : key, n); - check_leaf_key(level, n); - return true; + return check_leaf(level, sub_root, key, n); } boost::optional get_errors() const { @@ -134,6 +92,48 @@ namespace persistent_data { } private: + bool check_internal(unsigned level, + bool sub_root, + optional key, + btree_detail::node_ref const &n) { + if (!already_visited(n) && + check_sum(n) && + check_block_nr(n) && + check_max_entries(n) && + check_nr_entries(n, sub_root) && + check_ordered_keys(n) && + check_parent_key(sub_root ? optional() : key, n)) { + if (sub_root) + new_root(level); + + return true; + } + + return false; + } + + template + bool check_leaf(unsigned level, + bool sub_root, + optional key, + btree_detail::node_ref const &n) { + if (!already_visited(n) && + check_sum(n) && + check_block_nr(n) && + check_max_entries(n) && + check_nr_entries(n, sub_root) && + check_ordered_keys(n) && + check_parent_key(sub_root ? optional() : key, n)) { + if (sub_root) + new_root(level); + + return check_leaf_key(level, n); + } + + return false; + } + + template bool already_visited(node const &n) { block_address b = n.get_location(); @@ -148,7 +148,7 @@ namespace persistent_data { } template - void check_sum(node const &n) const { + bool check_sum(node const &n) const { crc32c sum(BTREE_CSUM_XOR); disk_node const *data = n.raw(); @@ -159,48 +159,55 @@ namespace persistent_data { << ", sum was " << sum.get_sum() << ", on disk " << n.get_checksum(); errs_->add_child(out.str()); - throw checksum_error(out.str()); + return false; } + + return true; } template - void check_block_nr(node const &n) const { + 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()); - throw checksum_error(out.str()); + return false; } + + return true; } template - void check_max_entries(node const &n) const { + 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()); - throw runtime_error(out.str()); + return false; } + + return true; } template - void check_nr_entries(node const &n, bool is_root) const { + 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()); - throw std::runtime_error(out.str()); + return false; } block_address min = n.get_max_entries() / 3; @@ -212,16 +219,18 @@ namespace persistent_data { << min << "(max_entries = " << n.get_max_entries() << ")"; errs_->add_child(out.str()); - throw runtime_error(out.str()); + return false; } + + return true; } template - void check_ordered_keys(node const &n) const { + bool check_ordered_keys(node const &n) const { unsigned nr_entries = n.get_nr_entries(); if (nr_entries == 0) - return; // can only happen if a root node + return true; // can only happen if a root node uint64_t last_key = n.key_at(0); @@ -230,44 +239,52 @@ namespace persistent_data { if (k <= last_key) { ostringstream out; out << "keys are out of order, " << k << " <= " << last_key; - throw runtime_error(out.str()); + errs_->add_child(out.str()); + return false; } last_key = k; } + + return true; } template - void check_parent_key(boost::optional key, node const &n) const { + bool check_parent_key(boost::optional key, node const &n) const { if (!key) - return; + 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); - throw runtime_error(out.str()); + errs_->add_child(out.str()); + return false; } + + return true; } template - void check_leaf_key(unsigned level, node const &n) { + bool check_leaf_key(unsigned level, node const &n) { if (n.get_nr_entries() == 0) - return; // can only happen if a root node + 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); - throw runtime_error(out.str()); + 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(); + // we're starting a new subtree, so should + // reset the last_leaf value. + last_leaf_key_[level] = boost::optional(); } block_counter &counter_;