check keys are strictly ordered, and parent keys are correct
This commit is contained in:
parent
096da9233b
commit
e727bc943a
11
btree.h
11
btree.h
@ -325,9 +325,12 @@ namespace persistent_data {
|
|||||||
|
|
||||||
// The bool return values indicate whether the walk
|
// The bool return values indicate whether the walk
|
||||||
// should be continued into sub trees of the node (true == continue).
|
// should be continued into sub trees of the node (true == continue).
|
||||||
virtual bool visit_internal(unsigned level, bool is_root, internal_node const &n) = 0;
|
virtual bool visit_internal(unsigned level, boost::optional<uint64_t> key,
|
||||||
virtual bool visit_internal_leaf(unsigned level, bool is_root, internal_node const &n) = 0;
|
internal_node const &n) = 0;
|
||||||
virtual bool visit_leaf(unsigned level, bool is_root, leaf_node const &n) = 0;
|
virtual bool visit_internal_leaf(unsigned level, boost::optional<uint64_t> key,
|
||||||
|
internal_node const &n) = 0;
|
||||||
|
virtual bool visit_leaf(unsigned level, boost::optional<uint64_t> key,
|
||||||
|
leaf_node const &n) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Walks the tree in depth first order
|
// Walks the tree in depth first order
|
||||||
@ -356,7 +359,7 @@ namespace persistent_data {
|
|||||||
int *index);
|
int *index);
|
||||||
|
|
||||||
void walk_tree(typename visitor::ptr visitor,
|
void walk_tree(typename visitor::ptr visitor,
|
||||||
unsigned level, bool is_root,
|
unsigned level, boost::optional<uint64_t> key,
|
||||||
block_address b) const;
|
block_address b) const;
|
||||||
|
|
||||||
typename persistent_data::transaction_manager::ptr tm_;
|
typename persistent_data::transaction_manager::ptr tm_;
|
||||||
|
14
btree.tcc
14
btree.tcc
@ -592,14 +592,14 @@ template <unsigned Levels, typename ValueTraits>
|
|||||||
void
|
void
|
||||||
btree<Levels, ValueTraits>::visit(typename visitor::ptr visitor) const
|
btree<Levels, ValueTraits>::visit(typename visitor::ptr visitor) const
|
||||||
{
|
{
|
||||||
walk_tree(visitor, 0, true, root_);
|
walk_tree(visitor, 0, boost::optional<uint64_t>(), root_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <unsigned Levels, typename ValueTraits>
|
template <unsigned Levels, typename ValueTraits>
|
||||||
void
|
void
|
||||||
btree<Levels, ValueTraits>::
|
btree<Levels, ValueTraits>::
|
||||||
walk_tree(typename visitor::ptr visitor,
|
walk_tree(typename visitor::ptr visitor,
|
||||||
unsigned level, bool is_root,
|
unsigned level, boost::optional<uint64_t> key,
|
||||||
block_address b) const
|
block_address b) const
|
||||||
{
|
{
|
||||||
using namespace btree_detail;
|
using namespace btree_detail;
|
||||||
@ -607,18 +607,18 @@ walk_tree(typename visitor::ptr visitor,
|
|||||||
read_ref blk = tm_->read_lock(b);
|
read_ref blk = tm_->read_lock(b);
|
||||||
internal_node o = to_node<uint64_traits>(blk);
|
internal_node o = to_node<uint64_traits>(blk);
|
||||||
if (o.get_type() == INTERNAL) {
|
if (o.get_type() == INTERNAL) {
|
||||||
if (visitor->visit_internal(level, is_root, o))
|
if (visitor->visit_internal(level, key, o))
|
||||||
for (unsigned i = 0; i < o.get_nr_entries(); i++)
|
for (unsigned i = 0; i < o.get_nr_entries(); i++)
|
||||||
walk_tree(visitor, level, false, o.value_at(i));
|
walk_tree(visitor, level, o.key_at(i), o.value_at(i));
|
||||||
|
|
||||||
} else if (level < Levels - 1) {
|
} else if (level < Levels - 1) {
|
||||||
if (visitor->visit_internal_leaf(level, is_root, o))
|
if (visitor->visit_internal_leaf(level, key, o))
|
||||||
for (unsigned i = 0; i < o.get_nr_entries(); i++)
|
for (unsigned i = 0; i < o.get_nr_entries(); i++)
|
||||||
walk_tree(visitor, level + 1, true, o.value_at(i));
|
walk_tree(visitor, level + 1, boost::optional<uint64_t>(), o.value_at(i));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
leaf_node ov = to_node<ValueTraits>(blk);
|
leaf_node ov = to_node<ValueTraits>(blk);
|
||||||
visitor->visit_leaf(level, is_root, ov);
|
visitor->visit_leaf(level, key, ov);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,36 +72,47 @@ namespace persistent_data {
|
|||||||
errs_(new error_set("btree errors")) {
|
errs_(new error_set("btree errors")) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_internal(unsigned level, bool is_root,
|
bool visit_internal(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<uint64_traits> const &n) {
|
btree_detail::node_ref<uint64_traits> const &n) {
|
||||||
if (already_visited(n))
|
if (already_visited(n))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
check_block_nr(n);
|
check_block_nr(n);
|
||||||
check_max_entries(n);
|
check_max_entries(n);
|
||||||
check_nr_entries(n, is_root);
|
check_nr_entries(n, !key);
|
||||||
|
check_ordered_keys(n);
|
||||||
|
check_parent_key(key, n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_internal_leaf(unsigned level, bool is_root,
|
bool visit_internal_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<uint64_traits> const &n) {
|
btree_detail::node_ref<uint64_traits> const &n) {
|
||||||
if (already_visited(n))
|
if (already_visited(n))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
check_block_nr(n);
|
check_block_nr(n);
|
||||||
check_max_entries(n);
|
check_max_entries(n);
|
||||||
check_nr_entries(n, is_root);
|
check_nr_entries(n, !key);
|
||||||
|
check_ordered_keys(n);
|
||||||
|
check_parent_key(key, n);
|
||||||
|
check_leaf_key(level, n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_leaf(unsigned level, bool is_root,
|
bool visit_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<ValueTraits> const &n) {
|
btree_detail::node_ref<ValueTraits> const &n) {
|
||||||
if (already_visited(n))
|
if (already_visited(n))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
check_block_nr(n);
|
check_block_nr(n);
|
||||||
check_max_entries(n);
|
check_max_entries(n);
|
||||||
check_nr_entries(n, is_root);
|
check_nr_entries(n, !key);
|
||||||
|
check_ordered_keys(n);
|
||||||
|
check_parent_key(key, n);
|
||||||
|
check_leaf_key(level, n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,9 +191,58 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename node>
|
||||||
|
void 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
|
||||||
|
|
||||||
|
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;
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
last_key = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename node>
|
||||||
|
void check_parent_key(boost::optional<uint64_t> key, node const &n) const {
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename node>
|
||||||
|
void check_leaf_key(unsigned level, node const &n) {
|
||||||
|
if (n.get_nr_entries() == 0)
|
||||||
|
return; // 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
last_leaf_key_[level] = n.key_at(n.get_nr_entries() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
block_counter &counter_;
|
block_counter &counter_;
|
||||||
std::set<block_address> seen_;
|
std::set<block_address> seen_;
|
||||||
error_set::ptr errs_;
|
error_set::ptr errs_;
|
||||||
|
boost::optional<uint64_t> last_leaf_key_[Levels];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
metadata.cc
15
metadata.cc
@ -56,10 +56,11 @@ namespace {
|
|||||||
|
|
||||||
// Sharing can only occur in level 1 nodes.
|
// Sharing can only occur in level 1 nodes.
|
||||||
// FIXME: not true once we start having held roots.
|
// FIXME: not true once we start having held roots.
|
||||||
bool visit_internal_leaf(unsigned level, bool is_root,
|
bool visit_internal_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<uint64_traits> const &n) {
|
btree_detail::node_ref<uint64_traits> const &n) {
|
||||||
|
|
||||||
bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, is_root, n);
|
bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, key, n);
|
||||||
if (!r && level == 0) {
|
if (!r && level == 0) {
|
||||||
throw runtime_error("unexpected sharing in level 0 of mapping tree.");
|
throw runtime_error("unexpected sharing in level 0 of mapping tree.");
|
||||||
}
|
}
|
||||||
@ -70,9 +71,10 @@ namespace {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_leaf(unsigned level, bool is_root,
|
bool visit_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<block_traits> const &n) {
|
btree_detail::node_ref<block_traits> const &n) {
|
||||||
bool r = btree_checker<2, block_traits>::visit_leaf(level, is_root, n);
|
bool r = btree_checker<2, block_traits>::visit_leaf(level, key, n);
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
for (unsigned i = 0; i < n.get_nr_entries(); i++)
|
for (unsigned i = 0; i < n.get_nr_entries(); i++)
|
||||||
@ -98,9 +100,10 @@ namespace {
|
|||||||
: btree_checker<1, device_details_traits>(counter) {
|
: btree_checker<1, device_details_traits>(counter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_leaf(unsigned level, bool is_root,
|
bool visit_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<device_details_traits> const &n) {
|
btree_detail::node_ref<device_details_traits> const &n) {
|
||||||
bool r = btree_checker<1, device_details_traits>::visit_leaf(level, is_root, n);
|
bool r = btree_checker<1, device_details_traits>::visit_leaf(level, key, n);
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
for (unsigned i = 0; i < n.get_nr_entries(); i++)
|
for (unsigned i = 0; i < n.get_nr_entries(); i++)
|
||||||
|
@ -109,11 +109,11 @@ namespace {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ref_count_validator : public btree_checker<1, ref_count_traits> {
|
class ref_count_checker : public btree_checker<1, ref_count_traits> {
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<ref_count_validator> ptr;
|
typedef boost::shared_ptr<ref_count_checker> ptr;
|
||||||
|
|
||||||
ref_count_validator(block_counter &counter)
|
ref_count_checker(block_counter &counter)
|
||||||
: btree_checker<1, ref_count_traits>(counter) {
|
: btree_checker<1, ref_count_traits>(counter) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -239,7 +239,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(block_counter &counter) const {
|
virtual void check(block_counter &counter) const {
|
||||||
ref_count_validator::ptr v(new ref_count_validator(counter));
|
ref_count_checker::ptr v(new ref_count_checker(counter));
|
||||||
ref_counts_.visit(v);
|
ref_counts_.visit(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,9 +315,10 @@ namespace {
|
|||||||
: btree_checker<1, index_entry_traits>(counter) {
|
: btree_checker<1, index_entry_traits>(counter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_leaf(unsigned level, bool is_root,
|
bool visit_leaf(unsigned level,
|
||||||
|
optional<uint64_t> key,
|
||||||
btree_detail::node_ref<index_entry_traits> const &n) {
|
btree_detail::node_ref<index_entry_traits> const &n) {
|
||||||
bool r = btree_checker<1, index_entry_traits>::visit_leaf(level, is_root, n);
|
bool r = btree_checker<1, index_entry_traits>::visit_leaf(level, key, n);
|
||||||
if (!r)
|
if (!r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user