[thin_delta] provide a more complete diff output.
This commit is contained in:
parent
f80c2dc77f
commit
0e62a1c4de
@ -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:
|
public:
|
||||||
delta_visitor(single_mapping_tree const &origin)
|
mapping_recorder() {
|
||||||
: origin_(origin) {
|
|
||||||
reset_range();
|
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) {
|
void visit(btree_path const &path, mapping_tree_detail::block_time const &bt) {
|
||||||
single_mapping_tree::key k = {path[0]};
|
record(path[0], bt.block_);
|
||||||
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_);
|
mapping_deque const &get_mappings() const {
|
||||||
|
return mappings_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -102,7 +126,7 @@ namespace {
|
|||||||
dbegin_ = dend_ = 0;
|
dbegin_ = dend_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit(uint64_t oblock, uint64_t dblock) {
|
void record(uint64_t oblock, uint64_t dblock) {
|
||||||
if (obegin_ == oend_) {
|
if (obegin_ == oend_) {
|
||||||
// We're starting a new range
|
// We're starting a new range
|
||||||
obegin_ = oblock;
|
obegin_ = oblock;
|
||||||
@ -114,14 +138,7 @@ namespace {
|
|||||||
} else {
|
} else {
|
||||||
if (oblock != oend_ || dblock != dend_) {
|
if (oblock != oend_ || dblock != dend_) {
|
||||||
// Emit the current range ...
|
// Emit the current range ...
|
||||||
if (oend_ - obegin_ > 1) {
|
push_mapping(obegin_, dbegin_, oend_ - obegin_);
|
||||||
cout << "<range_mapping origin_begin=\"" << obegin_ << "\""
|
|
||||||
<< " data_begin=\"" << dbegin_ << "\""
|
|
||||||
<< " length=\"" << oend_ - obegin_ << "\"/>" << '\n';
|
|
||||||
} else {
|
|
||||||
cout << "<single_mapping origin_block=\"" << obegin_ << "\""
|
|
||||||
<< " data_block=\"" << dbegin_ << "\"/>" << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
obegin_ = oblock;
|
obegin_ = oblock;
|
||||||
oend_ = obegin_;
|
oend_ = obegin_;
|
||||||
@ -135,12 +152,18 @@ namespace {
|
|||||||
dend_++;
|
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 obegin_, oend_;
|
||||||
uint64_t dbegin_, dend_;
|
uint64_t dbegin_, dend_;
|
||||||
|
|
||||||
single_mapping_tree const &origin_;
|
mapping_deque mappings_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
class damage_visitor {
|
class damage_visitor {
|
||||||
public:
|
public:
|
||||||
virtual void visit(btree_path const &path, btree_detail::damage const &d) {
|
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) {
|
void delta_(application &app, flags const &fs) {
|
||||||
block_manager<>::ptr bm = open_bm(*fs.dev);
|
mapping_recorder mr1;
|
||||||
transaction_manager::ptr tm = open_tm(bm);
|
mapping_recorder mr2;
|
||||||
|
|
||||||
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);
|
|
||||||
damage_visitor damage_v;
|
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) {
|
int delta(application &app, flags const &fs) {
|
||||||
|
Loading…
Reference in New Issue
Block a user