thin_restore works (well thin_repair thinks it does).

This commit is contained in:
Joe Thornber 2011-11-03 14:44:00 +00:00
parent 9cee046594
commit 6bff674720
16 changed files with 423 additions and 117 deletions

View File

@ -18,9 +18,14 @@ SOURCE=\
transaction_manager.cc \ transaction_manager.cc \
xml_format.cc xml_format.cc
PROGRAM_SOURCE=\
thin_dump.cc \
thin_repair.cc \
thin_restore.cc
OBJECTS=$(subst .cc,.o,$(SOURCE)) OBJECTS=$(subst .cc,.o,$(SOURCE))
TOP_DIR:=$(PWD) TOP_DIR:=$(PWD)
CPPFLAGS=-Wall -g -I$(TOP_DIR) -O8 CPPFLAGS=-Wall -g -I$(TOP_DIR)
#CPPFLAGS=-Wall -std=c++0x -g -I$(TOP_DIR) #CPPFLAGS=-Wall -std=c++0x -g -I$(TOP_DIR)
LIBS=-lstdc++ -lboost_program_options -lexpat LIBS=-lstdc++ -lboost_program_options -lexpat
@ -50,3 +55,4 @@ thin_repair: $(OBJECTS) thin_repair.o
include unit-tests/Makefile.in include unit-tests/Makefile.in
include $(subst .cc,.d,$(SOURCE)) include $(subst .cc,.d,$(SOURCE))
include $(subst .cc,.d,$(TEST_SOURCE)) include $(subst .cc,.d,$(TEST_SOURCE))
include $(subst .cc,.d,$(PROGRAM_SOURCE))

View File

@ -200,6 +200,12 @@ namespace persistent_data {
typedef std::map<block_address, std::pair<lock_type, unsigned> > held_map; typedef std::map<block_address, std::pair<lock_type, unsigned> > held_map;
mutable held_map held_locks_; mutable held_map held_locks_;
}; };
// A little utility to help build validators
inline block_manager<>::validator::ptr
mk_validator(block_manager<>::validator *v) {
return block_manager<>::validator::ptr(v);
}
} }
#include "block.tcc" #include "block.tcc"

View File

