diff --git a/btree.h b/btree.h index f7e26b3..aae571c 100644 --- a/btree.h +++ b/btree.h @@ -299,6 +299,22 @@ namespace persistent_data { // free the on disk btree when the destructor is called void destroy(); + + // Derive a class from this base class if you need to + // inspect the individual nodes that make up a btree. + class visitor { + public: + virtual ~visitor() {} + typedef boost::shared_ptr ptr; + + virtual void visit_internal(unsigned level, btree_detail::node_ref const &n) = 0; + virtual void visit_internal_leaf(unsigned level, btree_detail::node_ref const &n) = 0; + virtual void visit_leaf(unsigned level, btree_detail::node_ref const &n) = 0; + }; + + // Walks the tree in depth first order + void visit(typename visitor::ptr visitor); + private: template void split_node(btree_detail::shadow_spine &spine, @@ -321,6 +337,9 @@ namespace persistent_data { uint64_t key, int *index); + void walk_tree(typename visitor::ptr visitor, + unsigned level, block_address b); + typename persistent_data::transaction_manager::ptr tm_; bool destroy_; block_address root_; diff --git a/btree.tcc b/btree.tcc index 7b84efe..3b51eab 100644 --- a/btree.tcc +++ b/btree.tcc @@ -590,5 +590,36 @@ insert_location(btree_detail::shadow_spine &spine, (leaf.key_at(i) != key)); } +template +void +btree::visit(typename visitor::ptr visitor) +{ + walk_tree(visitor, 0, root_); +} + +template +void +btree:: +walk_tree(typename visitor::ptr visitor, + unsigned level, block_address b) +{ + using namespace btree_detail; + auto blk = tm_->read_lock(b); + auto o = to_node(blk); + if (o.get_type() == INTERNAL) { + visitor->visit_internal(level, o); + for (unsigned i = 0; i < o.get_nr_entries(); i++) + walk_tree(visitor, level, o.value_at(i)); + + } else if (level < Levels - 1) { + visitor->visit_internal_leaf(level, o); + for (unsigned i = 0; i < o.get_nr_entries(); i++) + walk_tree(visitor, level + 1, o.value_at(i)); + + } else { + auto ov = to_node(blk); + visitor->visit_leaf(level, ov); + } +} //---------------------------------------------------------------- diff --git a/unit-tests/btree_t.cc b/unit-tests/btree_t.cc index 87f30da..fa40eb0 100644 --- a/unit-tests/btree_t.cc +++ b/unit-tests/btree_t.cc @@ -30,6 +30,28 @@ namespace { new btree<1, uint64_traits, 4096>( create_tm(), rc)); } + + class constraint_visitor : public btree<1, uint64_traits, 4096>::visitor { + private: + void visit_internal(unsigned level, btree_detail::node_ref const &n) { + // cout << "internal: level = " << level << ", nr_entries = " << n.get_nr_entries() << endl; + } + + void visit_internal_leaf(unsigned level, btree_detail::node_ref const &n) { + // cout << "internal_leaf !" << endl; + } + + void visit_leaf(unsigned level, btree_detail::node_ref const &n) { + // cout << "leaf: level = " << level << ", nr_entries = " << n.get_nr_entries() << endl; + } + }; + + void check_constraints(btree<1, uint64_traits, 4096>::ptr tree) { + typedef btree<1, uint64_traits, 4096> tree_type; + + typename tree_type::visitor::ptr v(new constraint_visitor); + tree->visit(v); + } } //----------------------------------------------------------------