[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:
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user