[thin_delta] provide a more complete diff output.
This commit is contained in:
		@@ -80,20 +80,44 @@ namespace {
 | 
			
		||||
 | 
			
		||||
	//--------------------------------
 | 
			
		||||
 | 
			
		||||
	class delta_visitor {
 | 
			
		||||
	struct mapping {
 | 
			
		||||
		mapping()
 | 
			
		||||
			: vbegin_(0),
 | 
			
		||||
			  dbegin_(0),
 | 
			
		||||
			  len_(0) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mapping(uint64_t vbegin, uint64_t dbegin, uint64_t len)
 | 
			
		||||
			: vbegin_(vbegin),
 | 
			
		||||
			  dbegin_(dbegin),
 | 
			
		||||
			  len_(len) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void consume(uint64_t delta) {
 | 
			
		||||
			delta = min<uint64_t>(delta, len_);
 | 
			
		||||
			vbegin_ += delta;
 | 
			
		||||
			dbegin_ += delta;
 | 
			
		||||
			len_ -= delta;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uint64_t vbegin_, dbegin_, len_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	typedef std::deque<mapping> mapping_deque;
 | 
			
		||||
 | 
			
		||||
	// Builds up an in core rep of the mappings for a device.
 | 
			
		||||
	class mapping_recorder {
 | 
			
		||||
	public:
 | 
			
		||||
		delta_visitor(single_mapping_tree const &origin)
 | 
			
		||||
		: origin_(origin) {
 | 
			
		||||
		mapping_recorder() {
 | 
			
		||||
			reset_range();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// This is slow, but easy to write.  Faster would be to
 | 
			
		||||
		// iterate both trees simultaneously.
 | 
			
		||||
		void visit(btree_path const &path, mapping_tree_detail::block_time const &bt) {
 | 
			
		||||
			single_mapping_tree::key k = {path[0]};
 | 
			
		||||
			boost::optional<mapping_tree_detail::block_time> origin_bt = origin_.lookup(k);
 | 
			
		||||
			if (!origin_bt || origin_bt->block_ != bt.block_)
 | 
			
		||||
				emit(path[0], bt.block_);
 | 
			
		||||
			record(path[0], bt.block_);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mapping_deque const &get_mappings() const {
 | 
			
		||||
			return mappings_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
@@ -102,7 +126,7 @@ namespace {
 | 
			
		||||
			dbegin_ = dend_ = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void emit(uint64_t oblock, uint64_t dblock) {
 | 
			
		||||
		void record(uint64_t oblock, uint64_t dblock) {
 | 
			
		||||
			if (obegin_ == oend_) {
 | 
			
		||||
				// We're starting a new range
 | 
			
		||||
				obegin_ = oblock;
 | 
			
		||||
@@ -114,14 +138,7 @@ namespace {
 | 
			
		||||
			} else {
 | 
			
		||||
				if (oblock != oend_ || dblock != dend_) {
 | 
			
		||||
					// Emit the current range ...
 | 
			
		||||
					if (oend_ - obegin_ > 1) {
 | 
			
		||||
						cout << "<range_mapping origin_begin=\"" << obegin_ << "\""
 | 
			
		||||
						     << " data_begin=\"" << dbegin_ << "\""
 | 
			
		||||
						     << " length=\"" << oend_ - obegin_ << "\"/>" << '\n';
 | 
			
		||||
					} else {
 | 
			
		||||
						cout << "<single_mapping origin_block=\"" << obegin_ << "\""
 | 
			
		||||
						     << " data_block=\"" << dbegin_ << "\"/>" << '\n';
 | 
			
		||||
					}
 | 
			
		||||
					push_mapping(obegin_, dbegin_, oend_ - obegin_);
 | 
			
		||||
 | 
			
		||||
					obegin_ = oblock;
 | 
			
		||||
					oend_ = obegin_;
 | 
			
		||||
@@ -135,12 +152,18 @@ namespace {
 | 
			
		||||
			dend_++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void push_mapping(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
 | 
			
		||||
			mappings_.push_back(mapping(vbegin, dbegin, len));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uint64_t obegin_, oend_;
 | 
			
		||||
		uint64_t dbegin_, dend_;
 | 
			
		||||
 | 
			
		||||
		single_mapping_tree const &origin_;
 | 
			
		||||
		mapping_deque mappings_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	//--------------------------------
 | 
			
		||||
 | 
			
		||||
	class damage_visitor {
 | 
			
		||||
	public:
 | 
			
		||||
		virtual void visit(btree_path const &path, btree_detail::damage const &d) {
 | 
			
		||||
@@ -148,40 +171,202 @@ namespace {
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class diff_emitter {
 | 
			
		||||
	public:
 | 
			
		||||
		diff_emitter(ostream &out)
 | 
			
		||||
		: out_(out) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void left_only(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
 | 
			
		||||
			begin_block(LEFT_ONLY);
 | 
			
		||||
			out_ << "  <rang begin=\"" << vbegin << "\""
 | 
			
		||||
			     << " data_begin=\"" << dbegin << "\""
 | 
			
		||||
			     << " length=\"" << len << "\"/>\n";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void right_only(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
 | 
			
		||||
			begin_block(RIGHT_ONLY);
 | 
			
		||||
			out_ << "  <range begin=\"" << vbegin << "\""
 | 
			
		||||
			     << " data_begin=\"" << dbegin << "\""
 | 
			
		||||
			     << " length=\"" << len << "\"/>\n";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void blocks_differ(uint64_t vbegin, uint64_t left_dbegin, uint64_t right_dbegin, uint64_t len) {
 | 
			
		||||
			begin_block(DIFFER);
 | 
			
		||||
			out_ << "  <range begin=\"" << vbegin << "\""
 | 
			
		||||
			     << " left_data_begin=\"" << left_dbegin << "\""
 | 
			
		||||
			     << " right_data_begin=\"" << right_dbegin << "\""
 | 
			
		||||
			     << " length=\"" << len << "\"/>\n";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void blocks_same(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
 | 
			
		||||
			begin_block(SAME);
 | 
			
		||||
			out_ << "  <range begin=\"" << vbegin << "\""
 | 
			
		||||
			     << " data_begin=\"" << dbegin << "\""
 | 
			
		||||
			     << " length=\"" << len << "\"/>\n";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void complete() {
 | 
			
		||||
			if (current_type_)
 | 
			
		||||
				close(*current_type_);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		enum block_type {
 | 
			
		||||
			LEFT_ONLY,
 | 
			
		||||
			RIGHT_ONLY,
 | 
			
		||||
			DIFFER,
 | 
			
		||||
			SAME
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		void begin_block(block_type t) {
 | 
			
		||||
			if (!current_type_) {
 | 
			
		||||
				current_type_ = t;
 | 
			
		||||
				open(t);
 | 
			
		||||
 | 
			
		||||
			} else if (*current_type_ != t) {
 | 
			
		||||
				close(*current_type_);
 | 
			
		||||
				current_type_ = t;
 | 
			
		||||
				open(t);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void open(block_type t) {
 | 
			
		||||
			switch (t) {
 | 
			
		||||
			case LEFT_ONLY:
 | 
			
		||||
				out_ << "<left_only>\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case RIGHT_ONLY:
 | 
			
		||||
				out_ << "<right_only>\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case DIFFER:
 | 
			
		||||
				out_ << "<different>\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SAME:
 | 
			
		||||
				out_ << "<same>\n";
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void close(block_type t) {
 | 
			
		||||
			switch (t) {
 | 
			
		||||
			case LEFT_ONLY:
 | 
			
		||||
				out_ << "</left_only>\n\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case RIGHT_ONLY:
 | 
			
		||||
				out_ << "</right_only>\n\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case DIFFER:
 | 
			
		||||
				out_ << "</different>\n\n";
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SAME:
 | 
			
		||||
				out_ << "</same>\n\n";
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		boost::optional<block_type> current_type_;
 | 
			
		||||
		ostream &out_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	//----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	void dump_diff(mapping_deque const &left,
 | 
			
		||||
		       mapping_deque const &right) {
 | 
			
		||||
 | 
			
		||||
		diff_emitter e(cout);
 | 
			
		||||
 | 
			
		||||
		// We iterate through both sets of mappings in parallel
 | 
			
		||||
		// noting any differences.
 | 
			
		||||
		mapping_deque::const_iterator left_it = left.begin();
 | 
			
		||||
		mapping_deque::const_iterator right_it = right.begin();
 | 
			
		||||
 | 
			
		||||
		mapping left_mapping;
 | 
			
		||||
		mapping right_mapping;
 | 
			
		||||
 | 
			
		||||
		while (left_it != left.end() && right_it != right.end()) {
 | 
			
		||||
			if (!left_mapping.len_ && left_it != left.end())
 | 
			
		||||
				left_mapping = *left_it++;
 | 
			
		||||
 | 
			
		||||
			if (!right_mapping.len_ && right_it != right.end())
 | 
			
		||||
				right_mapping = *right_it++;
 | 
			
		||||
 | 
			
		||||
			while (left_mapping.len_ && right_mapping.len_) {
 | 
			
		||||
				if (left_mapping.vbegin_ < right_mapping.vbegin_) {
 | 
			
		||||
					uint64_t delta = min<uint64_t>(left_mapping.len_, right_mapping.vbegin_ - left_mapping.vbegin_);
 | 
			
		||||
					e.left_only(left_mapping.vbegin_, left_mapping.dbegin_, delta);
 | 
			
		||||
					left_mapping.consume(delta);
 | 
			
		||||
 | 
			
		||||
				} else if (left_mapping.vbegin_ > left_mapping.vbegin_) {
 | 
			
		||||
					uint64_t delta = min<uint64_t>(right_mapping.len_, left_mapping.vbegin_ - right_mapping.vbegin_);
 | 
			
		||||
					e.right_only(right_mapping.vbegin_, right_mapping.dbegin_, delta);
 | 
			
		||||
					right_mapping.consume(delta);
 | 
			
		||||
 | 
			
		||||
				} else if (left_mapping.dbegin_ != right_mapping.dbegin_) {
 | 
			
		||||
					uint64_t delta = min<uint64_t>(left_mapping.len_, right_mapping.len_);
 | 
			
		||||
					e.blocks_differ(left_mapping.vbegin_, left_mapping.dbegin_, right_mapping.dbegin_, delta);
 | 
			
		||||
					left_mapping.consume(delta);
 | 
			
		||||
					right_mapping.consume(delta);
 | 
			
		||||
 | 
			
		||||
				} else {
 | 
			
		||||
					uint64_t delta = min<uint64_t>(left_mapping.len_, right_mapping.len_);
 | 
			
		||||
					e.blocks_same(left_mapping.vbegin_, left_mapping.dbegin_, delta);
 | 
			
		||||
					left_mapping.consume(delta);
 | 
			
		||||
					right_mapping.consume(delta);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		e.complete();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void delta_(application &app, flags const &fs) {
 | 
			
		||||
		block_manager<>::ptr bm = open_bm(*fs.dev);
 | 
			
		||||
		transaction_manager::ptr tm = open_tm(bm);
 | 
			
		||||
 | 
			
		||||
		superblock_detail::superblock sb = read_superblock(bm);
 | 
			
		||||
 | 
			
		||||
		dev_tree dtree(tm, sb.data_mapping_root_,
 | 
			
		||||
			       mapping_tree_detail::mtree_traits::ref_counter(tm));
 | 
			
		||||
 | 
			
		||||
		dev_tree::key k = {*fs.snap1};
 | 
			
		||||
		boost::optional<uint64_t> snap1_root = dtree.lookup(k);
 | 
			
		||||
 | 
			
		||||
		if (!snap1_root) {
 | 
			
		||||
			ostringstream out;
 | 
			
		||||
			out << "Unable to find mapping tree for snap1 (" << *fs.snap1 << ")";
 | 
			
		||||
			app.die(out.str());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		single_mapping_tree snap1(tm, *snap1_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
 | 
			
		||||
 | 
			
		||||
		k[0] = *fs.snap2;
 | 
			
		||||
		boost::optional<uint64_t> snap2_root = dtree.lookup(k);
 | 
			
		||||
 | 
			
		||||
		if (!snap2_root) {
 | 
			
		||||
			ostringstream out;
 | 
			
		||||
			out << "Unable to find mapping tree for snap2 (" << *fs.snap2 << ")";
 | 
			
		||||
			app.die(out.str());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		single_mapping_tree snap2(tm, *snap2_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
 | 
			
		||||
 | 
			
		||||
		delta_visitor delta_v(snap1);
 | 
			
		||||
		mapping_recorder mr1;
 | 
			
		||||
		mapping_recorder mr2;
 | 
			
		||||
		damage_visitor damage_v;
 | 
			
		||||
		btree_visit_values(snap2, delta_v, damage_v);
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			block_manager<>::ptr bm = open_bm(*fs.dev);
 | 
			
		||||
			transaction_manager::ptr tm = open_tm(bm);
 | 
			
		||||
 | 
			
		||||
			superblock_detail::superblock sb = read_superblock(bm);
 | 
			
		||||
 | 
			
		||||
			dev_tree dtree(tm, sb.data_mapping_root_,
 | 
			
		||||
				       mapping_tree_detail::mtree_traits::ref_counter(tm));
 | 
			
		||||
 | 
			
		||||
			dev_tree::key k = {*fs.snap1};
 | 
			
		||||
			boost::optional<uint64_t> snap1_root = dtree.lookup(k);
 | 
			
		||||
 | 
			
		||||
			if (!snap1_root) {
 | 
			
		||||
				ostringstream out;
 | 
			
		||||
				out << "Unable to find mapping tree for snap1 (" << *fs.snap1 << ")";
 | 
			
		||||
				app.die(out.str());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			single_mapping_tree snap1(tm, *snap1_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
 | 
			
		||||
 | 
			
		||||
			k[0] = *fs.snap2;
 | 
			
		||||
			boost::optional<uint64_t> snap2_root = dtree.lookup(k);
 | 
			
		||||
 | 
			
		||||
			if (!snap2_root) {
 | 
			
		||||
				ostringstream out;
 | 
			
		||||
				out << "Unable to find mapping tree for snap2 (" << *fs.snap2 << ")";
 | 
			
		||||
				app.die(out.str());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			single_mapping_tree snap2(tm, *snap2_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
 | 
			
		||||
			btree_visit_values(snap1, mr1, damage_v);
 | 
			
		||||
			btree_visit_values(snap2, mr2, damage_v);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dump_diff(mr1.get_mappings(), mr2.get_mappings());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int delta(application &app, flags const &fs) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user