@ -8,6 +8,7 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <stdexcept> #include <stdexcept>
#include <sstream>
using namespace boost; using namespace boost;
using namespace persistent_data; using namespace persistent_data;
@ -20,7 +21,8 @@ block_io<BlockSize>::block_io(std::string const &path, block_address nr_blocks,
: nr_blocks_(nr_blocks), : nr_blocks_(nr_blocks),
writeable_(writeable) writeable_(writeable)
{ {
fd_ = ::open(path.c_str(), writeable ? (O_RDWR | O_CREAT) : O_RDONLY, 0666); // fd_ = ::open(path.c_str(), writeable ? (O_RDWR | O_CREAT) : O_RDONLY, 0666);
fd_ = ::open(path.c_str(), writeable ? O_RDWR : 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");
} }
@ -75,8 +77,17 @@ block_io<BlockSize>::write_buffer(block_address location, const_buffer &buffer)
} }
} while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN))); } while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN)));
if (n < 0) if (n < 0) {
throw std::runtime_error("write failed"); std::ostringstream out;
out << "write failed to block " << location
<< ", block size = " << BlockSize
<< ", remaining = " << remaining
<< ", n = " << n
<< ", errno = " << errno
<< ", fd_ = " << fd_
<< std::endl;
throw std::runtime_error(out.str());
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
@ -277,6 +288,7 @@ block_manager<BlockSize>::superblock(block_address location,
if (cached_block) { if (cached_block) {
(*cached_block)->check_write_lockable(); (*cached_block)->check_write_lockable();
(*cached_block)->bt_ = BT_SUPERBLOCK; (*cached_block)->bt_ = BT_SUPERBLOCK;
(*cached_block)->validator_ = v;
return write_ref(*this, *cached_block); return write_ref(*this, *cached_block);
} }
@ -297,10 +309,13 @@ block_manager<BlockSize>::superblock_zero(block_address location,
if (cached_block) { if (cached_block) {
(*cached_block)->check_write_lockable(); (*cached_block)->check_write_lockable();
memset(&(*cached_block)->data_, 0, BlockSize); memset(&(*cached_block)->data_, 0, BlockSize);
(*cached_block)->validator_ = v;
return write_ref(*this, *cached_block); return write_ref(*this, *cached_block);
} }
block_ptr b(new block(io_, location, BT_SUPERBLOCK, v, true)); block_ptr b(new block(io_, location, BT_SUPERBLOCK,
mk_validator(new noop_validator), true));
b->validator_ = v;
cache_.insert(b); cache_.insert(b);
return write_ref(*this, b); return write_ref(*this, b);
} }

18
btree.h
View File

@ -177,11 +177,7 @@ namespace persistent_data {
: tm_(tm) { : tm_(tm) {
} }
void step(block_address b) { void step(block_address b);
spine_.push_back(tm_->read_lock(b));
if (spine_.size() > 2)
spine_.pop_front();
}
template <typename ValueTraits> template <typename ValueTraits>
node_ref<ValueTraits> get_node() { node_ref<ValueTraits> get_node() {
@ -203,17 +199,7 @@ namespace persistent_data {
} }
// true if the children of the shadow need incrementing // true if the children of the shadow need incrementing
bool step(block_address b) { bool step(block_address b);
pair<write_ref, bool> p = tm_->shadow(b);
try {
step(p.first);
} catch (...) {
tm_->get_sm()->dec(p.first.get_location());
throw;
}
return p.second;
}
void step(transaction_manager::write_ref b) { void step(transaction_manager::write_ref b) {
spine_.push_back(b); spine_.push_back(b);
if (spine_.size() == 1) if (spine_.size() == 1)

View File

@ -1,4 +1,6 @@
#include "btree.h" #include "btree.h"
#include "checksum.h"
#include "transaction_manager.h" #include "transaction_manager.h"
#include <iostream> #include <iostream>
@ -9,6 +11,62 @@ using namespace std;
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace {
struct btree_node_validator : public block_manager<>::validator {
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
disk_node const *data = reinterpret_cast<disk_node const *>(&b);
node_header const *n = &data->header;
crc32c sum(BTREE_CSUM_XOR);
sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t));
if (sum.get_sum() != to_cpu<uint32_t>(n->csum))
throw runtime_error("bad checksum in btree node");
if (to_cpu<uint64_t>(n->blocknr) != location)
throw runtime_error("bad block nr in btree node");
}
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
disk_node *data = reinterpret_cast<disk_node *>(&b);
node_header *n = &data->header;
n->blocknr = to_disk<base::__le64, uint64_t>(location);
crc32c sum(BTREE_CSUM_XOR);
sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t));
n->csum = to_disk<base::__le32>(sum.get_sum());
}
};
block_manager<>::validator::ptr
btree_validator() {
return block_manager<>::validator::ptr(new btree_node_validator);
}
}
//----------------------------------------------------------------
inline void
ro_spine::step(block_address b)
{
spine_.push_back(tm_->read_lock(b, btree_validator()));
if (spine_.size() > 2)
spine_.pop_front();
}
inline bool
shadow_spine::step(block_address b)
{
pair<write_ref, bool> p = tm_->shadow(b, btree_validator());
try {
step(p.first);
} catch (...) {
tm_->get_sm()->dec(p.first.get_location());
throw;
}
return p.second;
}
//----------------------------------------------------------------
template <typename ValueTraits> template <typename ValueTraits>
node_ref<ValueTraits>::node_ref(block_address location, disk_node *raw) node_ref<ValueTraits>::node_ref(block_address location, disk_node *raw)
: location_(location), : location_(location),
@ -291,7 +349,7 @@ btree(typename transaction_manager::ptr tm,
{ {
using namespace btree_detail; using namespace btree_detail;
write_ref root = tm_->new_block(); write_ref root = tm_->new_block(btree_validator());
leaf_node n = to_node<ValueTraits>(root); leaf_node n = to_node<ValueTraits>(root);
n.set_type(btree_detail::LEAF); n.set_type(btree_detail::LEAF);
@ -511,13 +569,13 @@ split_beneath(btree_detail::shadow_spine &spine,
node_type type; node_type type;
unsigned nr_left, nr_right; unsigned nr_left, nr_right;
write_ref left = tm_->new_block(); write_ref left = tm_->new_block(btree_validator());
node_ref<ValueTraits> l = to_node<ValueTraits>(left); node_ref<ValueTraits> l = to_node<ValueTraits>(left);
l.set_nr_entries(0); l.set_nr_entries(0);
l.set_max_entries(); l.set_max_entries();
l.set_value_size(sizeof(typename ValueTraits::disk_type)); l.set_value_size(sizeof(typename ValueTraits::disk_type));
write_ref right = tm_->new_block(); write_ref right = tm_->new_block(btree_validator());
node_ref<ValueTraits> r = to_node<ValueTraits>(right); node_ref<ValueTraits> r = to_node<ValueTraits>(right);
r.set_nr_entries(0); r.set_nr_entries(0);
r.set_max_entries(); r.set_max_entries();
@ -570,7 +628,7 @@ split_sibling(btree_detail::shadow_spine &spine,
node_ref<ValueTraits> l = spine.template get_node<ValueTraits>(); node_ref<ValueTraits> l = spine.template get_node<ValueTraits>();
block_address left = spine.get_block(); block_address left = spine.get_block();
write_ref right = tm_->new_block(); write_ref right = tm_->new_block(btree_validator());
node_ref<ValueTraits> r = to_node<ValueTraits>(right); node_ref<ValueTraits> r = to_node<ValueTraits>(right);
unsigned nr_left = l.get_nr_entries() / 2; unsigned nr_left = l.get_nr_entries() / 2;

View File

@ -5,7 +5,6 @@
#include "checksum.h" #include "checksum.h"
#include "error_set.h" #include "error_set.h"
#include "hex_dump.h"
#include <sstream> #include <sstream>
#include <map> #include <map>
@ -170,7 +169,7 @@ namespace persistent_data {
std::ostringstream out; std::ostringstream out;
out << "checksum error for block " << n.get_block_nr() out << "checksum error for block " << n.get_block_nr()
<< ", sum was " << sum.get_sum() << ", sum was " << sum.get_sum()
<< ", expected " << n.get_checksum(); << ", on disk " << n.get_checksum();
errs_->add_child(out.str()); errs_->add_child(out.str());
throw runtime_error(out.str()); throw runtime_error(out.str());
} }

View File

@ -19,8 +19,27 @@ namespace {
uint32_t const VERSION = 1; uint32_t const VERSION = 1;
unsigned const METADATA_CACHE_SIZE = 1024; unsigned const METADATA_CACHE_SIZE = 1024;
unsigned const SECTOR_TO_BLOCK_SHIFT = 3; unsigned const SECTOR_TO_BLOCK_SHIFT = 3;
uint32_t const SUPERBLOCK_CSUM_SEED = 160774;
block_address get_nr_blocks(string const &path) { struct superblock_validator : public block_manager<>::validator {
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&b);
crc32c sum(SUPERBLOCK_CSUM_SEED);
sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t));
if (sum.get_sum() != to_cpu<uint32_t>(sbd->csum_))
throw runtime_error("bad checksum in superblock");
}
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
superblock_disk *sbd = reinterpret_cast<superblock_disk *>(&b);
crc32c sum(SUPERBLOCK_CSUM_SEED);
sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t));
sbd->csum_ = to_disk<base::__le32>(sum.get_sum());
}
};
block_address
get_nr_blocks(string const &path) {
struct stat info; struct stat info;
block_address nr_blocks; block_address nr_blocks;
@ -52,55 +71,93 @@ namespace {
} }
transaction_manager::ptr transaction_manager::ptr
open_tm(string const &dev_path) { open_tm(string const &dev_path, bool writeable) {
block_address nr_blocks = get_nr_blocks(dev_path); block_address nr_blocks = get_nr_blocks(dev_path);
block_manager<>::ptr bm(new block_manager<>(dev_path, nr_blocks, 8)); block_manager<>::ptr bm(new block_manager<>(dev_path, nr_blocks, 1, writeable));
space_map::ptr sm(new core_map(nr_blocks)); space_map::ptr sm(new core_map(nr_blocks));
sm->inc(SUPERBLOCK_LOCATION);
transaction_manager::ptr tm(new transaction_manager(bm, sm)); transaction_manager::ptr tm(new transaction_manager(bm, sm));
return tm; return tm;
} }
superblock read_superblock(block_manager<>::ptr bm) { superblock
read_superblock(block_manager<>::ptr bm) {
superblock sb; superblock sb;
block_manager<>::read_ref r = bm->read_lock(SUPERBLOCK_LOCATION); block_manager<>::read_ref r = bm->read_lock(SUPERBLOCK_LOCATION,
mk_validator(new superblock_validator));
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data()); superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data());
crc32c sum(160774); // FIXME: magic number
sum.append(&sbd->flags_, MD_BLOCK_SIZE - sizeof(uint32_t));
if (sum.get_sum() != to_cpu<uint32_t>(sbd->csum_)) {
ostringstream out;
out << "bad checksum in superblock, calculated "
<< sum.get_sum()
<< ", superblock contains " << to_cpu<uint32_t>(sbd->csum_);
throw runtime_error(out.str());
}
superblock_traits::unpack(*sbd, sb); superblock_traits::unpack(*sbd, sb);
return sb; return sb;
} }
void
copy_space_maps(space_map::ptr lhs, space_map::ptr rhs) {
for (block_address b = 0; b < rhs->get_nr_blocks(); b++) {
uint32_t count = rhs->get_count(b);
if (count > 0)
lhs->set_count(b, rhs->get_count(b));
}
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
metadata::metadata(std::string const &dev_path, open_type ot) metadata::metadata(std::string const &dev_path, open_type ot,
: tm_(open_tm(dev_path)), sector_t data_block_size, block_address nr_data_blocks)
sb_(read_superblock(tm_->get_bm())),
metadata_sm_(open_metadata_sm(tm_, static_cast<void *>(&sb_.metadata_space_map_root_))),
data_sm_(open_disk_sm(tm_, static_cast<void *>(&sb_.data_space_map_root_))),
details_(new detail_tree(tm_, sb_.device_details_root_, device_details_traits::ref_counter())),
mappings_top_level_(new dev_tree(tm_, sb_.data_mapping_root_, mtree_ref_counter(tm_))),
mappings_(new mapping_tree(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)))
{ {
tm_->set_sm(open_metadata_sm(tm_, sb_.metadata_space_map_root_)); switch (ot) {
} case OPEN:
tm_ = open_tm(dev_path, false);
sb_ = read_superblock(tm_->get_bm());
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_ = detail_tree::ptr(new detail_tree(tm_, sb_.device_details_root_, device_details_traits::ref_counter()));
mappings_top_level_ = dev_tree::ptr(new dev_tree(tm_, sb_.data_mapping_root_, mtree_ref_counter(tm_)));
mappings_ = mapping_tree::ptr(new mapping_tree(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)));
break;
case CREATE:
tm_ = open_tm(dev_path, true);
space_map::ptr core = tm_->get_sm();
metadata_sm_ = create_metadata_sm(tm_, tm_->get_bm()->get_nr_blocks());
copy_space_maps(metadata_sm_, core);
tm_->set_sm(metadata_sm_);
data_sm_ = create_disk_sm(tm_, nr_data_blocks);
details_ = detail_tree::ptr(new detail_tree(tm_, device_details_traits::ref_counter()));
mappings_ = mapping_tree::ptr(new mapping_tree(tm_, block_time_ref_counter(data_sm_)));
mappings_top_level_ = dev_tree::ptr(new dev_tree(tm_, mappings_->get_root(), mtree_ref_counter(tm_)));
#if 0
::memset(&sb_, 0, sizeof(sb_)); ::memset(&sb_, 0, sizeof(sb_));
sb_.data_mapping_root_ = mappings_.get_root(); sb_.magic_ = SUPERBLOCK_MAGIC;
sb_.device_details_root_ = details_.get_root(); sb_.data_mapping_root_ = mappings_->get_root();
sb_.device_details_root_ = details_->get_root();
sb_.data_block_size_ = data_block_size;
sb_.metadata_block_size_ = MD_BLOCK_SIZE; 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
break;
}
}
namespace {
void print_superblock(superblock const &sb) {
using namespace std;
cerr << "superblock " << sb.csum_ << endl
<< "flags " << sb.flags_ << endl
<< "blocknr " << sb.blocknr_ << endl
<< "transaction id " << sb.trans_id_ << endl
<< "data mapping root " << sb.data_mapping_root_ << endl
<< "details root " << sb.device_details_root_ << endl
<< "data block size " << sb.data_block_size_ << endl
<< "metadata block size " << sb.metadata_block_size_ << endl
<< "metadata nr blocks " << sb.metadata_nr_blocks_ << endl
;
}
}
void void
metadata::commit() metadata::commit()
@ -108,9 +165,16 @@ metadata::commit()
sb_.data_mapping_root_ = mappings_->get_root(); sb_.data_mapping_root_ = mappings_->get_root();
sb_.device_details_root_ = details_->get_root(); sb_.device_details_root_ = details_->get_root();
// FIXME: commit and copy the space map roots data_sm_->commit();
data_sm_->copy_root(&sb_.data_space_map_root_, sizeof(sb_.data_space_map_root_));
write_ref superblock = tm_->get_bm()->superblock(SUPERBLOCK_LOCATION); metadata_sm_->commit();
metadata_sm_->copy_root(&sb_.metadata_space_map_root_, sizeof(sb_.metadata_space_map_root_));
print_superblock(sb_);
superblock_validator v;
write_ref superblock = tm_->get_bm()->superblock_zero(SUPERBLOCK_LOCATION,
mk_validator(new superblock_validator()));
superblock_disk *disk = reinterpret_cast<superblock_disk *>(superblock.data()); superblock_disk *disk = reinterpret_cast<superblock_disk *>(superblock.data());
superblock_traits::pack(sb_, *disk); superblock_traits::pack(sb_, *disk);
} }

