btree_damage_tracker
This commit is contained in:
		| @@ -30,6 +30,68 @@ namespace persistent_data { | ||||
| 			range<uint64_t> lost_keys_; | ||||
| 			std::string desc_; | ||||
| 		}; | ||||
|  | ||||
| 		class damage_tracker { | ||||
| 		public: | ||||
| 			damage_tracker() | ||||
| 				: damaged_(false), | ||||
| 				  damage_begin_(0) { | ||||
| 			} | ||||
|  | ||||
| 			typedef range<block_address> range64; | ||||
| 			typedef boost::optional<range64> maybe_range64; | ||||
|  | ||||
| 			void bad_node() { | ||||
| 				damaged_ = true; | ||||
| 			} | ||||
|  | ||||
| 			maybe_range64 good_internal(block_address begin) { | ||||
| 				maybe_range64 r; | ||||
|  | ||||
| 				if (damaged_) { | ||||
| 					r = maybe_range64(range64(damage_begin_, begin)); | ||||
| 					damaged_ = false; | ||||
| 				} | ||||
|  | ||||
| 				damage_begin_ = begin; | ||||
| 				return r; | ||||
| 			} | ||||
|  | ||||
| 			// remembe 'end' is the one-past-the-end value, so | ||||
| 			// take the last key in the leaf and add one. | ||||
| 			maybe_range64 good_leaf(block_address begin, block_address end) { | ||||
| 				maybe_range64 r; | ||||
|  | ||||
| 				if (damaged_) { | ||||
| 					r = maybe_range64(range64(damage_begin_, begin)); | ||||
| 					damaged_ = false; | ||||
| 				} | ||||
|  | ||||
| 				damage_begin_ = end; | ||||
| 				return r; | ||||
| 			} | ||||
|  | ||||
| 			maybe_range64 end() { | ||||
| 				if (damaged_) | ||||
| 					return maybe_range64(damage_begin_); | ||||
| 				else | ||||
| 					return maybe_range64(); | ||||
| 			} | ||||
|  | ||||
| 		private: | ||||
| 			bool damaged_; | ||||
| 			block_address damage_begin_; | ||||
| 		}; | ||||
|  | ||||
| 		inline | ||||
| 		std::ostream &operator <<(std::ostream &out, damage_tracker::maybe_range64 const &mr) { | ||||
| 			if (mr) | ||||
| 				out << "Just " << *mr; | ||||
| 			else | ||||
| 				out << "Nothing"; | ||||
|  | ||||
| 			return out; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//---------------------------------------------------------------- | ||||
| @@ -68,7 +130,8 @@ namespace persistent_data { | ||||
| 			: counter_(counter), | ||||
| 			  avoid_repeated_visits_(true), | ||||
| 			  value_visitor_(value_visitor), | ||||
| 			  damage_visitor_(damage_visitor) { | ||||
| 			  damage_visitor_(damage_visitor), | ||||
| 			  key_end_(0) { | ||||
| 		} | ||||
|  | ||||
| 		bool visit_internal(node_location const &loc, | ||||
| @@ -121,6 +184,8 @@ namespace persistent_data { | ||||
| 				if (loc.sub_root) | ||||
| 					new_root(loc.level); | ||||
|  | ||||
| 				update_key_end(n.key_at(n.get_nr_entries() - 1) + 1ull); | ||||
|  | ||||
| 				return true; | ||||
| 			} | ||||
|  | ||||
| @@ -139,7 +204,11 @@ namespace persistent_data { | ||||
| 				if (loc.sub_root) | ||||
| 					new_root(loc.level); | ||||
|  | ||||
| 				return check_leaf_key(loc.level, n); | ||||
| 				bool r = check_leaf_key(loc.level, n); | ||||
| 				if (r) | ||||
| 					update_key_end(n.key_at(n.get_nr_entries() - 1) + 1ull); | ||||
|  | ||||
| 				return r; | ||||
| 			} | ||||
|  | ||||
| 			return false; | ||||
| @@ -285,19 +354,33 @@ namespace persistent_data { | ||||
| 			last_leaf_key_[level] = boost::optional<uint64_t>(); | ||||
| 		} | ||||
|  | ||||
| 		void update_key_end(uint64_t end) { | ||||
| 			key_end_ = max(end, key_end_); | ||||
| 		} | ||||
|  | ||||
| 		template <typename node> | ||||
| 		void report_damage(node const &n, std::string const &desc) { | ||||
| 			range<uint64_t> lost_keys; | ||||
| 			range<uint64_t> lost_keys(key_end_); | ||||
| 			damage d(0, lost_keys, desc); | ||||
|  | ||||
| 			cerr << "damage: keys = " << lost_keys << " " << desc << endl; | ||||
| 			damage_visitor_.visit(d); | ||||
| 		} | ||||
|  | ||||
| 		//-------------------------------- | ||||
|  | ||||
| 		// damage tracking | ||||
|  | ||||
| 		void report_damage(std::string const &desc) { | ||||
| 			range<uint64_t> lost_keys; | ||||
| 			range<uint64_t> lost_keys(key_end_); | ||||
| 			damage d(0, lost_keys, desc); | ||||
|  | ||||
| 			cerr << "damage: keys = " << lost_keys << " " << desc << endl; | ||||
| 			damage_visitor_.visit(d); | ||||
| 		} | ||||
|  | ||||
| 		//-------------------------------- | ||||
|  | ||||
| 		block_counter &counter_; | ||||
| 		bool avoid_repeated_visits_; | ||||
|  | ||||
| @@ -306,6 +389,8 @@ namespace persistent_data { | ||||
|  | ||||
| 		std::set<block_address> seen_; | ||||
| 		boost::optional<uint64_t> last_leaf_key_[Levels]; | ||||
|  | ||||
| 		uint64_t key_end_; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										101
									
								
								unit-tests/damage_tracker_t.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								unit-tests/damage_tracker_t.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #include "gmock/gmock.h" | ||||
|  | ||||
| #include "test_utils.h" | ||||
|  | ||||
| #include "persistent-data/data-structures/btree_damage_visitor.h" | ||||
|  | ||||
| using namespace std; | ||||
| using namespace persistent_data; | ||||
| using namespace test; | ||||
| using namespace testing; | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| namespace { | ||||
| 	typedef range<block_address> range64; | ||||
| 	typedef damage_tracker::maybe_range64 mr64; | ||||
|  | ||||
| 	class DamageTrackerTests : public Test { | ||||
| 	public: | ||||
| 		void assert_no_damage(mr64 const &mr) const { | ||||
| 			ASSERT_THAT(mr, Eq(mr64())); | ||||
| 		} | ||||
|  | ||||
| 		void assert_damage(mr64 const &mr, range64 const &expected) const { | ||||
| 			ASSERT_THAT(mr, Eq(mr64(expected))); | ||||
| 		} | ||||
|  | ||||
| 		damage_tracker dt; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| TEST_F(DamageTrackerTests, good_leaf) | ||||
| { | ||||
| 	assert_no_damage(dt.good_leaf(0, 10)); | ||||
| 	assert_no_damage(dt.end()); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, bad_node) | ||||
| { | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.end(), range64(0ull)); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, good_bad) | ||||
| { | ||||
| 	dt.good_leaf(0, 10); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.end(), range64(10ull)); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, bad_good) | ||||
| { | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.good_leaf(10, 20), range64(0ull, 10ull)); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, good_bad_good) | ||||
| { | ||||
| 	dt.good_leaf(0, 10); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.good_leaf(20, 30), range64(10ull, 20ull)); | ||||
| 	assert_no_damage(dt.end()); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, bad_good_bad) | ||||
| { | ||||
| 	dt.bad_node(); | ||||
| 	dt.good_leaf(10, 20); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.end(), range64(20ull)); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, gi_bl_gl) | ||||
| { | ||||
| 	dt.good_internal(0); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.good_leaf(10, 20), range64(0ull, 10ull)); | ||||
| 	assert_no_damage(dt.end()); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, gi_gl_bl_bi) | ||||
| { | ||||
| 	dt.good_internal(0); | ||||
| 	dt.good_leaf(0, 10); | ||||
| 	dt.bad_node(); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.end(), range64(10ull)); | ||||
| } | ||||
|  | ||||
| TEST_F(DamageTrackerTests, gi_bi_gi_bl_gl) | ||||
| { | ||||
| 	dt.good_internal(0); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.good_internal(10), range64(0ull, 10ull)); | ||||
| 	dt.bad_node(); | ||||
| 	assert_damage(dt.good_leaf(15, 20), range64(10ull, 15ull)); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
		Reference in New Issue
	
	Block a user