Merge branch 'master' of github.com:jthornber/thin-provisioning-tools
This commit is contained in:
commit
ef6066e2cd
@ -17,6 +17,7 @@
|
|||||||
#include "caching/metadata.h"
|
#include "caching/metadata.h"
|
||||||
#include "persistent-data/block.h"
|
#include "persistent-data/block.h"
|
||||||
#include "persistent-data/file_utils.h"
|
#include "persistent-data/file_utils.h"
|
||||||
|
#include "persistent-data/space_map.h"
|
||||||
#include "persistent-data/space-maps/core.h"
|
#include "persistent-data/space-maps/core.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
@ -158,6 +159,15 @@ namespace {
|
|||||||
using reporter_base::get_error;
|
using reporter_base::get_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class space_map_reporter : public space_map_detail::visitor, reporter_base {
|
||||||
|
public:
|
||||||
|
space_map_reporter(nested_output &o)
|
||||||
|
: reporter_base(o) {
|
||||||
|
}
|
||||||
|
|
||||||
|
using reporter_base::get_error;
|
||||||
|
};
|
||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
|
|
||||||
transaction_manager::ptr open_tm(block_manager<>::ptr bm) {
|
transaction_manager::ptr open_tm(block_manager<>::ptr bm) {
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "persistent-data/math_utils.h"
|
#include "persistent-data/math_utils.h"
|
||||||
#include "persistent-data/data-structures/btree.h"
|
#include "persistent-data/data-structures/btree.h"
|
||||||
|
#include "persistent-data/data-structures/btree_counter.h"
|
||||||
#include "persistent-data/data-structures/btree_damage_visitor.h"
|
#include "persistent-data/data-structures/btree_damage_visitor.h"
|
||||||
#include "persistent-data/data-structures/array_block.h"
|
#include "persistent-data/data-structures/array_block.h"
|
||||||
|
|
||||||
@ -275,10 +276,9 @@ namespace persistent_data {
|
|||||||
template <typename ValueVisitor, typename DamageVisitor>
|
template <typename ValueVisitor, typename DamageVisitor>
|
||||||
void visit_values(ValueVisitor &value_visitor,
|
void visit_values(ValueVisitor &value_visitor,
|
||||||
DamageVisitor &damage_visitor) const {
|
DamageVisitor &damage_visitor) const {
|
||||||
block_counter counter;
|
|
||||||
block_value_visitor<ValueVisitor> bvisitor(*this, value_visitor);
|
block_value_visitor<ValueVisitor> bvisitor(*this, value_visitor);
|
||||||
block_damage_visitor<DamageVisitor> dvisitor(damage_visitor, entries_per_block_);
|
block_damage_visitor<DamageVisitor> dvisitor(damage_visitor, entries_per_block_);
|
||||||
btree_visit_values(block_tree_, counter, bvisitor, dvisitor);
|
btree_visit_values(block_tree_, bvisitor, dvisitor);
|
||||||
|
|
||||||
// check that all blocks were seen
|
// check that all blocks were seen
|
||||||
unsigned h = bvisitor.get_highest_seen();
|
unsigned h = bvisitor.get_highest_seen();
|
||||||
@ -288,6 +288,26 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
struct ablock_counter {
|
||||||
|
ablock_counter(block_counter &bc)
|
||||||
|
: bc_(bc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(btree_detail::node_location const &loc, block_address b) {
|
||||||
|
bc_.inc(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
block_counter &bc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void count_metadata_blocks(block_counter &bc) const {
|
||||||
|
ablock_counter vc(bc);
|
||||||
|
count_btree_blocks(block_tree_, bc, vc);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct resizer {
|
struct resizer {
|
||||||
|
@ -1,277 +0,0 @@
|
|||||||
// Copyright (C) 2011 Red Hat, Inc. All rights reserved.
|
|
||||||
//
|
|
||||||
// This file is part of the thin-provisioning-tools source.
|
|
||||||
//
|
|
||||||
// thin-provisioning-tools is free software: you can redistribute it
|
|
||||||
// and/or modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation, either version 3 of
|
|
||||||
// the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// thin-provisioning-tools is distributed in the hope that it will be
|
|
||||||
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
||||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License along
|
|
||||||
// with thin-provisioning-tools. If not, see
|
|
||||||
// <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef BTREE_CHECKER_H
|
|
||||||
#define BTREE_CHECKER_H
|
|
||||||
|
|
||||||
#include "btree.h"
|
|
||||||
|
|
||||||
#include "persistent-data/block_counter.h"
|
|
||||||
#include "persistent-data/checksum.h"
|
|
||||||
#include "persistent-data/error_set.h"
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
using namespace persistent_data;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace persistent_data {
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// This class implements consistency checking for the btrees in
|
|
||||||
// general. Derive from this if you want some additional checks.
|
|
||||||
// It's worth summarising what is checked:
|
|
||||||
//
|
|
||||||
// Implemented
|
|
||||||
// -----------
|
|
||||||
//
|
|
||||||
// - block_nr
|
|
||||||
// - nr_entries < max_entries
|
|
||||||
// - max_entries fits in block
|
|
||||||
// - max_entries is divisible by 3
|
|
||||||
// - nr_entries > minimum (except for root nodes)
|
|
||||||
//
|
|
||||||
// Not implemented
|
|
||||||
// ---------------
|
|
||||||
//
|
|
||||||
// - leaf | internal flags (this can be inferred from siblings)
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
template <uint32_t Levels, typename ValueTraits>
|
|
||||||
class btree_checker : public btree<Levels, ValueTraits>::visitor {
|
|
||||||
public:
|
|
||||||
typedef btree_detail::node_location node_location;
|
|
||||||
|
|
||||||
btree_checker(block_counter &counter, bool avoid_repeated_visits = true)
|
|
||||||
: counter_(counter),
|
|
||||||
errs_(new error_set("btree errors")),
|
|
||||||
avoid_repeated_visits_(avoid_repeated_visits) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool visit_internal(node_location const &loc,
|
|
||||||
btree_detail::node_ref<block_traits> const &n) {
|
|
||||||
return check_internal(loc, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool visit_internal_leaf(node_location const &loc,
|
|
||||||
btree_detail::node_ref<block_traits> const &n) {
|
|
||||||
return check_leaf(loc, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool visit_leaf(node_location const &loc,
|
|
||||||
btree_detail::node_ref<ValueTraits> const &n) {
|
|
||||||
return check_leaf(loc, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_set::ptr get_errors() const {
|
|
||||||
return errs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
block_counter &get_counter() {
|
|
||||||
return counter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool check_internal(node_location const &loc,
|
|
||||||
btree_detail::node_ref<block_traits> const &n) {
|
|
||||||
if (!already_visited(n) &&
|
|
||||||
check_block_nr(n) &&
|
|
||||||
check_max_entries(n) &&
|
|
||||||
check_nr_entries(n, loc.is_sub_root()) &&
|
|
||||||
check_ordered_keys(n) &&
|
|
||||||
check_parent_key(loc.is_sub_root() ? boost::optional<uint64_t>() : loc.key, n)) {
|
|
||||||
if (loc.is_sub_root())
|
|
||||||
new_root(loc.level());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ValueTraits2>
|
|
||||||
bool check_leaf(node_location const &loc,
|
|
||||||
btree_detail::node_ref<ValueTraits2> const &n) {
|
|
||||||
if (!already_visited(n) &&
|
|
||||||
check_block_nr(n) &&
|
|
||||||
check_max_entries(n) &&
|
|
||||||
check_nr_entries(n, loc.is_sub_root()) &&
|
|
||||||
check_ordered_keys(n) &&
|
|
||||||
check_parent_key(loc.is_sub_root() ? boost::optional<uint64_t>() : loc.key, n)) {
|
|
||||||
if (loc.is_sub_root())
|
|
||||||
new_root(loc.level());
|
|
||||||
|
|
||||||
return check_leaf_key(loc.level(), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool already_visited(node const &n) {
|
|
||||||
block_address b = n.get_location();
|
|
||||||
|
|
||||||
counter_.inc(b);
|
|
||||||
|
|
||||||
if (avoid_repeated_visits_) {
|
|
||||||
if (seen_.count(b) > 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
seen_.insert(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool check_block_nr(node const &n) const {
|
|
||||||
if (n.get_location() != n.get_block_nr()) {
|
|
||||||
std::ostringstream out;
|
|
||||||
out << "block number mismatch: actually "
|
|
||||||
<< n.get_location()
|
|
||||||
<< ", claims " << n.get_block_nr();
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool 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) > MD_BLOCK_SIZE) {
|
|
||||||
std::ostringstream out;
|
|
||||||
out << "max entries too large: " << n.get_max_entries();
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n.get_max_entries() % 3) {
|
|
||||||
std::ostringstream out;
|
|
||||||
out << "max entries is not divisible by 3: " << n.get_max_entries();
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool check_nr_entries(node const &n, bool is_root) const {
|
|
||||||
if (n.get_nr_entries() > n.get_max_entries()) {
|
|
||||||
std::ostringstream out;
|
|
||||||
out << "bad nr_entries: "
|
|
||||||
<< n.get_nr_entries() << " < "
|
|
||||||
<< n.get_max_entries();
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
block_address min = n.get_max_entries() / 3;
|
|
||||||
if (!is_root && (n.get_nr_entries() < min)) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "too few entries in btree: "
|
|
||||||
<< n.get_nr_entries()
|
|
||||||
<< ", expected at least "
|
|
||||||
<< min
|
|
||||||
<< "(max_entries = " << n.get_max_entries() << ")";
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool check_ordered_keys(node const &n) const {
|
|
||||||
unsigned nr_entries = n.get_nr_entries();
|
|
||||||
|
|
||||||
if (nr_entries == 0)
|
|
||||||
return true; // can only happen if a root node
|
|
||||||
|
|
||||||
uint64_t last_key = n.key_at(0);
|
|
||||||
|
|
||||||
for (unsigned i = 1; i < nr_entries; i++) {
|
|
||||||
uint64_t k = n.key_at(i);
|
|
||||||
if (k <= last_key) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "keys are out of order, " << k << " <= " << last_key;
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
last_key = k;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool check_parent_key(boost::optional<uint64_t> key, node const &n) const {
|
|
||||||
if (!key)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (*key > n.key_at(0)) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "parent key mismatch: parent was " << *key
|
|
||||||
<< ", but lowest in node was " << n.key_at(0);
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename node>
|
|
||||||
bool check_leaf_key(unsigned level, node const &n) {
|
|
||||||
if (n.get_nr_entries() == 0)
|
|
||||||
return true; // can only happen if a root node
|
|
||||||
|
|
||||||
if (last_leaf_key_[level] && *last_leaf_key_[level] >= n.key_at(0)) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "the last key of the previous leaf was " << *last_leaf_key_[level]
|
|
||||||
<< " and the first key of this leaf is " << n.key_at(0);
|
|
||||||
errs_->add_child(out.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_leaf_key_[level] = n.key_at(n.get_nr_entries() - 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void new_root(unsigned level) {
|
|
||||||
// we're starting a new subtree, so should
|
|
||||||
// reset the last_leaf value.
|
|
||||||
last_leaf_key_[level] = boost::optional<uint64_t>();
|
|
||||||
}
|
|
||||||
|
|
||||||
block_counter &counter_;
|
|
||||||
std::set<block_address> seen_;
|
|
||||||
error_set::ptr errs_;
|
|
||||||
boost::optional<uint64_t> last_leaf_key_[Levels];
|
|
||||||
bool avoid_repeated_visits_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
#endif
|
|
81
persistent-data/data-structures/btree_counter.h
Normal file
81
persistent-data/data-structures/btree_counter.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H
|
||||||
|
#define PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H
|
||||||
|
|
||||||
|
#include "persistent-data/block_counter.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace persistent_data {
|
||||||
|
namespace btree_count_detail {
|
||||||
|
template <unsigned Levels, typename ValueTraits, typename ValueCounter>
|
||||||
|
class counting_visitor : public btree<Levels, ValueTraits>::visitor {
|
||||||
|
public:
|
||||||
|
typedef btree<Levels, ValueTraits> tree;
|
||||||
|
|
||||||
|
counting_visitor(block_counter &bc, ValueCounter &vc)
|
||||||
|
: bc_(bc),
|
||||||
|
vc_(vc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit_internal(node_location const &l,
|
||||||
|
typename tree::internal_node const &n) {
|
||||||
|
return visit_node(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit_internal_leaf(node_location const &l,
|
||||||
|
typename tree::internal_node const &n) {
|
||||||
|
return visit_node(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool visit_leaf(node_location const &l,
|
||||||
|
typename tree::leaf_node const &n) {
|
||||||
|
if (visit_node(n)) {
|
||||||
|
unsigned nr = n.get_nr_entries();
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < nr; i++) {
|
||||||
|
// FIXME: confirm l2 is correct
|
||||||
|
node_location l2(l);
|
||||||
|
l2.push_key(i);
|
||||||
|
vc_.visit(l2, n.value_at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Node>
|
||||||
|
bool visit_node(Node const &n) {
|
||||||
|
block_address b = n.get_location();
|
||||||
|
bool seen = bc_.get_count(b);
|
||||||
|
bc_.inc(b);
|
||||||
|
return !seen;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_counter &bc_;
|
||||||
|
ValueCounter &vc_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct noop_value_counter {
|
||||||
|
void visit(btree_detail::node_location const &loc, T const &v) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Counts how many times each metadata block is referenced in the
|
||||||
|
// tree. Blocks already referenced in the block counter are not
|
||||||
|
// walked. This walk should only be done once you're sure the tree
|
||||||
|
// is not corrupt.
|
||||||
|
template <unsigned Levels, typename ValueTraits, typename ValueCounter>
|
||||||
|
void count_btree_blocks(btree<Levels, ValueTraits> const &tree, block_counter &bc, ValueCounter &vc) {
|
||||||
|
btree_count_detail::counting_visitor<Levels, ValueTraits, ValueCounter> v(bc, vc);
|
||||||
|
tree.visit_depth_first(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -136,11 +136,9 @@ namespace persistent_data {
|
|||||||
typedef run<block_address> run64;
|
typedef run<block_address> run64;
|
||||||
typedef boost::optional<run64> maybe_run64;
|
typedef boost::optional<run64> maybe_run64;
|
||||||
|
|
||||||
btree_damage_visitor(block_counter &counter,
|
btree_damage_visitor(ValueVisitor &value_visitor,
|
||||||
ValueVisitor &value_visitor,
|
|
||||||
DamageVisitor &damage_visitor)
|
DamageVisitor &damage_visitor)
|
||||||
: counter_(counter),
|
: avoid_repeated_visits_(true),
|
||||||
avoid_repeated_visits_(true),
|
|
||||||
value_visitor_(value_visitor),
|
value_visitor_(value_visitor),
|
||||||
damage_visitor_(damage_visitor) {
|
damage_visitor_(damage_visitor) {
|
||||||
}
|
}
|
||||||
@ -243,8 +241,6 @@ namespace persistent_data {
|
|||||||
bool already_visited(node const &n) {
|
bool already_visited(node const &n) {
|
||||||
block_address b = n.get_location();
|
block_address b = n.get_location();
|
||||||
|
|
||||||
counter_.inc(b);
|
|
||||||
|
|
||||||
if (avoid_repeated_visits_) {
|
if (avoid_repeated_visits_) {
|
||||||
if (seen_.count(b) > 0)
|
if (seen_.count(b) > 0)
|
||||||
return true;
|
return true;
|
||||||
@ -441,7 +437,6 @@ namespace persistent_data {
|
|||||||
|
|
||||||
//--------------------------------
|
//--------------------------------
|
||||||
|
|
||||||
block_counter &counter_;
|
|
||||||
bool avoid_repeated_visits_;
|
bool avoid_repeated_visits_;
|
||||||
|
|
||||||
ValueVisitor &value_visitor_;
|
ValueVisitor &value_visitor_;
|
||||||
@ -458,11 +453,10 @@ namespace persistent_data {
|
|||||||
|
|
||||||
template <unsigned Levels, typename ValueTraits, typename ValueVisitor, typename DamageVisitor>
|
template <unsigned Levels, typename ValueTraits, typename ValueVisitor, typename DamageVisitor>
|
||||||
void btree_visit_values(btree<Levels, ValueTraits> const &tree,
|
void btree_visit_values(btree<Levels, ValueTraits> const &tree,
|
||||||
block_counter &counter,
|
|
||||||
ValueVisitor &value_visitor,
|
ValueVisitor &value_visitor,
|
||||||
DamageVisitor &damage_visitor) {
|
DamageVisitor &damage_visitor) {
|
||||||
btree_detail::btree_damage_visitor<ValueVisitor, DamageVisitor, Levels, ValueTraits>
|
btree_detail::btree_damage_visitor<ValueVisitor, DamageVisitor, Levels, ValueTraits>
|
||||||
v(counter, value_visitor, damage_visitor);
|
v(value_visitor, damage_visitor);
|
||||||
tree.visit_depth_first(v);
|
tree.visit_depth_first(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ namespace {
|
|||||||
return sm_->copy_root(dest, len);
|
return sm_->copy_root(dest, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(block_counter &counter) const {
|
virtual void visit(space_map_detail::visitor &v) const {
|
||||||
return sm_->check(counter);
|
return sm_->visit(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual checked_space_map::ptr clone() const {
|
virtual checked_space_map::ptr clone() const {
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include "persistent-data/space-maps/recursive.h"
|
#include "persistent-data/space-maps/recursive.h"
|
||||||
#include "persistent-data/space-maps/careful_alloc.h"
|
#include "persistent-data/space-maps/careful_alloc.h"
|
||||||
|
|
||||||
#include "persistent-data/data-structures/btree_checker.h"
|
#include "persistent-data/data-structures/btree_damage_visitor.h"
|
||||||
#include "persistent-data/checksum.h"
|
#include "persistent-data/checksum.h"
|
||||||
#include "persistent-data/endian_utils.h"
|
#include "persistent-data/endian_utils.h"
|
||||||
#include "persistent-data/math_utils.h"
|
#include "persistent-data/math_utils.h"
|
||||||
@ -200,6 +200,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
class ref_count_checker : public btree_checker<1, ref_count_traits> {
|
class ref_count_checker : public btree_checker<1, ref_count_traits> {
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<ref_count_checker> ptr;
|
typedef boost::shared_ptr<ref_count_checker> ptr;
|
||||||
@ -208,6 +209,14 @@ namespace {
|
|||||||
: btree_checker<1, ref_count_traits>(counter) {
|
: btree_checker<1, ref_count_traits>(counter) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class index_entry_visitor {
|
||||||
|
public:
|
||||||
|
virtual ~index_entry_visitor() {}
|
||||||
|
virtual void visit(index_entry const &ie) = 0;
|
||||||
|
virtual void visit(run<block_address> const &missing) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class index_store {
|
class index_store {
|
||||||
public:
|
public:
|
||||||
@ -219,7 +228,7 @@ namespace {
|
|||||||
virtual void commit_ies() = 0;
|
virtual void commit_ies() = 0;
|
||||||
virtual ptr clone() const = 0;
|
virtual ptr clone() const = 0;
|
||||||
virtual block_address get_root() const = 0;
|
virtual block_address get_root() const = 0;
|
||||||
virtual void check(block_counter &counter, block_address nr_index_entries) const = 0;
|
virtual void visit(index_entry_visitor &v, block_address nr_index_entries) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned const ENTRIES_PER_BLOCK = (MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4;
|
unsigned const ENTRIES_PER_BLOCK = (MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4;
|
||||||
@ -358,12 +367,14 @@ namespace {
|
|||||||
nr_blocks_ = nr_blocks;
|
nr_blocks_ = nr_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(block_counter &counter) const {
|
virtual void visit(space_map_detail::visitor &v) const {
|
||||||
ref_count_checker v(counter);
|
#if 0
|
||||||
ref_counts_.visit_depth_first(v);
|
ref_count_checker rcv(v);
|
||||||
|
ref_counts_.visit_depth_first(rcv);
|
||||||
|
|
||||||
block_address nr_entries = div_up<block_address>(get_nr_blocks(), ENTRIES_PER_BLOCK);
|
block_address nr_entries = div_up<block_address>(get_nr_blocks(), ENTRIES_PER_BLOCK);
|
||||||
indexes_->check(counter, nr_entries);
|
indexes_->visit(v, nr_entries);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct look_aside_iterator : public iterator {
|
struct look_aside_iterator : public iterator {
|
||||||
@ -498,56 +509,34 @@ namespace {
|
|||||||
btree<1, ref_count_traits> ref_counts_;
|
btree<1, ref_count_traits> ref_counts_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class bitmap_tree_validator : public btree_checker<1, index_entry_traits> {
|
//--------------------------------
|
||||||
|
|
||||||
|
class ie_value_visitor {
|
||||||
public:
|
public:
|
||||||
typedef btree_detail::node_location node_location;
|
ie_value_visitor(index_entry_visitor &v)
|
||||||
typedef boost::shared_ptr<bitmap_tree_validator> ptr;
|
: v_(v) {
|
||||||
|
|
||||||
bitmap_tree_validator(block_counter &counter)
|
|
||||||
: btree_checker<1, index_entry_traits>(counter) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit_leaf(node_location const &loc,
|
virtual void visit(btree_path const &path, sm_disk_detail::index_entry const &ie) {
|
||||||
btree_detail::node_ref<index_entry_traits> const &n) {
|
// FIXME: finish
|
||||||
bool r = btree_checker<1, index_entry_traits>::visit_leaf(loc, n);
|
|
||||||
if (!r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < n.get_nr_entries(); i++) {
|
|
||||||
if (seen_indexes_.count(n.key_at(i)) > 0) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "index entry " << i << " is present twice";
|
|
||||||
throw runtime_error(out.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
seen_indexes_.insert(n.key_at(i));
|
|
||||||
btree_checker<1, index_entry_traits>::get_counter().inc(n.value_at(i).blocknr_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_all_index_entries_present(block_address nr_entries) {
|
|
||||||
for (block_address i = 0; i < nr_entries; i++) {
|
|
||||||
if (seen_indexes_.count(i) == 0) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "missing index entry " << i;
|
|
||||||
throw runtime_error(out.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set<block_address>::const_iterator it;
|
|
||||||
for (it = seen_indexes_.begin(); it != seen_indexes_.end(); ++it) {
|
|
||||||
if (*it >= nr_entries) {
|
|
||||||
ostringstream out;
|
|
||||||
out << "unexpected index entry " << *it;
|
|
||||||
throw runtime_error(out.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
set<block_address> seen_indexes_;
|
index_entry_visitor &v_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ie_damage_visitor {
|
||||||
|
public:
|
||||||
|
ie_damage_visitor(index_entry_visitor &v)
|
||||||
|
: v_(v) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(btree_path const &path, btree_detail::damage const &d) {
|
||||||
|
// FIXME: finish
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
index_entry_visitor &v_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class btree_index_store : public index_store {
|
class btree_index_store : public index_store {
|
||||||
@ -595,10 +584,10 @@ namespace {
|
|||||||
return bitmaps_.get_root();
|
return bitmaps_.get_root();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(block_counter &counter, block_address nr_index_entries) const {
|
virtual void visit(index_entry_visitor &v, block_address nr_index_entries) const {
|
||||||
bitmap_tree_validator v(counter);
|
ie_value_visitor vv(v);
|
||||||
bitmaps_.visit_depth_first(v);
|
ie_damage_visitor dv(v);
|
||||||
v.check_all_index_entries_present(nr_index_entries);
|
btree_visit_values(bitmaps_, vv, dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -654,12 +643,18 @@ namespace {
|
|||||||
return bitmap_root_;
|
return bitmap_root_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(block_counter &counter, block_address nr_index_entries) const {
|
virtual void visit(index_entry_visitor &vv, block_address nr_index_entries) const {
|
||||||
|
for (unsigned i = 0; i < entries_.size(); i++)
|
||||||
|
if (entries_[i].blocknr_ != 0)
|
||||||
|
vv.visit(entries_[i]);
|
||||||
|
|
||||||
|
#if 0
|
||||||
counter.inc(bitmap_root_);
|
counter.inc(bitmap_root_);
|
||||||
for (unsigned i = 0; i < entries_.size(); i++)
|
for (unsigned i = 0; i < entries_.size(); i++)
|
||||||
// FIXME: this looks like a hack
|
// FIXME: this looks like a hack
|
||||||
if (entries_[i].blocknr_ != 0) // superblock
|
if (entries_[i].blocknr_ != 0) // superblock
|
||||||
counter.inc(entries_[i].blocknr_);
|
counter.inc(entries_[i].blocknr_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -188,10 +188,10 @@ namespace {
|
|||||||
return sm_->copy_root(dest, len);
|
return sm_->copy_root(dest, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void check(persistent_data::block_counter &counter) const {
|
virtual void visit(space_map_detail::visitor &v) const {
|
||||||
cant_recurse("check");
|
cant_recurse("check");
|
||||||
recursing_const_lock lock(*this);
|
recursing_const_lock lock(*this);
|
||||||
return sm_->check(counter);
|
return sm_->visit(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual checked_space_map::ptr clone() const {
|
virtual checked_space_map::ptr clone() const {
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
#ifndef SPACE_MAP_H
|
#ifndef SPACE_MAP_H
|
||||||
#define SPACE_MAP_H
|
#define SPACE_MAP_H
|
||||||
|
|
||||||
#include "block.h"
|
#include "persistent-data/block.h"
|
||||||
#include "block_counter.h"
|
#include "persistent-data/block_counter.h"
|
||||||
|
#include "persistent-data/run.h"
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@ -114,6 +115,28 @@ namespace persistent_data {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
namespace space_map_detail {
|
||||||
|
class damage {
|
||||||
|
virtual ~damage() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class missing_counts : public damage {
|
||||||
|
public:
|
||||||
|
missing_counts(base::run<block_address> &lost);
|
||||||
|
};
|
||||||
|
|
||||||
|
class visitor {
|
||||||
|
public:
|
||||||
|
virtual ~visitor() {}
|
||||||
|
virtual void visit(missing_counts const &mc) = 0;
|
||||||
|
virtual void visit(block_address b, uint32_t count) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
class persistent_space_map : public space_map {
|
class persistent_space_map : public space_map {
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<persistent_space_map> ptr;
|
typedef boost::shared_ptr<persistent_space_map> ptr;
|
||||||
@ -126,8 +149,8 @@ namespace persistent_data {
|
|||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<checked_space_map> ptr;
|
typedef boost::shared_ptr<checked_space_map> ptr;
|
||||||
|
|
||||||
virtual void check(block_counter &counter) const {
|
virtual void visit(space_map_detail::visitor &v) const {
|
||||||
throw std::runtime_error("'check' not implemented");
|
throw std::runtime_error("space_map.visit not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: should this be in the base space_map class?
|
// FIXME: should this be in the base space_map class?
|
||||||
|
@ -84,10 +84,9 @@ thin_provisioning::walk_device_tree(device_tree const &tree,
|
|||||||
device_tree_detail::device_visitor &vv,
|
device_tree_detail::device_visitor &vv,
|
||||||
device_tree_detail::damage_visitor &dv)
|
device_tree_detail::damage_visitor &dv)
|
||||||
{
|
{
|
||||||
block_counter counter;
|
|
||||||
visitor_adapter av(vv);
|
visitor_adapter av(vv);
|
||||||
ll_damage_visitor ll_dv(dv);
|
ll_damage_visitor ll_dv(dv);
|
||||||
btree_visit_values(tree, counter, av, ll_dv);
|
btree_visit_values(tree, av, ll_dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -173,9 +173,8 @@ thin_provisioning::walk_mapping_tree(dev_tree const &tree,
|
|||||||
mapping_tree_detail::device_visitor &dev_v,
|
mapping_tree_detail::device_visitor &dev_v,
|
||||||
mapping_tree_detail::damage_visitor &dv)
|
mapping_tree_detail::damage_visitor &dv)
|
||||||
{
|
{
|
||||||
block_counter counter;
|
|
||||||
ll_damage_visitor ll_dv(dv);
|
ll_damage_visitor ll_dv(dv);
|
||||||
btree_visit_values(tree, counter, dev_v, ll_dv);
|
btree_visit_values(tree, dev_v, ll_dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -191,9 +190,8 @@ thin_provisioning::walk_mapping_tree(mapping_tree const &tree,
|
|||||||
mapping_tree_detail::mapping_visitor &mv,
|
mapping_tree_detail::mapping_visitor &mv,
|
||||||
mapping_tree_detail::damage_visitor &dv)
|
mapping_tree_detail::damage_visitor &dv)
|
||||||
{
|
{
|
||||||
block_counter counter;
|
|
||||||
ll_damage_visitor ll_dv(dv);
|
ll_damage_visitor ll_dv(dv);
|
||||||
btree_visit_values(tree, counter, mv, ll_dv);
|
btree_visit_values(tree, mv, ll_dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -209,9 +207,8 @@ thin_provisioning::walk_mapping_tree(single_mapping_tree const &tree,
|
|||||||
mapping_tree_detail::mapping_visitor &mv,
|
mapping_tree_detail::mapping_visitor &mv,
|
||||||
mapping_tree_detail::damage_visitor &dv)
|
mapping_tree_detail::damage_visitor &dv)
|
||||||
{
|
{
|
||||||
block_counter counter;
|
|
||||||
ll_damage_visitor ll_dv(dv);
|
ll_damage_visitor ll_dv(dv);
|
||||||
btree_visit_values(tree, counter, mv, ll_dv);
|
btree_visit_values(tree, mv, ll_dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "thin-provisioning/thin_pool.h"
|
#include "thin-provisioning/thin_pool.h"
|
||||||
|
|
||||||
#include "persistent-data/data-structures/btree_checker.h"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -63,7 +63,6 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rmap(string const &path, vector<region> const ®ions) {
|
int rmap(string const &path, vector<region> const ®ions) {
|
||||||
block_counter counter; // FIXME: get rid of this counter arg
|
|
||||||
damage_visitor dv;
|
damage_visitor dv;
|
||||||
rmap_visitor rv;
|
rmap_visitor rv;
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ namespace {
|
|||||||
mapping_tree mtree(tm, sb.data_mapping_root_,
|
mapping_tree mtree(tm, sb.data_mapping_root_,
|
||||||
mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
|
mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
|
||||||
|
|
||||||
btree_visit_values(mtree, counter, rv, dv);
|
btree_visit_values(mtree, rv, dv);
|
||||||
rv.complete();
|
rv.complete();
|
||||||
display_rmap(cout, rv.get_rmap());
|
display_rmap(cout, rv.get_rmap());
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ TEST_SOURCE=\
|
|||||||
unit-tests/bitset_t.cc \
|
unit-tests/bitset_t.cc \
|
||||||
unit-tests/block_t.cc \
|
unit-tests/block_t.cc \
|
||||||
unit-tests/btree_t.cc \
|
unit-tests/btree_t.cc \
|
||||||
|
unit-tests/btree_counter_t.cc \
|
||||||
unit-tests/btree_damage_visitor_t.cc \
|
unit-tests/btree_damage_visitor_t.cc \
|
||||||
unit-tests/buffer_t.cc \
|
unit-tests/buffer_t.cc \
|
||||||
unit-tests/cache_t.cc \
|
unit-tests/cache_t.cc \
|
||||||
|
84
unit-tests/btree_counter_t.cc
Normal file
84
unit-tests/btree_counter_t.cc
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
#include "persistent-data/data-structures/btree.h"
|
||||||
|
#include "persistent-data/data-structures/btree_counter.h"
|
||||||
|
#include "persistent-data/space-maps/core.h"
|
||||||
|
|
||||||
|
using namespace base;
|
||||||
|
using namespace std;
|
||||||
|
using namespace persistent_data;
|
||||||
|
using namespace test;
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
block_address const BLOCK_SIZE = 4096;
|
||||||
|
block_address const NR_BLOCKS = 102400;
|
||||||
|
block_address const SUPERBLOCK = 0;
|
||||||
|
|
||||||
|
class BTreeCounterTests : public Test {
|
||||||
|
public:
|
||||||
|
BTreeCounterTests()
|
||||||
|
: bm_(create_bm<BLOCK_SIZE>(NR_BLOCKS)),
|
||||||
|
sm_(setup_core_map()),
|
||||||
|
tm_(new transaction_manager(bm_, sm_)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_nr_metadata_blocks_is_ge(unsigned n) {
|
||||||
|
block_counter bc;
|
||||||
|
noop_value_counter<uint64_t> vc;
|
||||||
|
count_btree_blocks(*tree_, bc, vc);
|
||||||
|
ASSERT_THAT(bc.get_counts().size(), Ge(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
with_temp_directory dir_;
|
||||||
|
block_manager<>::ptr bm_;
|
||||||
|
space_map::ptr sm_;
|
||||||
|
transaction_manager::ptr tm_;
|
||||||
|
uint64_traits::ref_counter rc_;
|
||||||
|
|
||||||
|
btree<1, uint64_traits>::ptr tree_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
space_map::ptr setup_core_map() {
|
||||||
|
space_map::ptr sm(new core_map(NR_BLOCKS));
|
||||||
|
sm->inc(SUPERBLOCK);
|
||||||
|
return sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit() {
|
||||||
|
block_manager<>::write_ref superblock(bm_->superblock(SUPERBLOCK));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump_counts(block_counter const &bc) {
|
||||||
|
block_counter::count_map::const_iterator it, end = bc.get_counts().end();
|
||||||
|
for (it = bc.get_counts().begin(); it != end; ++it)
|
||||||
|
cout << it->first << " -> " << it->second << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST_F(BTreeCounterTests, count_empty_tree)
|
||||||
|
{
|
||||||
|
tree_.reset(new btree<1, uint64_traits>(tm_, rc_));
|
||||||
|
check_nr_metadata_blocks_is_ge(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(BTreeCounterTests, count_populated_tree)
|
||||||
|
{
|
||||||
|
tree_.reset(new btree<1, uint64_traits>(tm_, rc_));
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 10000; i++) {
|
||||||
|
uint64_t key[1] = {i};
|
||||||
|
tree_->insert(key, 0ull);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_nr_metadata_blocks_is_ge(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
@ -388,8 +388,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void run_() {
|
virtual void run_() {
|
||||||
block_counter counter;
|
btree_visit_values(*tree_, value_visitor_, damage_visitor_);
|
||||||
btree_visit_values(*tree_, counter, value_visitor_, damage_visitor_);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -470,8 +469,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void run_() {
|
virtual void run_() {
|
||||||
block_counter counter;
|
btree_visit_values(*tree_, value_visitor_, damage_visitor_);
|
||||||
btree_visit_values(*tree_, counter, value_visitor_, damage_visitor_);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user