[thin] Make the metadata class resposible for locating metadata snapshots

This commit is contained in:
Joe Thornber 2015-12-15 10:08:07 +00:00
parent 30a3bf67d1
commit a709b9718b
6 changed files with 104 additions and 77 deletions

View File

@ -112,33 +112,32 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot,
}
}
metadata::metadata(block_manager<>::ptr bm, block_address metadata_snap)
metadata::metadata(block_manager<>::ptr bm)
{
tm_ = open_tm(bm);
sb_ = read_superblock(tm_->get_bm(), SUPERBLOCK_LOCATION);
open_space_maps();
open_btrees();
}
metadata::metadata(block_manager<>::ptr bm,
boost::optional<block_address> metadata_snap)
{
tm_ = open_tm(bm);
if (metadata_snap) {
if (metadata_snap != sb_.metadata_snap_)
superblock_detail::superblock actual_sb = read_superblock(bm, SUPERBLOCK_LOCATION);
if (!actual_sb.metadata_snap_)
throw runtime_error("no current metadata snap");
if (metadata_snap && *metadata_snap != actual_sb.metadata_snap_)
throw runtime_error("metadata snapshot does not match that in superblock");
sb_ = read_superblock(tm_->get_bm(), metadata_snap);
sb_ = read_superblock(bm, actual_sb.metadata_snap_);
// metadata snaps don't record the space maps
} else {
sb_ = read_superblock(tm_->get_bm(), SUPERBLOCK_LOCATION);
metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_);
tm_->set_sm(metadata_sm_);
data_sm_ = open_disk_sm(*tm_, static_cast<void *>(&sb_.data_space_map_root_));
}
details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_,
device_tree_detail::device_details_traits::ref_counter()));
mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_,
mapping_tree_detail::mtree_ref_counter(tm_)));
mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_,
mapping_tree_detail::block_time_ref_counter(data_sm_)));
// metadata snaps don't record the space maps
open_btrees();
}
void
@ -158,4 +157,22 @@ metadata::commit()
superblock_traits::pack(sb_, *disk);
}
void metadata::open_space_maps()
{
metadata_sm_ = open_metadata_sm(*tm_, &sb_.metadata_space_map_root_);
tm_->set_sm(metadata_sm_);
data_sm_ = open_disk_sm(*tm_, static_cast<void *>(&sb_.data_space_map_root_));
}
void metadata::open_btrees()
{
details_ = device_tree::ptr(new device_tree(*tm_, sb_.device_details_root_,
device_tree_detail::device_details_traits::ref_counter()));
mappings_top_level_ = dev_tree::ptr(new dev_tree(*tm_, sb_.data_mapping_root_,
mapping_tree_detail::mtree_ref_counter(tm_)));
mappings_ = mapping_tree::ptr(new mapping_tree(*tm_, sb_.data_mapping_root_,
mapping_tree_detail::block_time_ref_counter(data_sm_)));
}
//----------------------------------------------------------------

View File

@ -62,7 +62,21 @@ namespace thin_provisioning {
metadata(block_manager<>::ptr bm, open_type ot,
sector_t data_block_size = 128,
block_address nr_data_blocks = 0); // Only used if CREATE
metadata(block_manager<>::ptr bm, block_address metadata_snap = 0);
// Ideally we'd like the metadata snap argument to be a
// boolean, and we'd read the snap location from the
// superblock. But the command line interface for some of
// the tools allows the user to pass in a block, which
// they've retrieved from the pool status. So we have to
// support 3 cases:
//
// i) Read superblock
// ii) Read the metadata snap as given in the superblock
// iii) Read the metadata snap given on command line, checking it matches superblock.
//
metadata(block_manager<>::ptr bm); // (i)
metadata(block_manager<>::ptr,
boost::optional<block_address> metadata_snap); // (ii) and (iii)
void commit();
@ -75,6 +89,10 @@ namespace thin_provisioning {
device_tree::ptr details_;
dev_tree::ptr mappings_top_level_;
mapping_tree::ptr mappings_;
private:
void open_space_maps();
void open_btrees();
};
}

View File

@ -181,18 +181,6 @@ namespace thin_provisioning {
visitor.visit(superblock_corruption(e.what()));
}
}
block_address find_metadata_snap(string const &path)
{
superblock_detail::superblock sb =
read_superblock(open_bm(path, block_manager<>::READ_ONLY, false), 0);
uint64_t ms = sb.metadata_snap_;
if (!ms)
throw runtime_error("no metadata snapshot found!\n");
return ms;
}
}
//----------------------------------------------------------------

View File

@ -137,9 +137,6 @@ namespace thin_provisioning {
void check_superblock(persistent_data::block_manager<>::ptr bm,
superblock_detail::damage_visitor &visitor);
persistent_data::block_address find_metadata_snap(string const &path);
}
//----------------------------------------------------------------

View File

