thin dump now does something useful

This commit is contained in:
Joe Thornber 2011-10-10 14:10:30 +01:00
parent 16539b59ff
commit d255180e37
12 changed files with 342 additions and 17 deletions

View File

@ -7,7 +7,9 @@ SOURCE=\
endian_utils.cc \ endian_utils.cc \
error_set.cc \ error_set.cc \
hex_dump.cc \ hex_dump.cc \
human_readable_format.cc \
metadata.cc \ metadata.cc \
metadata_dump.cc \
metadata_disk_structures.cc \ metadata_disk_structures.cc \
space_map_disk.cc \ space_map_disk.cc \
transaction_manager.cc transaction_manager.cc

View File

@ -57,7 +57,8 @@ block_manager<BlockSize>::block_manager(std::string const &path, block_address n
superblock_count_(0), superblock_count_(0),
ordinary_count_(0) ordinary_count_(0)
{ {
fd_ = ::open(path.c_str(), O_RDWR | O_CREAT, 0666); //fd_ = ::open(path.c_str(), O_RDWR | O_CREAT, 0666);
fd_ = ::open(path.c_str(), O_RDONLY, 0666);
if (fd_ < 0) if (fd_ < 0)
throw std::runtime_error("couldn't open file"); throw std::runtime_error("couldn't open file");
} }

10
btree.h
View File

@ -332,12 +332,14 @@ namespace persistent_data {
// The bool return values indicate whether the walk // The bool return values indicate whether the walk
// should be continued into sub trees of the node (true == continue). // should be continued into sub trees of the node (true == continue).
virtual bool visit_internal(unsigned level, boost::optional<uint64_t> key, virtual bool visit_internal(unsigned level, bool sub_root, boost::optional<uint64_t> key,
internal_node const &n) = 0; internal_node const &n) = 0;
virtual bool visit_internal_leaf(unsigned level, boost::optional<uint64_t> key, virtual bool visit_internal_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> key,
internal_node const &n) = 0; internal_node const &n) = 0;
virtual bool visit_leaf(unsigned level, boost::optional<uint64_t> key, virtual bool visit_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> key,
leaf_node const &n) = 0; leaf_node const &n) = 0;
virtual void visit_complete() {}
}; };
// Walks the tree in depth first order // Walks the tree in depth first order
@ -366,7 +368,7 @@ namespace persistent_data {
int *index); int *index);
void walk_tree(typename visitor::ptr visitor, void walk_tree(typename visitor::ptr visitor,
unsigned level, boost::optional<uint64_t> key, unsigned level, bool root, boost::optional<uint64_t> key,
block_address b) const; block_address b) const;
typename persistent_data::transaction_manager::ptr tm_; typename persistent_data::transaction_manager::ptr tm_;

View File

