Some work on thin_repair.

This commit is contained in:
Joe Thornber
2011-08-23 11:55:37 +01:00
parent 29c2831f3e
commit 511456f903
9 changed files with 292 additions and 29 deletions

View File

@@ -1,7 +1,12 @@
#include "metadata.h"
#include <stdexcept>
#include "core_map.h"
#include <stdexcept>
#include <sstream>
#include <iostream>
using namespace std;
using namespace persistent_data;
using namespace thin_provisioning;
@@ -13,6 +18,164 @@ namespace {
uint32_t const VERSION = 1;
unsigned const METADATA_CACHE_SIZE = 1024;
unsigned const SECTOR_TO_BLOCK_SHIFT = 3;
// FIXME: get the file size
unsigned const NR_BLOCKS = 1024;
transaction_manager<4096>::ptr
open_tm(string const &dev_path) {
block_manager<4096>::ptr bm(new block_manager<4096>(dev_path, NR_BLOCKS));
space_map::ptr sm(new core_map(NR_BLOCKS));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm));
return tm;
}
superblock read_superblock(block_manager<4096>::ptr bm) {
superblock sb;
auto r = bm->read_lock(SUPERBLOCK_LOCATION);
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data());
superblock_traits::unpack(*sbd, sb);
return sb;
}
//----------------------------------------------------------------
// This class implements consistency checking for the
// btrees in general. It's worth summarising what is checked:
//
// Implemented
// -----------
//
// - No block appears in the tree more than once.
// - block_nr
// - nr_entries < max_entries
// - max_entries fits in block
// - max_entries is divisible by 3
//
// Not implemented
// ---------------
//
// - checksum
// - leaf | internal flags (this can be inferred from siblings)
// - nr_entries > minimum
//----------------------------------------------------------------
template <uint32_t Levels, typename ValueTraits, uint32_t BlockSize>
class btree_validator : public btree<Levels, ValueTraits, BlockSize>::visitor {
public:
void visit_internal(unsigned level, btree_detail::node_ref<uint64_traits, BlockSize> const &n) {
check_duplicate_block(n.get_location());
check_block_nr(n);
check_max_entries(n);
check_nr_entries(n);
}
void visit_internal_leaf(unsigned level, btree_detail::node_ref<uint64_traits, BlockSize> const &n) {
check_duplicate_block(n.get_location());
check_block_nr(n);
check_max_entries(n);
check_nr_entries(n);
}
void visit_leaf(unsigned level, btree_detail::node_ref<ValueTraits, BlockSize> const &n) {
check_duplicate_block(n.get_location());
check_block_nr(n);
check_max_entries(n);
check_nr_entries(n);
}
private:
void check_duplicate_block(block_address b) {
if (seen_.count(b)) {
ostringstream out;
out << "duplicate block in btree: " << b;
throw runtime_error(out.str());
}
seen_.insert(b);
}
template <typename node>
void check_block_nr(node const &n) const {
if (n.get_location() != n.get_block_nr()) {
ostringstream out;
out << "block number mismatch: actually "
<< n.get_location()
<< ", claims " << n.get_block_nr();
throw runtime_error(out.str());
}
}
template <typename node>
void check_max_entries(node const &n) const {
size_t elt_size = sizeof(uint64_t) + n.get_value_size();
if (elt_size * n.get_max_entries() + sizeof(node_header) > BlockSize) {
ostringstream out;
out << "max entries too large: " << n.get_max_entries();
throw runtime_error(out.str());
}
if (n.get_max_entries() % 3) {
ostringstream out;
out << "max entries is not divisible by 3: " << n.get_max_entries();
throw runtime_error(out.str());
}
}
template <typename node>
void check_nr_entries(node const &n) const {
if (n.get_nr_entries() > n.get_max_entries()) {
ostringstream out;
out << "bad nr_entries: "
<< n.get_nr_entries() << " < "
<< n.get_max_entries();
throw runtime_error(out.str());
}
}
set<block_address> seen_;
};
// As well as the standard btree checks, we build up a set of what
// devices having mappings defined, which can later be cross
// referenced with the details tree.
class mapping_validator : public btree_validator<2, block_traits, MD_BLOCK_SIZE> {
public:
typedef boost::shared_ptr<mapping_validator> ptr;
void visit_internal_leaf(unsigned level,
btree_detail::node_ref<uint64_traits, MD_BLOCK_SIZE> const &n) {
btree_validator<2, block_traits, MD_BLOCK_SIZE>::visit_internal_leaf(level, n);
for (unsigned i = 0; i < n.get_nr_entries(); i++)
devices_.insert(n.key_at(i));
}
set<uint64_t> get_devices() const {
return devices_;
}
private:
set<uint64_t> devices_;
};
class details_validator : public btree_validator<1, device_details_traits, MD_BLOCK_SIZE> {
public:
typedef boost::shared_ptr<details_validator> ptr;
void visit_leaf(unsigned level,
btree_detail::node_ref<device_details_traits, MD_BLOCK_SIZE> const &n) {
btree_validator<1, device_details_traits, MD_BLOCK_SIZE>::visit_leaf(level, n);
for (unsigned i = 0; i < n.get_nr_entries(); i++)
devices_.insert(n.key_at(i));
}
set<uint64_t> get_devices() const {
return devices_;
}
private:
set<uint64_t> devices_;
};
}
//----------------------------------------------------------------
@@ -87,22 +250,20 @@ thin::set_mapped_blocks(block_address count)
//--------------------------------
metadata::metadata(transaction_manager<MD_BLOCK_SIZE>::ptr tm,
block_address superblock,
sector_t data_block_size,
block_address nr_data_blocks,
bool create)
: superblock_(superblock),
tm_(tm),
details_(tm, typename device_details_traits::ref_counter()),
mappings_top_level_(tm, mtree_ref_counter<MD_BLOCK_SIZE>(tm)),
mappings_(tm, space_map_ref_counter(data_sm_))
metadata::metadata(std::string const &dev_path)
: tm_(open_tm(dev_path)),
sb_(read_superblock(tm_->get_bm())),
details_(tm_, sb_.device_details_root_, typename device_details_traits::ref_counter()),
mappings_top_level_(tm_, sb_.data_mapping_root_, mtree_ref_counter<MD_BLOCK_SIZE>(tm_)),
mappings_(tm_, sb_.data_mapping_root_, space_map_ref_counter(data_sm_))
{
#if 0
::memset(&sb_, 0, sizeof(sb_));
sb_.data_mapping_root_ = mappings_.get_root();
sb_.device_details_root_ = details_.get_root();
sb_.metadata_block_size_ = MD_BLOCK_SIZE;
sb_.metadata_nr_blocks_ = tm->get_bm()->get_nr_blocks();
sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks();
#endif
}
metadata::~metadata()
@@ -116,7 +277,7 @@ metadata::commit()
sb_.data_mapping_root_ = mappings_.get_root();
sb_.device_details_root_ = details_.get_root();
auto superblock = tm_->get_bm()->superblock(superblock_);
auto superblock = tm_->get_bm()->superblock(SUPERBLOCK_LOCATION);
auto disk = reinterpret_cast<superblock_disk *>(superblock.data());
superblock_traits::pack(sb_, *disk);
}
@@ -235,4 +396,24 @@ metadata::device_exists(thin_dev_t dev) const
return details_.lookup(key);
}
void
metadata::check()
{
mapping_validator::ptr mv(new mapping_validator);
mappings_.visit(mv);
auto mapped_devs = mv->get_devices();
details_validator::ptr dv(new details_validator);
details_.visit(dv);
auto details_devs = dv->get_devices();
for (auto it = mapped_devs.begin(); it != mapped_devs.end(); ++it)
if (details_devs.count(*it) == 0) {
ostringstream out;
out << "mapping exists for device " << *it
<< ", yet there is no entry in the details tree.";
throw runtime_error(out.str());
}
}
//----------------------------------------------------------------