View File

@ -129,7 +129,9 @@ namespace thin_provisioning {
OPEN OPEN
}; };
metadata(std::string const &dev_path, open_type ot); metadata(std::string const &dev_path, open_type ot,
sector_t data_block_size = 128,
block_address nr_data_blocks = 0); // Only used if CREATE
void commit(); void commit();

View File

@ -134,10 +134,11 @@ thin_provisioning::metadata_check(metadata::ptr md)
mapping_validator::ptr mv(new mapping_validator(metadata_counter, mapping_validator::ptr mv(new mapping_validator(metadata_counter,
data_counter)); data_counter));
md->mappings_->visit(mv); md->mappings_->visit(mv);
set<uint64_t> const &mapped_devs = mv->get_devices();
set<uint64_t> const &mapped_devs = mv->get_devices();
details_validator::ptr dv(new details_validator(metadata_counter)); details_validator::ptr dv(new details_validator(metadata_counter));
md->details_->visit(dv); md->details_->visit(dv);
set<uint64_t> const &details_devs = dv->get_devices(); set<uint64_t> const &details_devs = dv->get_devices();
for (set<uint64_t>::const_iterator it = mapped_devs.begin(); it != mapped_devs.end(); ++it) for (set<uint64_t>::const_iterator it = mapped_devs.begin(); it != mapped_devs.end(); ++it)
@ -150,6 +151,7 @@ thin_provisioning::metadata_check(metadata::ptr md)
metadata_counter.inc(SUPERBLOCK_LOCATION); metadata_counter.inc(SUPERBLOCK_LOCATION);
md->metadata_sm_->check(metadata_counter); md->metadata_sm_->check(metadata_counter);
md->data_sm_->check(metadata_counter); md->data_sm_->check(metadata_counter);
errors->add_child(check_ref_counts("Errors in metadata block reference counts", errors->add_child(check_ref_counts("Errors in metadata block reference counts",
metadata_counter, md->metadata_sm_)); metadata_counter, md->metadata_sm_));

