Some work on thin_repair.
This commit is contained in:
207
metadata.cc
207
metadata.cc
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user