@ -599,14 +599,16 @@ template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits>::visit(typename visitor::ptr visitor) const btree<Levels, ValueTraits>::visit(typename visitor::ptr visitor) const
{ {
walk_tree(visitor, 0, boost::optional<uint64_t>(), root_); walk_tree(visitor, 0, true, boost::optional<uint64_t>(), root_);
visitor->visit_complete();
} }
template <unsigned Levels, typename ValueTraits> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits>:: btree<Levels, ValueTraits>::
walk_tree(typename visitor::ptr visitor, walk_tree(typename visitor::ptr visitor,
unsigned level, boost::optional<uint64_t> key, unsigned level, bool sub_root,
boost::optional<uint64_t> key,
block_address b) const block_address b) const
{ {
using namespace btree_detail; using namespace btree_detail;
@ -614,18 +616,18 @@ walk_tree(typename visitor::ptr visitor,
read_ref blk = tm_->read_lock(b); read_ref blk = tm_->read_lock(b);
internal_node o = to_node<uint64_traits>(blk); internal_node o = to_node<uint64_traits>(blk);
if (o.get_type() == INTERNAL) { if (o.get_type() == INTERNAL) {
if (visitor->visit_internal(level, key, o)) if (visitor->visit_internal(level, sub_root, key, o))
for (unsigned i = 0; i < o.get_nr_entries(); i++) for (unsigned i = 0; i < o.get_nr_entries(); i++)
walk_tree(visitor, level, o.key_at(i), o.value_at(i)); walk_tree(visitor, level, false, o.key_at(i), o.value_at(i));
} else if (level < Levels - 1) { } else if (level < Levels - 1) {
if (visitor->visit_internal_leaf(level, key, o)) if (visitor->visit_internal_leaf(level, sub_root, key, o))
for (unsigned i = 0; i < o.get_nr_entries(); i++) for (unsigned i = 0; i < o.get_nr_entries(); i++)
walk_tree(visitor, level + 1, boost::optional<uint64_t>(), o.value_at(i)); walk_tree(visitor, level + 1, true, boost::optional<uint64_t>(o.key_at(i)), o.value_at(i));
} else { } else {
leaf_node ov = to_node<ValueTraits>(blk); leaf_node ov = to_node<ValueTraits>(blk);
visitor->visit_leaf(level, key, ov); visitor->visit_leaf(level, sub_root, key, ov);
} }
} }

View File

@ -75,6 +75,7 @@ namespace persistent_data {
} }
bool visit_internal(unsigned level, bool visit_internal(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
if (already_visited(n)) if (already_visited(n))
@ -94,6 +95,7 @@ namespace persistent_data {
} }
bool visit_internal_leaf(unsigned level, bool visit_internal_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
if (already_visited(n)) if (already_visited(n))
@ -115,6 +117,7 @@ namespace persistent_data {
} }
bool visit_leaf(unsigned level, bool visit_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<ValueTraits> const &n) { btree_detail::node_ref<ValueTraits> const &n) {
if (already_visited(n)) if (already_visited(n))

53
emitter.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef EMITTER_H
#define EMITTER_H
#include <boost/shared_ptr.hpp>
#include <string>
#include <stdint.h>
//----------------------------------------------------------------
namespace thin_provisioning {
//------------------------------------------------
// Here's a little grammar for how this all hangs together:
//
// superblock := <uuid> <time> <trans_id> <data_block_size> device*
// device := <dev id> <transaction id> <creation time> <snap time> <binding>
// binding := (<identifier> | <mapping>)*
// mapping := range_map | single_map
// range_map := <origin_begin> <origin_end> <data_begin>
// single_map := <origin> <data>
// named_mapping := <identifier> <mapping>
//------------------------------------------------
class emitter {
public:
typedef boost::shared_ptr<emitter> ptr;
virtual ~emitter() {}
virtual void begin_superblock(std::string const &uuid,
uint64_t time,
uint64_t trans_id,
uint32_t data_block_size) = 0;
virtual void end_superblock() = 0;
virtual void begin_device(uint32_t dev_id,
uint64_t mapped_blocks,
uint64_t trans_id,
uint64_t creation_time,
uint64_t snap_time) = 0;
virtual void end_device() = 0;
virtual void begin_named_mapping(std::string const &name) = 0;
virtual void end_named_mapping() = 0;
virtual void identifier(std::string const &name) = 0;
virtual void range_map(uint64_t origin_begin, uint64_t data_begin, uint64_t len) = 0;
virtual void single_map(uint64_t origin_block, uint64_t ddata_block) = 0;
};
}
//----------------------------------------------------------------
#endif

89
human_readable_format.cc Normal file
View File

@ -0,0 +1,89 @@
#include "human_readable_format.h"
#include <iostream>
using namespace std;
using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
class hr_emitter : public emitter {
public:
hr_emitter(ostream &out)
: out_(out) {
}
void begin_superblock(string const &uuid,
uint64_t time,
uint64_t trans_id,
uint32_t data_block_size) {
out_ << "begin superblock: " << uuid
<< ", " << time
<< ", " << trans_id
<< ", " << data_block_size
<< endl;
}
void end_superblock() {
out_ << "end superblock" << endl;
}
void begin_device(uint32_t dev_id,
uint64_t mapped_blocks,
uint64_t trans_id,
uint64_t creation_time,
uint64_t snap_time) {
out_ << "device: " << dev_id << endl
<< "mapped_blocks: " << mapped_blocks << endl
<< "transaction: " << trans_id << endl
<< "creation time: " << creation_time << endl
<< "snap time: " << snap_time << endl;
}
void end_device() {
out_ << endl;
}
void begin_named_mapping(string const &name) {
out_ << "begin named mapping"
<< endl;
}
void end_named_mapping() {
out_ << "end named mapping"
<< endl;
}
void identifier(string const &name) {
out_ << "identifier: " << name << endl;
}
void range_map(uint64_t origin_begin, uint64_t data_begin, uint64_t len) {
out_ << " (" << origin_begin
<< ".." << origin_begin + len - 1
<< ") -> (" << data_begin
<< ".." << data_begin + len - 1
<< ")" << endl;
}
void single_map(uint64_t origin_block, uint64_t data_block) {
out_ << " " << origin_block
<< " -> " << data_block
<< endl;
}
private:
ostream &out_;
};
}
//----------------------------------------------------------------
thin_provisioning::emitter::ptr
thin_provisioning::create_human_readable_emitter(ostream &out)
{
return emitter::ptr(new hr_emitter(out));
}
//----------------------------------------------------------------

16
human_readable_format.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef HUMAN_READABLE_H
#define HUMAN_READABLE_H
#include "emitter.h"
#include <iosfwd>
//----------------------------------------------------------------
namespace thin_provisioning {
emitter::ptr create_human_readable_emitter(std::ostream &out);
}
//----------------------------------------------------------------
#endif

View File

@ -105,10 +105,11 @@ namespace {
// Sharing can only occur in level 1 nodes. // Sharing can only occur in level 1 nodes.
// FIXME: not true once we start having held roots. // FIXME: not true once we start having held roots.
bool visit_internal_leaf(unsigned level, bool visit_internal_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, key, n); bool r = btree_checker<2, block_traits>::visit_internal_leaf(level, sub_root, key, n);
if (!r && level == 0) { if (!r && level == 0) {
throw runtime_error("unexpected sharing in level 0 of mapping tree."); throw runtime_error("unexpected sharing in level 0 of mapping tree.");
} }
@ -120,9 +121,10 @@ namespace {
} }
bool visit_leaf(unsigned level, bool visit_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<block_traits> const &n) { btree_detail::node_ref<block_traits> const &n) {
bool r = btree_checker<2, block_traits>::visit_leaf(level, key, n); bool r = btree_checker<2, block_traits>::visit_leaf(level, sub_root, key, n);
if (r) if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++) for (unsigned i = 0; i < n.get_nr_entries(); i++)
@ -149,9 +151,10 @@ namespace {
} }
bool visit_leaf(unsigned level, bool visit_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<device_details_traits> const &n) { btree_detail::node_ref<device_details_traits> const &n) {
bool r = btree_checker<1, device_details_traits>::visit_leaf(level, key, n); bool r = btree_checker<1, device_details_traits>::visit_leaf(level, sub_root, key, n);
if (r) if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++) for (unsigned i = 0; i < n.get_nr_entries(); i++)

