Merge branch 'master' of github.com:jthornber/thin-provisioning-tools
This commit is contained in:
		| @@ -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) { | ||||
|   | ||||
| @@ -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 <typename ValueVisitor, typename DamageVisitor> | ||||
| 		void visit_values(ValueVisitor &value_visitor, | ||||
| 				  DamageVisitor &damage_visitor) const { | ||||
| 			block_counter counter; | ||||
| 			block_value_visitor<ValueVisitor> bvisitor(*this, value_visitor); | ||||
| 			block_damage_visitor<DamageVisitor> 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 { | ||||
|   | ||||
| @@ -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 | ||||
| // <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| #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 <sstream> | ||||
| #include <map> | ||||
| #include <set> | ||||
|  | ||||
| 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 <uint32_t Levels, typename ValueTraits> | ||||
| 	class btree_checker : public btree<Levels, ValueTraits>::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<block_traits> const &n) { | ||||
| 			return check_internal(loc, n); | ||||
| 		} | ||||
|  | ||||
| 		bool visit_internal_leaf(node_location const &loc, | ||||
| 					 btree_detail::node_ref<block_traits> const &n) { | ||||
| 			return check_leaf(loc, n); | ||||
| 		} | ||||
|  | ||||
| 		bool visit_leaf(node_location const &loc, | ||||
| 				btree_detail::node_ref<ValueTraits> 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<block_traits> 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<uint64_t>() : loc.key, n)) { | ||||
| 				if (loc.is_sub_root()) | ||||
| 					new_root(loc.level()); | ||||
|  | ||||
| 				return true; | ||||
| 			} | ||||
|  | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		template <typename ValueTraits2> | ||||
| 		bool check_leaf(node_location const &loc, | ||||
| 				btree_detail::node_ref<ValueTraits2> 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<uint64_t>() : loc.key, n)) { | ||||
| 				if (loc.is_sub_root()) | ||||
| 					new_root(loc.level()); | ||||
|  | ||||
| 				return check_leaf_key(loc.level(), n); | ||||
| 			} | ||||
|  | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		template <typename node> | ||||
| 		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 <typename node> | ||||
| 		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 <typename node> | ||||
| 		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 <typename node> | ||||
| 		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 <typename node> | ||||
| 		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 <typename node> | ||||
| 		bool check_parent_key(boost::optional<uint64_t> 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 <typename node> | ||||
| 		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<uint64_t>(); | ||||
| 	        } | ||||
|  | ||||
| 		block_counter &counter_; | ||||
| 		std::set<block_address> seen_; | ||||
| 		error_set::ptr errs_; | ||||
| 		boost::optional<uint64_t> last_leaf_key_[Levels]; | ||||
| 		bool avoid_repeated_visits_; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										81
									
								
								persistent-data/data-structures/btree_counter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								persistent-data/data-structures/btree_counter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <unsigned Levels, typename ValueTraits, typename ValueCounter> | ||||
| 		class counting_visitor : public btree<Levels, ValueTraits>::visitor { | ||||
| 		public: | ||||
| 			typedef btree<Levels, ValueTraits> 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 <typename Node> | ||||
| 			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 <typename T> | ||||
| 	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 <unsigned Levels, typename ValueTraits, typename ValueCounter> | ||||
| 	void count_btree_blocks(btree<Levels, ValueTraits> const &tree, block_counter &bc, ValueCounter &vc) { | ||||
| 		btree_count_detail::counting_visitor<Levels, ValueTraits, ValueCounter> v(bc, vc); | ||||
| 		tree.visit_depth_first(v); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| #endif | ||||
| @@ -136,11 +136,9 @@ namespace persistent_data { | ||||
| 			typedef run<block_address> run64; | ||||
| 			typedef boost::optional<run64> 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 <unsigned Levels, typename ValueTraits, typename ValueVisitor, typename DamageVisitor> | ||||
| 	void btree_visit_values(btree<Levels, ValueTraits> const &tree, | ||||
| 				block_counter &counter, | ||||
| 				ValueVisitor &value_visitor, | ||||
| 				DamageVisitor &damage_visitor) { | ||||
| 		btree_detail::btree_damage_visitor<ValueVisitor, DamageVisitor, Levels, ValueTraits> | ||||
| 			v(counter, value_visitor, damage_visitor); | ||||
| 			v(value_visitor, damage_visitor); | ||||
| 		tree.visit_depth_first(v); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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<ref_count_checker> 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<block_address> 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<block_address>(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<bitmap_tree_validator> 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<index_entry_traits> 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<block_address>::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<block_address> 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: | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 <boost/shared_ptr.hpp> | ||||
| #include <boost/optional.hpp> | ||||
| @@ -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<block_address> &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<persistent_space_map> ptr; | ||||
| @@ -126,8 +149,8 @@ namespace persistent_data { | ||||
| 	public: | ||||
| 		typedef boost::shared_ptr<checked_space_map> 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? | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -18,8 +18,6 @@ | ||||
|  | ||||
| #include "thin-provisioning/thin_pool.h" | ||||
|  | ||||
| #include "persistent-data/data-structures/btree_checker.h" | ||||
|  | ||||
| #include <stdexcept> | ||||
| #include <sstream> | ||||
| #include <iostream> | ||||
|   | ||||
| @@ -63,7 +63,6 @@ namespace { | ||||
| 	} | ||||
|  | ||||
| 	int rmap(string const &path, vector<region> 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()); | ||||
|  | ||||
|   | ||||
| @@ -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 \ | ||||
|   | ||||
							
								
								
									
										84
									
								
								unit-tests/btree_counter_t.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								unit-tests/btree_counter_t.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -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<BLOCK_SIZE>(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<uint64_t> 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); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
| @@ -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_); | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user