diff --git a/caching/cache_check.cc b/caching/cache_check.cc index 419169f..8f6ab7d 100644 --- a/caching/cache_check.cc +++ b/caching/cache_check.cc @@ -17,6 +17,7 @@ #include "caching/metadata.h" #include "persistent-data/block.h" #include "persistent-data/file_utils.h" +#include "persistent-data/space_map.h" #include "persistent-data/space-maps/core.h" #include "version.h" @@ -158,6 +159,15 @@ namespace { using reporter_base::get_error; }; + class space_map_reporter : public space_map_detail::visitor, reporter_base { + public: + space_map_reporter(nested_output &o) + : reporter_base(o) { + } + + using reporter_base::get_error; + }; + //-------------------------------- transaction_manager::ptr open_tm(block_manager<>::ptr bm) { diff --git a/persistent-data/data-structures/array.h b/persistent-data/data-structures/array.h index 654902d..6c76bf2 100644 --- a/persistent-data/data-structures/array.h +++ b/persistent-data/data-structures/array.h @@ -21,6 +21,7 @@ #include "persistent-data/math_utils.h" #include "persistent-data/data-structures/btree.h" +#include "persistent-data/data-structures/btree_counter.h" #include "persistent-data/data-structures/btree_damage_visitor.h" #include "persistent-data/data-structures/array_block.h" @@ -275,10 +276,9 @@ namespace persistent_data { template void visit_values(ValueVisitor &value_visitor, DamageVisitor &damage_visitor) const { - block_counter counter; block_value_visitor bvisitor(*this, value_visitor); block_damage_visitor dvisitor(damage_visitor, entries_per_block_); - btree_visit_values(block_tree_, counter, bvisitor, dvisitor); + btree_visit_values(block_tree_, bvisitor, dvisitor); // check that all blocks were seen unsigned h = bvisitor.get_highest_seen(); @@ -288,6 +288,26 @@ namespace persistent_data { } } + //-------------------------------- + + struct ablock_counter { + ablock_counter(block_counter &bc) + : bc_(bc) { + } + + void visit(btree_detail::node_location const &loc, block_address b) { + bc_.inc(b); + } + + private: + block_counter &bc_; + }; + + void count_metadata_blocks(block_counter &bc) const { + ablock_counter vc(bc); + count_btree_blocks(block_tree_, bc, vc); + } + private: struct resizer { diff --git a/persistent-data/data-structures/btree_checker.h b/persistent-data/data-structures/btree_checker.h deleted file mode 100644 index d78505f..0000000 --- a/persistent-data/data-structures/btree_checker.h +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright (C) 2011 Red Hat, Inc. All rights reserved. -// -// This file is part of the thin-provisioning-tools source. -// -// thin-provisioning-tools is free software: you can redistribute it -// and/or modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// thin-provisioning-tools is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with thin-provisioning-tools. If not, see -// . - -#ifndef BTREE_CHECKER_H -#define BTREE_CHECKER_H - -#include "btree.h" - -#include "persistent-data/block_counter.h" -#include "persistent-data/checksum.h" -#include "persistent-data/error_set.h" - -#include -#include -#include - -using namespace persistent_data; -using namespace std; - -//---------------------------------------------------------------- - -namespace persistent_data { - //---------------------------------------------------------------- - // This class implements consistency checking for the btrees in - // general. 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_checker : public btree::visitor { - public: - typedef btree_detail::node_location node_location; - - btree_checker(block_counter &counter, bool avoid_repeated_visits = true) - : counter_(counter), - errs_(new error_set("btree errors")), - avoid_repeated_visits_(avoid_repeated_visits) { - } - - 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); - } - - error_set::ptr get_errors() const { - return errs_; - } - - protected: - block_counter &get_counter() { - return counter_; - } - - 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.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()); - - 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.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()); - - 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_; - std::set seen_; - error_set::ptr errs_; - boost::optional last_leaf_key_[Levels]; - bool avoid_repeated_visits_; - }; -} - -//---------------------------------------------------------------- - -#endif diff --git a/persistent-data/data-structures/btree_counter.h b/persistent-data/data-structures/btree_counter.h new file mode 100644 index 0000000..2f00173 --- /dev/null +++ b/persistent-data/data-structures/btree_counter.h @@ -0,0 +1,81 @@ +#ifndef PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H +#define PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H + +#include "persistent-data/block_counter.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + namespace btree_count_detail { + template + class counting_visitor : public btree::visitor { + public: + typedef btree tree; + + counting_visitor(block_counter &bc, ValueCounter &vc) + : bc_(bc), + vc_(vc) { + } + + virtual bool visit_internal(node_location const &l, + typename tree::internal_node const &n) { + return visit_node(n); + } + + virtual bool visit_internal_leaf(node_location const &l, + typename tree::internal_node const &n) { + return visit_node(n); + } + + virtual bool visit_leaf(node_location const &l, + typename tree::leaf_node const &n) { + if (visit_node(n)) { + unsigned nr = n.get_nr_entries(); + + for (unsigned i = 0; i < nr; i++) { + // FIXME: confirm l2 is correct + node_location l2(l); + l2.push_key(i); + vc_.visit(l2, n.value_at(i)); + } + + return true; + } + + return false; + } + + private: + template + bool visit_node(Node const &n) { + block_address b = n.get_location(); + bool seen = bc_.get_count(b); + bc_.inc(b); + return !seen; + } + + block_counter &bc_; + ValueCounter &vc_; + }; + } + + template + struct noop_value_counter { + void visit(btree_detail::node_location const &loc, T const &v) { + } + }; + + // Counts how many times each metadata block is referenced in the + // tree. Blocks already referenced in the block counter are not + // walked. This walk should only be done once you're sure the tree + // is not corrupt. + template + void count_btree_blocks(btree const &tree, block_counter &bc, ValueCounter &vc) { + btree_count_detail::counting_visitor v(bc, vc); + tree.visit_depth_first(v); + } +} + +//---------------------------------------------------------------- + +#endif diff --git a/persistent-data/data-structures/btree_damage_visitor.h b/persistent-data/data-structures/btree_damage_visitor.h index 67addaa..c8eee3b 100644 --- a/persistent-data/data-structures/btree_damage_visitor.h +++ b/persistent-data/data-structures/btree_damage_visitor.h @@ -136,11 +136,9 @@ namespace persistent_data { typedef run run64; typedef boost::optional maybe_run64; - btree_damage_visitor(block_counter &counter, - ValueVisitor &value_visitor, + btree_damage_visitor(ValueVisitor &value_visitor, DamageVisitor &damage_visitor) - : counter_(counter), - avoid_repeated_visits_(true), + : avoid_repeated_visits_(true), value_visitor_(value_visitor), damage_visitor_(damage_visitor) { } @@ -243,8 +241,6 @@ namespace persistent_data { 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; @@ -441,7 +437,6 @@ namespace persistent_data { //-------------------------------- - block_counter &counter_; bool avoid_repeated_visits_; ValueVisitor &value_visitor_; @@ -458,11 +453,10 @@ namespace persistent_data { template void btree_visit_values(btree const &tree, - block_counter &counter, ValueVisitor &value_visitor, DamageVisitor &damage_visitor) { btree_detail::btree_damage_visitor - v(counter, value_visitor, damage_visitor); + v(value_visitor, damage_visitor); tree.visit_depth_first(v); } } diff --git a/persistent-data/space-maps/careful_alloc.cc b/persistent-data/space-maps/careful_alloc.cc index a0fb180..a25653c 100644 --- a/persistent-data/space-maps/careful_alloc.cc +++ b/persistent-data/space-maps/careful_alloc.cc @@ -97,8 +97,8 @@ namespace { return sm_->copy_root(dest, len); } - virtual void check(block_counter &counter) const { - return sm_->check(counter); + virtual void visit(space_map_detail::visitor &v) const { + return sm_->visit(v); } virtual checked_space_map::ptr clone() const { diff --git a/persistent-data/space-maps/disk.cc b/persistent-data/space-maps/disk.cc index 36937ec..df3ed43 100644 --- a/persistent-data/space-maps/disk.cc +++ b/persistent-data/space-maps/disk.cc @@ -21,7 +21,7 @@ #include "persistent-data/space-maps/recursive.h" #include "persistent-data/space-maps/careful_alloc.h" -#include "persistent-data/data-structures/btree_checker.h" +#include "persistent-data/data-structures/btree_damage_visitor.h" #include "persistent-data/checksum.h" #include "persistent-data/endian_utils.h" #include "persistent-data/math_utils.h" @@ -200,6 +200,7 @@ namespace { } }; +#if 0 class ref_count_checker : public btree_checker<1, ref_count_traits> { public: typedef boost::shared_ptr ptr; @@ -208,6 +209,14 @@ namespace { : btree_checker<1, ref_count_traits>(counter) { } }; +#endif + + class index_entry_visitor { + public: + virtual ~index_entry_visitor() {} + virtual void visit(index_entry const &ie) = 0; + virtual void visit(run const &missing) = 0; + }; class index_store { public: @@ -219,7 +228,7 @@ namespace { virtual void commit_ies() = 0; virtual ptr clone() const = 0; virtual block_address get_root() const = 0; - virtual void check(block_counter &counter, block_address nr_index_entries) const = 0; + virtual void visit(index_entry_visitor &v, block_address nr_index_entries) const = 0; }; unsigned const ENTRIES_PER_BLOCK = (MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4; @@ -358,12 +367,14 @@ namespace { nr_blocks_ = nr_blocks; } - virtual void check(block_counter &counter) const { - ref_count_checker v(counter); - ref_counts_.visit_depth_first(v); + virtual void visit(space_map_detail::visitor &v) const { +#if 0 + ref_count_checker rcv(v); + ref_counts_.visit_depth_first(rcv); block_address nr_entries = div_up(get_nr_blocks(), ENTRIES_PER_BLOCK); - indexes_->check(counter, nr_entries); + indexes_->visit(v, nr_entries); +#endif } struct look_aside_iterator : public iterator { @@ -498,56 +509,34 @@ namespace { btree<1, ref_count_traits> ref_counts_; }; - class bitmap_tree_validator : public btree_checker<1, index_entry_traits> { + //-------------------------------- + + class ie_value_visitor { public: - typedef btree_detail::node_location node_location; - typedef boost::shared_ptr ptr; - - bitmap_tree_validator(block_counter &counter) - : btree_checker<1, index_entry_traits>(counter) { + ie_value_visitor(index_entry_visitor &v) + : v_(v) { } - bool visit_leaf(node_location const &loc, - btree_detail::node_ref const &n) { - bool r = btree_checker<1, index_entry_traits>::visit_leaf(loc, n); - if (!r) - return r; - - for (unsigned i = 0; i < n.get_nr_entries(); i++) { - if (seen_indexes_.count(n.key_at(i)) > 0) { - ostringstream out; - out << "index entry " << i << " is present twice"; - throw runtime_error(out.str()); - } - - seen_indexes_.insert(n.key_at(i)); - btree_checker<1, index_entry_traits>::get_counter().inc(n.value_at(i).blocknr_); - } - - return true; - } - - void check_all_index_entries_present(block_address nr_entries) { - for (block_address i = 0; i < nr_entries; i++) { - if (seen_indexes_.count(i) == 0) { - ostringstream out; - out << "missing index entry " << i; - throw runtime_error(out.str()); - } - } - - set::const_iterator it; - for (it = seen_indexes_.begin(); it != seen_indexes_.end(); ++it) { - if (*it >= nr_entries) { - ostringstream out; - out << "unexpected index entry " << *it; - throw runtime_error(out.str()); - } - } + virtual void visit(btree_path const &path, sm_disk_detail::index_entry const &ie) { + // FIXME: finish } private: - set seen_indexes_; + index_entry_visitor &v_; + }; + + class ie_damage_visitor { + public: + ie_damage_visitor(index_entry_visitor &v) + : v_(v) { + } + + virtual void visit(btree_path const &path, btree_detail::damage const &d) { + // FIXME: finish + } + + private: + index_entry_visitor &v_; }; class btree_index_store : public index_store { @@ -595,10 +584,10 @@ namespace { return bitmaps_.get_root(); } - virtual void check(block_counter &counter, block_address nr_index_entries) const { - bitmap_tree_validator v(counter); - bitmaps_.visit_depth_first(v); - v.check_all_index_entries_present(nr_index_entries); + virtual void visit(index_entry_visitor &v, block_address nr_index_entries) const { + ie_value_visitor vv(v); + ie_damage_visitor dv(v); + btree_visit_values(bitmaps_, vv, dv); } private: @@ -654,12 +643,18 @@ namespace { return bitmap_root_; } - virtual void check(block_counter &counter, block_address nr_index_entries) const { + virtual void visit(index_entry_visitor &vv, block_address nr_index_entries) const { + for (unsigned i = 0; i < entries_.size(); i++) + if (entries_[i].blocknr_ != 0) + vv.visit(entries_[i]); + +#if 0 counter.inc(bitmap_root_); for (unsigned i = 0; i < entries_.size(); i++) // FIXME: this looks like a hack if (entries_[i].blocknr_ != 0) // superblock counter.inc(entries_[i].blocknr_); +#endif } private: diff --git a/persistent-data/space-maps/recursive.cc b/persistent-data/space-maps/recursive.cc index f7939e9..6533c20 100644 --- a/persistent-data/space-maps/recursive.cc +++ b/persistent-data/space-maps/recursive.cc @@ -188,10 +188,10 @@ namespace { return sm_->copy_root(dest, len); } - virtual void check(persistent_data::block_counter &counter) const { + virtual void visit(space_map_detail::visitor &v) const { cant_recurse("check"); recursing_const_lock lock(*this); - return sm_->check(counter); + return sm_->visit(v); } virtual checked_space_map::ptr clone() const { diff --git a/persistent-data/space_map.h b/persistent-data/space_map.h index 8f37b0b..5395c90 100644 --- a/persistent-data/space_map.h +++ b/persistent-data/space_map.h @@ -19,8 +19,9 @@ #ifndef SPACE_MAP_H #define SPACE_MAP_H -#include "block.h" -#include "block_counter.h" +#include "persistent-data/block.h" +#include "persistent-data/block_counter.h" +#include "persistent-data/run.h" #include #include @@ -114,6 +115,28 @@ namespace persistent_data { } }; + //-------------------------------- + + namespace space_map_detail { + class damage { + virtual ~damage() {} + }; + + class missing_counts : public damage { + public: + missing_counts(base::run &lost); + }; + + class visitor { + public: + virtual ~visitor() {} + virtual void visit(missing_counts const &mc) = 0; + virtual void visit(block_address b, uint32_t count) = 0; + }; + } + + //-------------------------------- + class persistent_space_map : public space_map { public: typedef boost::shared_ptr ptr; @@ -126,8 +149,8 @@ namespace persistent_data { public: typedef boost::shared_ptr ptr; - virtual void check(block_counter &counter) const { - throw std::runtime_error("'check' not implemented"); + virtual void visit(space_map_detail::visitor &v) const { + throw std::runtime_error("space_map.visit not implemented"); } // FIXME: should this be in the base space_map class? diff --git a/thin-provisioning/device_tree.cc b/thin-provisioning/device_tree.cc index ef5d097..223d816 100644 --- a/thin-provisioning/device_tree.cc +++ b/thin-provisioning/device_tree.cc @@ -84,10 +84,9 @@ thin_provisioning::walk_device_tree(device_tree const &tree, device_tree_detail::device_visitor &vv, device_tree_detail::damage_visitor &dv) { - block_counter counter; visitor_adapter av(vv); ll_damage_visitor ll_dv(dv); - btree_visit_values(tree, counter, av, ll_dv); + btree_visit_values(tree, av, ll_dv); } void diff --git a/thin-provisioning/mapping_tree.cc b/thin-provisioning/mapping_tree.cc index 007d1dd..ea3292f 100644 --- a/thin-provisioning/mapping_tree.cc +++ b/thin-provisioning/mapping_tree.cc @@ -173,9 +173,8 @@ thin_provisioning::walk_mapping_tree(dev_tree const &tree, mapping_tree_detail::device_visitor &dev_v, mapping_tree_detail::damage_visitor &dv) { - block_counter counter; ll_damage_visitor ll_dv(dv); - btree_visit_values(tree, counter, dev_v, ll_dv); + btree_visit_values(tree, dev_v, ll_dv); } void @@ -191,9 +190,8 @@ thin_provisioning::walk_mapping_tree(mapping_tree const &tree, mapping_tree_detail::mapping_visitor &mv, mapping_tree_detail::damage_visitor &dv) { - block_counter counter; ll_damage_visitor ll_dv(dv); - btree_visit_values(tree, counter, mv, ll_dv); + btree_visit_values(tree, mv, ll_dv); } void @@ -209,9 +207,8 @@ thin_provisioning::walk_mapping_tree(single_mapping_tree const &tree, mapping_tree_detail::mapping_visitor &mv, mapping_tree_detail::damage_visitor &dv) { - block_counter counter; ll_damage_visitor ll_dv(dv); - btree_visit_values(tree, counter, mv, ll_dv); + btree_visit_values(tree, mv, ll_dv); } void diff --git a/thin-provisioning/thin_pool.cc b/thin-provisioning/thin_pool.cc index cb2655e..23725d4 100644 --- a/thin-provisioning/thin_pool.cc +++ b/thin-provisioning/thin_pool.cc @@ -18,8 +18,6 @@ #include "thin-provisioning/thin_pool.h" -#include "persistent-data/data-structures/btree_checker.h" - #include #include #include diff --git a/thin-provisioning/thin_rmap.cc b/thin-provisioning/thin_rmap.cc index bfbd67f..9211459 100644 --- a/thin-provisioning/thin_rmap.cc +++ b/thin-provisioning/thin_rmap.cc @@ -63,7 +63,6 @@ namespace { } int rmap(string const &path, vector const ®ions) { - block_counter counter; // FIXME: get rid of this counter arg damage_visitor dv; rmap_visitor rv; @@ -79,7 +78,7 @@ namespace { mapping_tree mtree(tm, sb.data_mapping_root_, mapping_tree_detail::block_traits::ref_counter(tm->get_sm())); - btree_visit_values(mtree, counter, rv, dv); + btree_visit_values(mtree, rv, dv); rv.complete(); display_rmap(cout, rv.get_rmap()); diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in index db790e6..d2506ec 100644 --- a/unit-tests/Makefile.in +++ b/unit-tests/Makefile.in @@ -51,6 +51,7 @@ TEST_SOURCE=\ unit-tests/bitset_t.cc \ unit-tests/block_t.cc \ unit-tests/btree_t.cc \ + unit-tests/btree_counter_t.cc \ unit-tests/btree_damage_visitor_t.cc \ unit-tests/buffer_t.cc \ unit-tests/cache_t.cc \ diff --git a/unit-tests/btree_counter_t.cc b/unit-tests/btree_counter_t.cc new file mode 100644 index 0000000..5f4a7d0 --- /dev/null +++ b/unit-tests/btree_counter_t.cc @@ -0,0 +1,84 @@ +#include "gmock/gmock.h" + +#include "test_utils.h" + +#include "persistent-data/data-structures/btree.h" +#include "persistent-data/data-structures/btree_counter.h" +#include "persistent-data/space-maps/core.h" + +using namespace base; +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; + block_address const SUPERBLOCK = 0; + + class BTreeCounterTests : public Test { + public: + BTreeCounterTests() + : bm_(create_bm(NR_BLOCKS)), + sm_(setup_core_map()), + tm_(new transaction_manager(bm_, sm_)) { + } + + void check_nr_metadata_blocks_is_ge(unsigned n) { + block_counter bc; + noop_value_counter vc; + count_btree_blocks(*tree_, bc, vc); + ASSERT_THAT(bc.get_counts().size(), Ge(n)); + } + + with_temp_directory dir_; + block_manager<>::ptr bm_; + space_map::ptr sm_; + transaction_manager::ptr tm_; + uint64_traits::ref_counter rc_; + + btree<1, uint64_traits>::ptr tree_; + + private: + space_map::ptr setup_core_map() { + space_map::ptr sm(new core_map(NR_BLOCKS)); + sm->inc(SUPERBLOCK); + return sm; + } + + void commit() { + block_manager<>::write_ref superblock(bm_->superblock(SUPERBLOCK)); + } + }; + + void dump_counts(block_counter const &bc) { + block_counter::count_map::const_iterator it, end = bc.get_counts().end(); + for (it = bc.get_counts().begin(); it != end; ++it) + cout << it->first << " -> " << it->second << endl; + } +} + +//---------------------------------------------------------------- + +TEST_F(BTreeCounterTests, count_empty_tree) +{ + tree_.reset(new btree<1, uint64_traits>(tm_, rc_)); + check_nr_metadata_blocks_is_ge(1); +} + +TEST_F(BTreeCounterTests, count_populated_tree) +{ + tree_.reset(new btree<1, uint64_traits>(tm_, rc_)); + + for (unsigned i = 0; i < 10000; i++) { + uint64_t key[1] = {i}; + tree_->insert(key, 0ull); + } + + check_nr_metadata_blocks_is_ge(40); +} + +//---------------------------------------------------------------- diff --git a/unit-tests/btree_damage_visitor_t.cc b/unit-tests/btree_damage_visitor_t.cc index 175f0a7..d6eb9c4 100644 --- a/unit-tests/btree_damage_visitor_t.cc +++ b/unit-tests/btree_damage_visitor_t.cc @@ -388,8 +388,7 @@ namespace { } virtual void run_() { - block_counter counter; - btree_visit_values(*tree_, counter, value_visitor_, damage_visitor_); + btree_visit_values(*tree_, value_visitor_, damage_visitor_); } }; @@ -470,8 +469,7 @@ namespace { } virtual void run_() { - block_counter counter; - btree_visit_values(*tree_, counter, value_visitor_, damage_visitor_); + btree_visit_values(*tree_, value_visitor_, damage_visitor_); } }; }