From 0e62a1c4dedcf5effc1aaa3399ce3c291ea9d8a8 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 17 Jun 2014 12:39:13 +0100 Subject: [PATCH] [thin_delta] provide a more complete diff output. --- thin-provisioning/thin_delta.cc | 287 ++++++++++++++++++++++++++------ 1 file changed, 236 insertions(+), 51 deletions(-) diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index ed32763..d0d5fee 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -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(delta, len_); + vbegin_ += delta; + dbegin_ += delta; + len_ -= delta; + } + + uint64_t vbegin_, dbegin_, len_; + }; + + typedef std::deque 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 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 << "" << '\n'; - } else { - cout << "" << '\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_ << " \n"; + } + + void right_only(uint64_t vbegin, uint64_t dbegin, uint64_t len) { + begin_block(RIGHT_ONLY); + out_ << " \n"; + } + + void blocks_differ(uint64_t vbegin, uint64_t left_dbegin, uint64_t right_dbegin, uint64_t len) { + begin_block(DIFFER); + out_ << " \n"; + } + + void blocks_same(uint64_t vbegin, uint64_t dbegin, uint64_t len) { + begin_block(SAME); + out_ << " \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_ << "\n"; + break; + + case RIGHT_ONLY: + out_ << "\n"; + break; + + case DIFFER: + out_ << "\n"; + break; + + case SAME: + out_ << "\n"; + break; + } + } + + void close(block_type t) { + switch (t) { + case LEFT_ONLY: + out_ << "\n\n"; + break; + + case RIGHT_ONLY: + out_ << "\n\n"; + break; + + case DIFFER: + out_ << "\n\n"; + break; + + case SAME: + out_ << "\n\n"; + break; + } + + } + + boost::optional 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(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(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(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(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 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 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 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 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) {