View File

@ -65,6 +65,7 @@ namespace thin_provisioning {
__le64 metadata_nr_blocks_; __le64 metadata_nr_blocks_;
__le32 compat_flags_; __le32 compat_flags_;
__le32 compat_ro_flags_;
__le32 incompat_flags_; __le32 incompat_flags_;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -97,6 +98,7 @@ namespace thin_provisioning {
uint64_t metadata_nr_blocks_; uint64_t metadata_nr_blocks_;
uint32_t compat_flags_; uint32_t compat_flags_;
uint32_t compat_ro_flags_;
uint32_t incompat_flags_; uint32_t incompat_flags_;
}; };

View File

@ -38,7 +38,6 @@ namespace {
throw runtime_error("missing superblock"); throw runtime_error("missing superblock");
md_->commit(); md_->commit();
in_superblock_ = false; in_superblock_ = false;
} }
@ -64,7 +63,6 @@ namespace {
block_time_ref_counter(md_->data_sm_))); block_time_ref_counter(md_->data_sm_)));
md_->mappings_top_level_->insert(key, new_tree->get_root()); md_->mappings_top_level_->insert(key, new_tree->get_root());
md_->mappings_->set_root(md_->mappings_top_level_->get_root()); // FIXME: ugly md_->mappings_->set_root(md_->mappings_top_level_->get_root()); // FIXME: ugly
current_device_ = optional<uint32_t>(dev); current_device_ = optional<uint32_t>(dev);
} }
@ -99,12 +97,14 @@ namespace {
bt.time_ = time; bt.time_ = time;
md_->mappings_->insert(key, bt); md_->mappings_->insert(key, bt);
md_->mappings_top_level_->set_root(md_->mappings_->get_root()); md_->mappings_top_level_->set_root(md_->mappings_->get_root());
md_->data_sm_->inc(data_block);
} }
private: private:
bool device_exists(thin_dev_t dev) const { bool device_exists(thin_dev_t dev) const {
uint64_t key[1] = {dev}; uint64_t key[1] = {dev};
return md_->details_->lookup(key); detail_tree::maybe_value v = md_->details_->lookup(key);
return v;
} }
metadata::ptr md_; metadata::ptr md_;