@ -14,6 +14,7 @@
#include "persistent-data/file_utils.h"
#include "thin-provisioning/superblock.h"
#include "thin-provisioning/mapping_tree.h"
#include "thin-provisioning/metadata.h"
#include "thin-provisioning/commands.h"
using namespace std;
@ -65,15 +66,16 @@ namespace local {
struct flags {
flags()
: verbose(false),
find_metadata_snap(false) {
use_metadata_snap(false) {
}
bool verbose;
bool use_metadata_snap;
boost::optional<string> dev;
boost::optional<uint64_t> metadata_snap;
boost::optional<uint64_t> snap1;
boost::optional<uint64_t> snap2;
bool verbose;
bool find_metadata_snap;
};
//--------------------------------
@ -528,17 +530,12 @@ namespace local {
checked_space_map::ptr data_sm;
{
block_manager<>::ptr bm = open_bm(*fs.dev, block_manager<>::READ_ONLY, !fs.metadata_snap);
transaction_manager::ptr tm = open_tm(bm);
sb = fs.metadata_snap ? read_superblock(bm, *fs.metadata_snap) : read_superblock(bm);
data_sm = open_disk_sm(*tm, static_cast<void *>(&sb.data_space_map_root_));
dev_tree dtree(*tm, sb.data_mapping_root_,
mapping_tree_detail::mtree_traits::ref_counter(tm));
block_manager<>::ptr bm = open_bm(*fs.dev, block_manager<>::READ_ONLY, !fs.use_metadata_snap);
metadata::ptr md(fs.use_metadata_snap ? new metadata(bm, fs.metadata_snap) : new metadata(bm));
sb = md->sb_;
dev_tree::key k = {*fs.snap1};
boost::optional<uint64_t> snap1_root = dtree.lookup(k);
boost::optional<uint64_t> snap1_root = md->mappings_top_level_->lookup(k);
if (!snap1_root) {
ostringstream out;
@ -546,10 +543,11 @@ namespace local {
app.die(out.str());
}
single_mapping_tree snap1(*tm, *snap1_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
single_mapping_tree snap1(*md->tm_, *snap1_root,
mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm()));
k[0] = *fs.snap2;
boost::optional<uint64_t> snap2_root = dtree.lookup(k);
boost::optional<uint64_t> snap2_root = md->mappings_top_level_->lookup(k);
if (!snap2_root) {
ostringstream out;
@ -557,7 +555,8 @@ namespace local {
app.die(out.str());
}
single_mapping_tree snap2(*tm, *snap2_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
single_mapping_tree snap2(*md->tm_, *snap2_root,
mapping_tree_detail::block_traits::ref_counter(md->tm_->get_sm()));
btree_visit_values(snap1, mr1, damage_v);
mr1.complete();
@ -642,10 +641,9 @@ int thin_delta_main(int argc, char **argv)
break;
case 'm':
fs.use_metadata_snap = true;
if (optarg)
fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block");
else
fs.find_metadata_snap = true;
break;
case 4:
@ -669,9 +667,6 @@ int thin_delta_main(int argc, char **argv)
if (!fs.snap2)
app.die("--snap2 not specified.");
if (fs.find_metadata_snap)
fs.metadata_snap = find_metadata_snap(*fs.dev);
return delta(app, fs);
}

View File

@ -29,27 +29,42 @@
#include "thin-provisioning/commands.h"
#include "persistent-data/file_utils.h"
using namespace boost;
using namespace persistent_data;
using namespace std;
using namespace thin_provisioning;
struct flags {
bool find_metadata_snap;
bool repair;
};
namespace {
int dump_(string const &path, ostream &out, string const &format, struct flags &flags,
block_address metadata_snap) {
// FIXME: put the path into the flags
struct flags {
flags()
: repair(false),
use_metadata_snap(false) {
}
bool repair;
bool use_metadata_snap;
optional<block_address> snap_location;
};
metadata::ptr open_metadata(string const &path, struct flags &flags) {
block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY, !flags.use_metadata_snap);
metadata::ptr md(flags.use_metadata_snap ? new metadata(bm, flags.snap_location) : new metadata(bm));
return md;
}
int dump_(string const &path, ostream &out, string const &format, struct flags &flags) {
try {
block_manager<>::ptr bm = open_bm(path, block_manager<>::READ_ONLY, !metadata_snap);
metadata::ptr md(new metadata(bm, metadata_snap));
metadata::ptr md = open_metadata(path, flags);
emitter::ptr e;
if (format == "xml")
e = create_xml_emitter(out);
else if (format == "human_readable")
e = create_human_readable_emitter(out);
else {
cerr << "unknown format '" << format << "'" << endl;
exit(1);
@ -65,13 +80,12 @@ namespace {
return 0;
}
int dump(string const &path, char const *output, string const &format, struct flags &flags,
block_address metadata_snap = 0) {
int dump(string const &path, char const *output, string const &format, struct flags &flags) {
if (output) {
ofstream out(output);
return dump_(path, out, format, flags, metadata_snap);
return dump_(path, out, format, flags);
} else
return dump_(path, cout, format, flags, metadata_snap);
return dump_(path, cout, format, flags);
}
void usage(ostream &out, string const &cmd) {
@ -95,7 +109,6 @@ int thin_dump_main(int argc, char **argv)
string format = "xml";
block_address metadata_snap = 0;
struct flags flags;
flags.find_metadata_snap = flags.repair = false;
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h'},
@ -122,16 +135,18 @@ int thin_dump_main(int argc, char **argv)
break;
case 'm':
flags.use_metadata_snap = true;
if (optarg) {
// FIXME: deprecate this option
metadata_snap = strtoull(optarg, &end_ptr, 10);
if (end_ptr == optarg) {
cerr << "couldn't parse <metadata_snap>" << endl;
usage(cerr, basename(argv[0]));
return 1;
}
} else
flags.find_metadata_snap = true;
flags.snap_location = metadata_snap;
}
break;
case 'o':
@ -154,10 +169,7 @@ int thin_dump_main(int argc, char **argv)
return 1;
}
if (flags.find_metadata_snap)
metadata_snap = find_metadata_snap(argv[optind]);
return dump(argv[optind], output, format, flags, metadata_snap);
return dump(argv[optind], output, format, flags);
}
base::command thin_provisioning::thin_dump_cmd("thin_dump", thin_dump_main);