From d7d293ee4fd15649222143ca3bcaeeb9f43014e9 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 10 Jun 2014 16:38:20 +0100 Subject: [PATCH] thin_delta now works --- thin-provisioning/thin_delta.cc | 153 ++++++++++++++++++++++++++++++-- 1 file changed, 148 insertions(+), 5 deletions(-) diff --git a/thin-provisioning/thin_delta.cc b/thin-provisioning/thin_delta.cc index bbd1ec2..c12c084 100644 --- a/thin-provisioning/thin_delta.cc +++ b/thin-provisioning/thin_delta.cc @@ -6,7 +6,15 @@ #include "version.h" +#include "persistent-data/data-structures/btree_damage_visitor.h" +#include "persistent-data/run.h" +#include "persistent-data/space-maps/core.h" +#include "persistent-data/file_utils.h" +#include "thin-provisioning/superblock.h" +#include "thin-provisioning/mapping_tree.h" + using namespace std; +using namespace thin_provisioning; //---------------------------------------------------------------- @@ -30,9 +38,9 @@ namespace { exit(1); } - unsigned parse_snap(string const &str) { + uint64_t parse_snap(string const &str) { try { - return boost::lexical_cast(str); + return boost::lexical_cast(str); } catch (...) { ostringstream out; @@ -49,9 +57,143 @@ namespace { struct flags { boost::optional dev; - boost::optional snap1; - boost::optional snap2; + boost::optional snap1; + boost::optional snap2; }; + + //-------------------------------- + + block_manager<>::ptr + open_bm(string const &path) { + block_address nr_blocks = get_nr_blocks(path); + block_io<>::mode m = block_io<>::READ_ONLY; + return block_manager<>::ptr(new block_manager<>(path, nr_blocks, 1, m)); + } + + transaction_manager::ptr + open_tm(block_manager<>::ptr bm) { + space_map::ptr sm(new core_map(bm->get_nr_blocks())); + sm->inc(superblock_detail::SUPERBLOCK_LOCATION); + transaction_manager::ptr tm(new transaction_manager(bm, sm)); + return tm; + } + + //-------------------------------- + + class delta_visitor { + public: + delta_visitor(single_mapping_tree const &origin) + : origin_(origin) { + 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_); + } + + private: + void reset_range() { + obegin_ = oend_ = 0; + dbegin_ = dend_ = 0; + } + + void emit(uint64_t oblock, uint64_t dblock) { + if (obegin_ == oend_) { + // We're starting a new range + obegin_ = oblock; + oend_ = obegin_; + + dbegin_ = dblock; + dend_ = dbegin_; + + } else { + if (oblock != oend_ || dblock != dend_) { + // Emit the current range ... + if (oend_ - obegin_ > 1) { + cout << "" << endl; + } else { + cout << "" << endl; + } + + obegin_ = oblock; + oend_ = obegin_; + + dbegin_ = dblock; + dend_ = dbegin_; + } + } + + oend_++; + dend_++; + } + + uint64_t obegin_, oend_; + uint64_t dbegin_, dend_; + + single_mapping_tree const &origin_; + }; + + class damage_visitor { + public: + virtual void visit(btree_path const &path, btree_detail::damage const &d) { + throw std::runtime_error("damage in mapping tree, please run thin_check"); + } + }; + + 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); + damage_visitor damage_v; + btree_visit_values(snap2, delta_v, damage_v); + } + + int delta(application &app, flags const &fs) { + try { + delta_(app, fs); + } catch (exception const &e) { + app.die(e.what()); + return 1; // never get here + } + + return 0; + } } //---------------------------------------------------------------- @@ -70,6 +212,7 @@ int main(int argc, char **argv) { "version", no_argument, NULL, 'V' }, { "snap1", required_argument, NULL, 1 }, { "snap2", required_argument, NULL, 2 }, + { "metadata-snap", optional_argument, NULL, 3 }, }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { @@ -107,7 +250,7 @@ int main(int argc, char **argv) if (!fs.snap2) app.die("--snap2 not specified."); - return 0; + return delta(app, fs); } //----------------------------------------------------------------