View File

@ -1,5 +1,6 @@
#include "space_map_disk.h" #include "space_map_disk.h"
#include "checksum.h"
#include "endian_utils.h" #include "endian_utils.h"
#include "math_utils.h" #include "math_utils.h"
#include "space_map_disk_structures.h" #include "space_map_disk_structures.h"
@ -14,6 +15,35 @@ using namespace sm_disk_detail;
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace { namespace {
uint64_t const BITMAP_CSUM_XOR = 240779;
struct bitmap_block_validator : public block_manager<>::validator {
virtual void check(block_manager<>::const_buffer &b, block_address location) const {
bitmap_header const *data = reinterpret_cast<bitmap_header const *>(&b);
crc32c sum(BITMAP_CSUM_XOR);
sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t));
if (sum.get_sum() != to_cpu<uint32_t>(data->csum))
throw runtime_error("bad checksum in space map bitmap");
if (to_cpu<uint64_t>(data->blocknr) != location)
throw runtime_error("bad block nr in space map bitmap");
}
virtual void prepare(block_manager<>::buffer &b, block_address location) const {
bitmap_header *data = reinterpret_cast<bitmap_header *>(&b);
data->blocknr = to_disk<base::__le64, uint64_t>(location);
crc32c sum(BITMAP_CSUM_XOR);
sum.append(&data->not_used, MD_BLOCK_SIZE - sizeof(uint32_t));
data->csum = to_disk<base::__le32>(sum.get_sum());
}
};
block_manager<>::validator::ptr
bitmap_validator() {
return block_manager<>::validator::ptr(new bitmap_block_validator());
}
class bitmap { class bitmap {
public: public:
typedef transaction_manager::read_ref read_ref; typedef transaction_manager::read_ref read_ref;
@ -64,16 +94,16 @@ namespace {
} }
} }
unsigned find_free(unsigned end) { boost::optional<unsigned> find_free(unsigned begin, unsigned end) {
for (unsigned i = ie_.none_free_before_; i < end; i++) { for (unsigned i = max(begin, ie_.none_free_before_); i < end; i++) {
if (lookup(i) == 0) { if (lookup(i) == 0) {
insert(i, 1); insert(i, 1);
ie_.none_free_before_ = i + 1; ie_.none_free_before_ = i + 1;
return i; return boost::optional<unsigned>(i);
} }
} }
throw std::runtime_error("no free entry in bitmap"); return boost::optional<unsigned>();
} }
index_entry const &get_ie() const { index_entry const &get_ie() const {
@ -213,21 +243,24 @@ namespace {
} }
block_address new_block() { block_address new_block() {
// silly to always start searching from the // FIXME: silly to always start searching from the
// beginning. // beginning.
block_address nr_indexes = div_up<block_address>(nr_blocks_, entries_per_block_); block_address nr_indexes = div_up<block_address>(nr_blocks_, entries_per_block_);
for (block_address index = 0; index < nr_indexes; index++) { for (block_address index = 0; index < nr_indexes; index++) {
index_entry ie = find_ie(index); index_entry ie = find_ie(index);
bitmap bm(tm_, ie); bitmap bm(tm_, ie);
block_address b = bm.find_free((index == nr_indexes - 1) ? optional<unsigned> maybe_b = bm.find_free(0, (index == nr_indexes - 1) ?
nr_blocks_ % entries_per_block_ : entries_per_block_); nr_blocks_ % entries_per_block_ : entries_per_block_);
save_ie(b, bm.get_ie()); if (maybe_b) {
block_address b = *maybe_b;
save_ie(index, bm.get_ie());
nr_allocated_++; nr_allocated_++;
b = (index * entries_per_block_) + b; b = (index * entries_per_block_) + b;
assert(get_count(b) == 1); assert(get_count(b) == 1);
return b; return b;
} }
}
throw runtime_error("out of space"); throw runtime_error("out of space");
} }
@ -242,9 +275,9 @@ namespace {
block_address bitmap_count = div_up<block_address>(nr_blocks, entries_per_block_); block_address bitmap_count = div_up<block_address>(nr_blocks, entries_per_block_);
block_address old_bitmap_count = div_up<block_address>(nr_blocks_, entries_per_block_); block_address old_bitmap_count = div_up<block_address>(nr_blocks_, entries_per_block_);
for (block_address i = old_bitmap_count; i < bitmap_count; i++) { for (block_address i = old_bitmap_count; i < bitmap_count; i++) {
write_ref wr = tm_->new_block(); write_ref wr = tm_->new_block(bitmap_validator());
struct index_entry ie; index_entry ie;
ie.blocknr_ = wr.get_location(); ie.blocknr_ = wr.get_location();
ie.nr_free_ = i == (bitmap_count - 1) ? ie.nr_free_ = i == (bitmap_count - 1) ?
(nr_blocks % entries_per_block_) : entries_per_block_; (nr_blocks % entries_per_block_) : entries_per_block_;
@ -324,7 +357,7 @@ namespace {
index_entry ie = find_ie(b / entries_per_block_); index_entry ie = find_ie(b / entries_per_block_);
bitmap bm(tm_, ie); bitmap bm(tm_, ie);
bm.insert(b % entries_per_block_, n); bm.insert(b % entries_per_block_, n);
save_ie(b, bm.get_ie()); save_ie(b / entries_per_block_, bm.get_ie());
} }
ref_t lookup_ref_count(block_address b) const { ref_t lookup_ref_count(block_address b) const {
@ -436,6 +469,7 @@ namespace {
v.nr_allocated_ = sm_disk_base::get_nr_allocated(); v.nr_allocated_ = sm_disk_base::get_nr_allocated();
v.bitmap_root_ = bitmaps_.get_root(); v.bitmap_root_ = bitmaps_.get_root();
v.ref_count_root_ = sm_disk_base::get_ref_count_root(); v.ref_count_root_ = sm_disk_base::get_ref_count_root();
sm_root_traits::pack(v, d); sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d)); ::memcpy(dest, &d, sizeof(d));
} }
@ -477,8 +511,8 @@ namespace {
sm_metadata(transaction_manager::ptr tm) sm_metadata(transaction_manager::ptr tm)
: sm_disk_base(tm), : sm_disk_base(tm),
bitmap_root_(tm->get_sm()->new_block()), // FIXME: add bitmap_index validator
entries_(MAX_METADATA_BITMAPS) { entries_(MAX_METADATA_BITMAPS) {
// FIXME: allocate a new bitmap root
} }
sm_metadata(transaction_manager::ptr tm, sm_metadata(transaction_manager::ptr tm,
@ -505,6 +539,7 @@ namespace {
v.nr_allocated_ = sm_disk_base::get_nr_allocated(); v.nr_allocated_ = sm_disk_base::get_nr_allocated();
v.bitmap_root_ = bitmap_root_; v.bitmap_root_ = bitmap_root_;
v.ref_count_root_ = sm_disk_base::get_ref_count_root(); v.ref_count_root_ = sm_disk_base::get_ref_count_root();
sm_root_traits::pack(v, d); sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d)); ::memcpy(dest, &d, sizeof(d));
} }
@ -582,13 +617,22 @@ persistent_data::open_disk_sm(transaction_manager::ptr tm, void *root)
} }
checked_space_map::ptr checked_space_map::ptr
persistent_data::open_metadata_sm(transaction_manager::ptr tm, void * root) persistent_data::create_metadata_sm(transaction_manager::ptr tm, block_address nr_blocks)
{
checked_space_map::ptr sm(new sm_metadata(tm));
sm->extend(nr_blocks);
return sm;
}
checked_space_map::ptr
persistent_data::open_metadata_sm(transaction_manager::ptr tm, void *root)
{ {
sm_root_disk d; sm_root_disk d;
sm_root v; sm_root v;
::memcpy(&d, root, sizeof(d)); ::memcpy(&d, root, sizeof(d));
sm_root_traits::unpack(d, v); sm_root_traits::unpack(d, v);
return checked_space_map::ptr(new sm_metadata(tm, v)); return checked_space_map::ptr(new sm_metadata(tm, v));
} }

