thin_restore works (well thin_repair thinks it does).
This commit is contained in:
parent
9cee046594
commit
6bff674720
8
Makefile
8
Makefile
@ -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))
|
||||||
|
6
block.h
6
block.h
@ -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"
|
||||||
|
23
block.tcc
23
block.tcc
@ -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
18
btree.h
@ -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)
|
||||||
|
66
btree.tcc
66
btree.tcc
@ -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;
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
132
metadata.cc
132
metadata.cc
@ -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_)));
|
||||||
|
|
||||||
|
::memset(&sb_, 0, sizeof(sb_));
|
||||||
|
sb_.magic_ = SUPERBLOCK_MAGIC;
|
||||||
|
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_nr_blocks_ = tm_->get_bm()->get_nr_blocks();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
namespace {
|
||||||
::memset(&sb_, 0, sizeof(sb_));
|
void print_superblock(superblock const &sb) {
|
||||||
sb_.data_mapping_root_ = mappings_.get_root();
|
using namespace std;
|
||||||
sb_.device_details_root_ = details_.get_root();
|
|
||||||
sb_.metadata_block_size_ = MD_BLOCK_SIZE;
|
cerr << "superblock " << sb.csum_ << endl
|
||||||
sb_.metadata_nr_blocks_ = tm_->get_bm()->get_nr_blocks();
|
<< "flags " << sb.flags_ << endl
|
||||||
#endif
|
<< "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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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_));
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
|
@ -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,20 +243,23 @@ 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) {
|
||||||
nr_allocated_++;
|
block_address b = *maybe_b;
|
||||||
b = (index * entries_per_block_) + b;
|
save_ie(index, bm.get_ie());
|
||||||
assert(get_count(b) == 1);
|
nr_allocated_++;
|
||||||
return b;
|
b = (index * entries_per_block_) + b;
|
||||||
|
assert(get_count(b) == 1);
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user