153
metadata_dump.cc Normal file
View File

@ -0,0 +1,153 @@
#include "metadata.h"
#include "human_readable_format.h"
using namespace persistent_data;
using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
class mappings_extractor : public btree<2, block_traits>::visitor {
public:
typedef boost::shared_ptr<mappings_extractor> ptr;
mappings_extractor(uint64_t dev_id, emitter::ptr e,
space_map::ptr md_sm, space_map::ptr data_sm)
: dev_id_(dev_id),
e_(e),
md_sm_(md_sm),
data_sm_(data_sm),
in_range_(false) {
}
bool visit_internal(unsigned level, bool sub_root, boost::optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) {
return (sub_root && key) ? (*key == dev_id_) : true;
}
bool visit_internal_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) {
return true;
}
bool visit_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> maybe_key,
btree_detail::node_ref<block_traits> const &n) {
for (unsigned i = 0; i < n.get_nr_entries(); i++) {
add_mapping(n.key_at(i), n.value_at(i).block_);
}
return true;
}
void visit_complete() {
end_mapping();
}
private:
void start_mapping(uint64_t origin_block, uint64_t dest_block) {
origin_start_ = origin_block;
dest_start_ = dest_block;
len_ = 1;
in_range_ = true;
}
void end_mapping() {
if (in_range_) {
if (len_ == 1)
e_->single_map(origin_start_, dest_start_);
else
e_->range_map(origin_start_, dest_start_, len_);
in_range_ = false;
}
}
void add_mapping(uint64_t origin_block, uint64_t dest_block) {
if (!in_range_)
start_mapping(origin_block, dest_block);
else if (origin_block == origin_start_ + len_ &&
dest_block == dest_start_ + len_)
len_++;
else {
end_mapping();
start_mapping(origin_block, dest_block);
}
}
uint64_t dev_id_;
emitter::ptr e_;
space_map::ptr md_sm_;
space_map::ptr data_sm_;
bool in_range_;
uint64_t origin_start_, dest_start_, len_;
};
class details_extractor : public btree<1, device_details_traits>::visitor {
public:
typedef boost::shared_ptr<details_extractor> ptr;
details_extractor() {
}
bool visit_internal(unsigned level, bool sub_root, boost::optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) {
return true;
}
bool visit_internal_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> key,
btree_detail::node_ref<uint64_traits> const &n) {
return true;
}
bool visit_leaf(unsigned level, bool sub_root, boost::optional<uint64_t> maybe_key,
btree_detail::node_ref<device_details_traits> const &n) {
for (unsigned i = 0; i < n.get_nr_entries(); i++)
devices_.insert(make_pair(n.key_at(i), n.value_at(i)));
return true;
}
map<uint64_t, device_details> const &get_devices() const {
return devices_;
}
private:
map<uint64_t, device_details> devices_;
};
}
void
metadata::dump()
{
emitter::ptr e = create_human_readable_emitter(cout);
details_extractor::ptr de(new details_extractor);
details_.visit(de);
map<uint64_t, device_details> const &devs = de->get_devices();
map<uint64_t, device_details>::const_iterator it, end = devs.end();
for (it = devs.begin(); it != end; ++it) {
uint64_t dev_id = it->first;
device_details const &dd = it->second;
e->begin_device(dev_id,
dd.mapped_blocks_,
dd.transaction_id_,
dd.creation_time_,
dd.snapshotted_time_);
mappings_extractor::ptr me(new mappings_extractor(dev_id, e, metadata_sm_, data_sm_));
mappings_.visit(me);
e->end_device();
}
}
//----------------------------------------------------------------

View File

@ -321,9 +321,10 @@ namespace {
} }
bool visit_leaf(unsigned level, bool visit_leaf(unsigned level,
bool sub_root,
optional<uint64_t> key, optional<uint64_t> key,
btree_detail::node_ref<index_entry_traits> const &n) { btree_detail::node_ref<index_entry_traits> const &n) {
bool r = btree_checker<1, index_entry_traits>::visit_leaf(level, key, n); bool r = btree_checker<1, index_entry_traits>::visit_leaf(level, sub_root, key, n);
if (!r) if (!r)
return r; return r;

View File

@ -12,7 +12,7 @@ namespace {
void dump(string const &path) { void dump(string const &path) {
metadata md(path); metadata md(path);
//human_readable::ptr emitter(new human_readable); //human_readable::ptr emitter(new human_readable);
// md.dump(); md.dump();
} }
void usage(string const &cmd) { void usage(string const &cmd) {