[btree_damage_tracker] track the paths
This commit is contained in:
		| @@ -82,6 +82,29 @@ namespace persistent_data { | ||||
| 			block_address damage_begin_; | ||||
| 		}; | ||||
|  | ||||
| 		// As we walk a btree we need to know if we've moved into a | ||||
| 		// different sub tree (by looking at the btree_path). | ||||
| 		class path_tracker { | ||||
| 		public: | ||||
| 			// returns the old path if the tree has changed. | ||||
| 			boost::optional<btree_path> next_path(btree_path const &p) { | ||||
| 				if (p != path_) { | ||||
| 					btree_path tmp(path_); | ||||
| 					path_ = p; | ||||
| 					return boost::optional<btree_path>(tmp); | ||||
| 				} | ||||
|  | ||||
| 				return boost::optional<btree_path>(); | ||||
| 			} | ||||
|  | ||||
| 			btree_path const ¤t_path() const { | ||||
| 				return path_; | ||||
| 			} | ||||
|  | ||||
| 		private: | ||||
| 			btree_path path_; | ||||
| 		}; | ||||
|  | ||||
| 		//---------------------------------------------------------------- | ||||
|  | ||||
| 		// This class implements consistency checking for the btrees.  It | ||||
| @@ -125,16 +148,23 @@ namespace persistent_data { | ||||
|  | ||||
| 			bool visit_internal(node_location const &loc, | ||||
| 					    btree_detail::node_ref<uint64_traits> const &n) { | ||||
| 				update_path(loc.path); | ||||
|  | ||||
| 				return check_internal(loc, n); | ||||
| 			} | ||||
|  | ||||
| 			bool visit_internal_leaf(node_location const &loc, | ||||
| 						 btree_detail::node_ref<uint64_traits> const &n) { | ||||
| 				update_path(loc.path); | ||||
|  | ||||
| 				return check_leaf(loc, n); | ||||
| 			} | ||||
|  | ||||
| 			bool visit_leaf(node_location const &loc, | ||||
| 					btree_detail::node_ref<ValueTraits> const &n) { | ||||
| 				update_path(loc.path); | ||||
|  | ||||
|  | ||||
| 				bool r = check_leaf(loc, n); | ||||
|  | ||||
| 				// If anything goes wrong with the checks, we skip | ||||
| @@ -359,28 +389,27 @@ namespace persistent_data { | ||||
| 			void good_internal(block_address b) { | ||||
| 				maybe_range64 mr = dt_.good_internal(b); | ||||
| 				if (mr) | ||||
| 					issue_damage(*mr); | ||||
| 					issue_damage(path_tracker_.current_path(), *mr); | ||||
| 			} | ||||
|  | ||||
| 			void good_leaf(block_address b, block_address e) { | ||||
| 				maybe_range64 mr = dt_.good_leaf(b, e); | ||||
|  | ||||
| 				if (mr) | ||||
| 					issue_damage(*mr); | ||||
| 					issue_damage(path_tracker_.current_path(), *mr); | ||||
| 			} | ||||
|  | ||||
| 			// FIXME: duplicate code | ||||
| 			void end_walk() { | ||||
| 				maybe_range64 mr = dt_.end(); | ||||
| 				if (mr) | ||||
| 					issue_damage(*mr); | ||||
| 					issue_damage(path_tracker_.current_path(), *mr); | ||||
| 			} | ||||
|  | ||||
| 			void issue_damage(range64 const &r) { | ||||
| 				// FIXME: we don't really know what level | ||||
| 				// the damage is coming from | ||||
| 			void issue_damage(btree_path const &path, range64 const &r) { | ||||
| 				damage d(r, build_damage_desc()); | ||||
| 				clear_damage_desc(); | ||||
| 				damage_visitor_.visit(btree_path(), d); | ||||
| 				damage_visitor_.visit(path, d); | ||||
| 			} | ||||
|  | ||||
| 			std::string build_damage_desc() const { | ||||
| @@ -399,6 +428,22 @@ namespace persistent_data { | ||||
|  | ||||
| 			//-------------------------------- | ||||
|  | ||||
| 			void update_path(btree_path const &path) { | ||||
| 				boost::optional<btree_path> old_path = path_tracker_.next_path(path); | ||||
| 				if (old_path) { | ||||
| 					// we need to emit any errors that | ||||
| 					// were accrued against the old | ||||
| 					// path. | ||||
|  | ||||
| 					// FIXME: duplicate code with end_walk() | ||||
| 					maybe_range64 mr = dt_.end(); | ||||
| 					if (mr) | ||||
| 						issue_damage(*old_path, *mr); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			//-------------------------------- | ||||
|  | ||||
| 			block_counter &counter_; | ||||
| 			bool avoid_repeated_visits_; | ||||
|  | ||||
| @@ -408,6 +453,7 @@ namespace persistent_data { | ||||
| 			std::set<block_address> seen_; | ||||
| 			boost::optional<uint64_t> last_leaf_key_[Levels]; | ||||
|  | ||||
| 			path_tracker path_tracker_; | ||||
| 			damage_tracker dt_; | ||||
| 			std::list<std::string> damage_reasons_; | ||||
| 		}; | ||||
|   | ||||
| @@ -420,6 +420,26 @@ namespace { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void expect_values_except(unsigned nr_sub_trees, unsigned nr_values, | ||||
| 					  btree_path const &path, range<uint64_t> keys) { | ||||
| 			for (unsigned i = 0; i < nr_sub_trees; i++) | ||||
| 				expect_sub_tree_values_except(i, nr_values, path, keys); | ||||
| 		} | ||||
|  | ||||
| 		void expect_sub_tree_values_except(unsigned sub_tree, unsigned nr_values, | ||||
| 						   btree_path const &path, range<uint64_t> keys) { | ||||
| 			for (unsigned i = 0; i < nr_values; i++) { | ||||
| 				uint64_t key[2] = {sub_tree, i}; | ||||
|  | ||||
| 				if (sub_tree == path[0] && keys.contains(i)) | ||||
| 					continue; | ||||
|  | ||||
| 				btree_path p2; | ||||
| 				p2.push_back(sub_tree); | ||||
| 				EXPECT_CALL(value_visitor_, visit(Eq(p2), Eq(key_to_value(key)))); | ||||
|  			} | ||||
|  		} | ||||
|  | ||||
| 		void expect_damage(btree_path path, range<uint64_t> keys) { | ||||
| 			EXPECT_CALL(damage_visitor_, visit(Eq(path), DamagedKeys(keys))).Times(1); | ||||
| 		} | ||||
| @@ -599,4 +619,23 @@ TEST_F(BTreeDamageVisitor2Tests, populated_tree_with_no_damage) | ||||
| 	run(); | ||||
| } | ||||
|  | ||||
| TEST_F(BTreeDamageVisitor2Tests, damaged_leaf) | ||||
| { | ||||
| 	insert_values(10, 1000); | ||||
| 	tree_complete(); | ||||
|  | ||||
| 	auto leaf1 = [] (node_info const &n) { | ||||
| 		return (n.leaf && n.path.size() == 1 && n.path[0] == 1); | ||||
| 	}; | ||||
|  | ||||
| 	node_info n = layout_->random_node(leaf1); | ||||
| 	cerr << "node: " << n << endl; | ||||
| 	trash_block(n.b); | ||||
|  | ||||
| 	expect_damage(n.path, n.keys); | ||||
| 	expect_values_except(10, 1000, n.path, n.keys); | ||||
|  | ||||
| 	run(); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user