View File

@ -21,7 +21,10 @@ namespace persistent_data {
open_disk_sm(transaction_manager::ptr tm, void *root); open_disk_sm(transaction_manager::ptr tm, void *root);
checked_space_map::ptr checked_space_map::ptr
open_metadata_sm(transaction_manager::ptr tm, void * root); create_metadata_sm(transaction_manager::ptr tm, block_address nr_blocks);
checked_space_map::ptr
open_metadata_sm(transaction_manager::ptr tm, void *root);
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -18,16 +18,21 @@ namespace po = boost::program_options;
namespace { namespace {
void restore(string const &backup_file, string const &dev) { void restore(string const &backup_file, string const &dev) {
metadata::ptr md(new metadata(dev, metadata::CREATE)); // FIXME: hard coded
block_address const NR_BLOCKS = 100000;
metadata::ptr md(new metadata(dev, metadata::CREATE, 128, NR_BLOCKS));
emitter::ptr restorer = create_restore_emitter(md); emitter::ptr restorer = create_restore_emitter(md);
ifstream in(backup_file.c_str(), ifstream::in); ifstream in(backup_file.c_str(), ifstream::in);
try { // FIXME:
//try {
parse_xml(in, restorer); parse_xml(in, restorer);
#if 0
} catch (...) { } catch (...) {
in.close(); in.close();
throw; throw;
} }
#endif
} }
void usage(po::options_description const &desc) { void usage(po::options_description const &desc) {

View File

@ -98,8 +98,8 @@ pair<transaction_manager::write_ref, bool>
transaction_manager::shadow(block_address orig, validator v) transaction_manager::shadow(block_address orig, validator v)
{ {
if (is_shadow(orig) && if (is_shadow(orig) &&
sm_->count_possibly_greater_than_one(orig)) !sm_->count_possibly_greater_than_one(orig))
return make_pair(bm_->write_lock(orig), false); return make_pair(bm_->write_lock(orig, v), false);
read_ref src = bm_->read_lock(orig, v); read_ref src = bm_->read_lock(orig, v);
write_ref dest = bm_->write_lock_zero(sm_->new_block(), v); write_ref dest = bm_->write_lock_zero(sm_->new_block(), v);

View File

@ -1,5 +1,5 @@
#include "space_map_disk.h" #include "space_map_disk.h"
#include "core_map.h" #include "space_map_core.h"
#define BOOST_TEST_MODULE SpaceMapDiskTests #define BOOST_TEST_MODULE SpaceMapDiskTests
#include <boost/test/included/unit_test.hpp> #include <boost/test/included/unit_test.hpp>
@ -11,13 +11,14 @@ using namespace persistent_data;
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace { namespace {
block_address const NR_BLOCKS = 10237; block_address const NR_BLOCKS = 1000; // FIXME: bump up
block_address const SUPERBLOCK = 0; block_address const SUPERBLOCK = 0;
block_address const MAX_LOCKS = 8;
transaction_manager::ptr transaction_manager::ptr
create_tm() { create_tm() {
block_manager<>::ptr bm( block_manager<>::ptr bm(
new block_manager<>("./test.data", NR_BLOCKS)); new block_manager<>("./test.data", NR_BLOCKS, MAX_LOCKS, true));
space_map::ptr sm(new core_map(1024)); space_map::ptr sm(new core_map(1024));
transaction_manager::ptr tm( transaction_manager::ptr tm(
new transaction_manager(bm, sm)); new transaction_manager(bm, sm));
@ -26,27 +27,26 @@ namespace {
persistent_space_map::ptr persistent_space_map::ptr
create_sm_disk() { create_sm_disk() {
auto tm = create_tm(); transaction_manager::ptr tm = create_tm();
return persistent_data::create_disk_sm(tm, NR_BLOCKS); return persistent_data::create_disk_sm(tm, NR_BLOCKS);
} }
persistent_space_map::ptr
create_sm_metadata() {
transaction_manager::ptr tm = create_tm();
return persistent_data::create_metadata_sm(tm, NR_BLOCKS);
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------
BOOST_AUTO_TEST_CASE(reopen_an_sm) void _test_get_nr_blocks(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
}
BOOST_AUTO_TEST_CASE(test_get_nr_blocks)
{
auto sm = create_sm_disk();
BOOST_CHECK_EQUAL(sm->get_nr_blocks(), NR_BLOCKS); BOOST_CHECK_EQUAL(sm->get_nr_blocks(), NR_BLOCKS);
} }
BOOST_AUTO_TEST_CASE(test_get_nr_free) void _test_get_nr_free(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
BOOST_CHECK_EQUAL(sm->get_nr_free(), NR_BLOCKS); BOOST_CHECK_EQUAL(sm->get_nr_free(), NR_BLOCKS);
for (unsigned i = 0; i < NR_BLOCKS; i++) { for (unsigned i = 0; i < NR_BLOCKS; i++) {
@ -60,18 +60,16 @@ BOOST_AUTO_TEST_CASE(test_get_nr_free)
} }
} }
BOOST_AUTO_TEST_CASE(test_throws_no_space) void _test_throws_no_space(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
for (unsigned i = 0; i < NR_BLOCKS; i++) for (unsigned i = 0; i < NR_BLOCKS; i++)
sm->new_block(); sm->new_block();
BOOST_CHECK_THROW(sm->new_block(), std::runtime_error); BOOST_CHECK_THROW(sm->new_block(), std::runtime_error);
} }
BOOST_AUTO_TEST_CASE(test_inc_and_dec) void _test_inc_and_dec(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
block_address b = 63; block_address b = 63;
for (unsigned i = 0; i < 50; i++) { for (unsigned i = 0; i < 50; i++) {
@ -85,9 +83,8 @@ BOOST_AUTO_TEST_CASE(test_inc_and_dec)
} }
} }
BOOST_AUTO_TEST_CASE(test_not_allocated_twice) void _test_not_allocated_twice(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
block_address b = sm->new_block(); block_address b = sm->new_block();
try { try {
@ -97,16 +94,14 @@ BOOST_AUTO_TEST_CASE(test_not_allocated_twice)
} }
} }
BOOST_AUTO_TEST_CASE(test_set_count) void _test_set_count(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
sm->set_count(43, 5); sm->set_count(43, 5);
BOOST_CHECK_EQUAL(sm->get_count(43), 5); BOOST_CHECK_EQUAL(sm->get_count(43), 5);
} }
BOOST_AUTO_TEST_CASE(test_set_effects_nr_allocated) void _test_set_affects_nr_allocated(space_map::ptr sm)
{ {
auto sm = create_sm_disk();
for (unsigned i = 0; i < NR_BLOCKS; i++) { for (unsigned i = 0; i < NR_BLOCKS; i++) {
sm->set_count(i, 1); sm->set_count(i, 1);
BOOST_CHECK_EQUAL(sm->get_nr_free(), NR_BLOCKS - i - 1); BOOST_CHECK_EQUAL(sm->get_nr_free(), NR_BLOCKS - i - 1);
@ -118,24 +113,143 @@ BOOST_AUTO_TEST_CASE(test_set_effects_nr_allocated)
} }
} }
BOOST_AUTO_TEST_CASE(test_reopen) //----------------------------------------------------------------
#if 0
BOOST_AUTO_TEST_CASE(reopen_an_sm)
{
space_map::ptr sm = create_sm_disk();
}
#endif
BOOST_AUTO_TEST_CASE(test_disk_get_nr_blocks)
{
space_map::ptr sm = create_sm_disk();
_test_get_nr_blocks(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_get_nr_free)
{
space_map::ptr sm = create_sm_disk();
_test_get_nr_free(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_throws_no_space)
{
space_map::ptr sm = create_sm_disk();
_test_throws_no_space(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_inc_and_dec)
{
space_map::ptr sm = create_sm_disk();
_test_inc_and_dec(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_not_allocated_twice)
{
space_map::ptr sm = create_sm_disk();
_test_not_allocated_twice(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_set_count)
{
space_map::ptr sm = create_sm_disk();
_test_set_count(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_set_affects_nr_allocated)
{
space_map::ptr sm = create_sm_disk();
_test_set_affects_nr_allocated(sm);
}
BOOST_AUTO_TEST_CASE(test_disk_reopen)
{ {
unsigned char buffer[128]; unsigned char buffer[128];
{ {
auto sm = create_sm_disk(); persistent_space_map::ptr sm = create_sm_disk();
for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++) { for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++) {
sm->inc(i); sm->inc(i);
} }
sm->commit();
BOOST_CHECK(sm->root_size() <= sizeof(buffer)); BOOST_CHECK(sm->root_size() <= sizeof(buffer));
sm->copy_root(buffer, sizeof(buffer)); sm->copy_root(buffer, sizeof(buffer));
} }
{ {
auto tm = create_tm(); transaction_manager::ptr tm = create_tm();
auto sm = persistent_data::open_disk_sm(tm, buffer); persistent_space_map::ptr sm = persistent_data::open_disk_sm(tm, buffer);
for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++)
BOOST_CHECK_EQUAL(sm->get_count(i), 1);
}
}
//----------------------------------------------------------------
BOOST_AUTO_TEST_CASE(test_metadata_get_nr_blocks)
{
space_map::ptr sm = create_sm_metadata();
_test_get_nr_blocks(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_get_nr_free)
{
space_map::ptr sm = create_sm_metadata();
_test_get_nr_free(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_throws_no_space)
{
space_map::ptr sm = create_sm_metadata();
_test_throws_no_space(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_inc_and_dec)
{
space_map::ptr sm = create_sm_metadata();
_test_inc_and_dec(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_not_allocated_twice)
{
space_map::ptr sm = create_sm_metadata();
_test_not_allocated_twice(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_set_count)
{
space_map::ptr sm = create_sm_metadata();
_test_set_count(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_set_affects_nr_allocated)
{
space_map::ptr sm = create_sm_metadata();
_test_set_affects_nr_allocated(sm);
}
BOOST_AUTO_TEST_CASE(test_metadata_reopen)
{
unsigned char buffer[128];
{
persistent_space_map::ptr sm = create_sm_metadata();
for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++) {
sm->inc(i);
}
sm->commit();
BOOST_CHECK(sm->root_size() <= sizeof(buffer));
sm->copy_root(buffer, sizeof(buffer));
}
{
transaction_manager::ptr tm = create_tm();
persistent_space_map::ptr sm = persistent_data::open_metadata_sm(tm, buffer);
for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++) for (unsigned i = 0, step = 1; i < NR_BLOCKS; i += step, step++)
BOOST_CHECK_EQUAL(sm->get_count(i), 1); BOOST_CHECK_EQUAL(sm->get_count(i), 1);