Having the block size as a template parameter makes all the code very

verbose, and we're not likely to change it.  So this change removes
that template arg from everything except the block manager.
This commit is contained in:
Joe Thornber 2011-08-31 12:48:41 +01:00
parent a285fee757
commit 9cfdbfb8cc
15 changed files with 799 additions and 807 deletions

View File

@ -2,7 +2,9 @@ SOURCE=\
endian_utils.cc \ endian_utils.cc \
error_set.cc \ error_set.cc \
metadata.cc \ metadata.cc \
metadata_disk_structures.cc metadata_disk_structures.cc \
space_map_disk.cc \
transaction_manager.cc
TEST_SOURCE=\ TEST_SOURCE=\
unit-tests/block_t.cc \ unit-tests/block_t.cc \
@ -48,16 +50,16 @@ thin_repair: $(OBJECTS) thin_repair.o
unit-tests/block_t: unit-tests/block_t.o unit-tests/block_t: unit-tests/block_t.o
g++ $(CPPFLAGS) -o $@ $+ $(LIBS) g++ $(CPPFLAGS) -o $@ $+ $(LIBS)
unit-tests/btree_t: unit-tests/btree_t.o unit-tests/btree_t: unit-tests/btree_t.o $(OBJECTS)
g++ $(CPPFLAGS) -o $@ $+ $(LIBS) g++ $(CPPFLAGS) -o $@ $+ $(LIBS)
unit-tests/space_map_t: unit-tests/space_map_t.o unit-tests/space_map_t: unit-tests/space_map_t.o $(OBJECTS)
g++ $(CPPFLAGS) -o $@ $+ $(LIBS) g++ $(CPPFLAGS) -o $@ $+ $(LIBS)
unit-tests/space_map_disk_t: unit-tests/space_map_disk_t.o $(OBJECTS) unit-tests/space_map_disk_t: unit-tests/space_map_disk_t.o $(OBJECTS)
g++ $(CPPFLAGS) -o $@ $+ $(LIBS) g++ $(CPPFLAGS) -o $@ $+ $(LIBS)
unit-tests/transaction_manager_t: unit-tests/transaction_manager_t.o unit-tests/transaction_manager_t: unit-tests/transaction_manager_t.o $(OBJECTS)
g++ $(CPPFLAGS) -o $@ $+ $(LIBS) g++ $(CPPFLAGS) -o $@ $+ $(LIBS)
unit-tests/metadata_t: unit-tests/metadata_t.o $(OBJECTS) unit-tests/metadata_t: unit-tests/metadata_t.o $(OBJECTS)

View File

@ -15,6 +15,8 @@
namespace persistent_data { namespace persistent_data {
uint32_t const MD_BLOCK_SIZE = 4096;
class count_adjuster { class count_adjuster {
public: public:
count_adjuster(unsigned &c) count_adjuster(unsigned &c)
@ -32,7 +34,7 @@ namespace persistent_data {
typedef uint64_t block_address; typedef uint64_t block_address;
template <uint32_t BlockSize> template <uint32_t BlockSize = MD_BLOCK_SIZE>
class block_manager : private boost::noncopyable { class block_manager : private boost::noncopyable {
public: public:
typedef boost::shared_ptr<block_manager> ptr; typedef boost::shared_ptr<block_manager> ptr;

84
btree.h
View File

@ -69,7 +69,7 @@ namespace persistent_data {
//------------------------------------------------ //------------------------------------------------
// Class that acts as an interface over the raw little endian btree // Class that acts as an interface over the raw little endian btree
// node data. // node data.
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
class node_ref { class node_ref {
public: public:
explicit node_ref(block_address b, disk_node *raw); explicit node_ref(block_address b, disk_node *raw);
@ -142,31 +142,30 @@ namespace persistent_data {
//------------------------------------------------ //------------------------------------------------
// //
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> node_ref<ValueTraits>
to_node(typename block_manager<BlockSize>::read_ref &b) to_node(typename block_manager<>::read_ref &b)
{ {
// FIXME: this should return a const read_ref somehow. // FIXME: this should return a const read_ref somehow.
return node_ref<ValueTraits, BlockSize>( return node_ref<ValueTraits>(
b.get_location(), b.get_location(),
reinterpret_cast<disk_node *>( reinterpret_cast<disk_node *>(
const_cast<unsigned char *>(b.data()))); const_cast<unsigned char *>(b.data())));
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> node_ref<ValueTraits>
to_node(typename block_manager<BlockSize>::write_ref &b) to_node(typename block_manager<>::write_ref &b)
{ {
return node_ref<ValueTraits, BlockSize>( return node_ref<ValueTraits>(
b.get_location(), b.get_location(),
reinterpret_cast<disk_node *>( reinterpret_cast<disk_node *>(
const_cast<unsigned char *>(b.data()))); const_cast<unsigned char *>(b.data())));
} }
template <uint32_t BlockSize>
class ro_spine : private noncopyable { class ro_spine : private noncopyable {
public: public:
ro_spine(typename transaction_manager<BlockSize>::ptr tm) ro_spine(typename transaction_manager::ptr tm)
: tm_(tm) { : tm_(tm) {
} }
@ -177,22 +176,21 @@ namespace persistent_data {
} }
template <typename ValueTraits> template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> get_node() { node_ref<ValueTraits> get_node() {
return to_node<ValueTraits, BlockSize>(spine_.back()); return to_node<ValueTraits>(spine_.back());
} }
private: private:
typename transaction_manager<BlockSize>::ptr tm_; typename transaction_manager::ptr tm_;
std::list<typename block_manager<BlockSize>::read_ref> spine_; std::list<typename block_manager<>::read_ref> spine_;
}; };
template <uint32_t BlockSize>
class shadow_spine : private noncopyable { class shadow_spine : private noncopyable {
public: public:
typedef typename transaction_manager<BlockSize>::read_ref read_ref; typedef typename transaction_manager::read_ref read_ref;
typedef typename transaction_manager<BlockSize>::write_ref write_ref; typedef typename transaction_manager::write_ref write_ref;
shadow_spine(typename transaction_manager<BlockSize>::ptr tm) shadow_spine(typename transaction_manager::ptr tm)
: tm_(tm) { : tm_(tm) {
} }
@ -208,7 +206,7 @@ namespace persistent_data {
return p.second; return p.second;
} }
void step(typename transaction_manager<BlockSize>::write_ref b) { void step(typename transaction_manager::write_ref b) {
spine_.push_back(b); spine_.push_back(b);
if (spine_.size() == 1) if (spine_.size() == 1)
root_ = spine_.front().get_location(); root_ = spine_.front().get_location();
@ -221,8 +219,8 @@ namespace persistent_data {
} }
template <typename ValueTraits> template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> get_node() { node_ref<ValueTraits> get_node() {
return to_node<ValueTraits, BlockSize>(spine_.back()); return to_node<ValueTraits>(spine_.back());
} }
block_address get_block() const { block_address get_block() const {
@ -233,11 +231,11 @@ namespace persistent_data {
return spine_.size() > 1; return spine_.size() > 1;
} }
node_ref<uint64_traits, BlockSize> get_parent() { node_ref<uint64_traits> get_parent() {
if (spine_.size() < 2) if (spine_.size() < 2)
throw std::runtime_error("no parent"); throw std::runtime_error("no parent");
return to_node<uint64_traits, BlockSize>(spine_.front()); return to_node<uint64_traits>(spine_.front());
} }
block_address get_parent_location() const { block_address get_parent_location() const {
@ -249,22 +247,22 @@ namespace persistent_data {
} }
private: private:
typename transaction_manager<BlockSize>::ptr tm_; typename transaction_manager::ptr tm_;
std::list<typename block_manager<BlockSize>::write_ref> spine_; std::list<typename block_manager<>::write_ref> spine_;
block_address root_; block_address root_;
}; };
// FIXME: make a member of btree // FIXME: make a member of btree
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
optional<typename ValueTraits::value_type> optional<typename ValueTraits::value_type>
lookup_raw(ro_spine<BlockSize> &spine, block_address block, uint64_t key) { lookup_raw(ro_spine &spine, block_address block, uint64_t key) {
using namespace boost; using namespace boost;
typedef typename ValueTraits::value_type leaf_type; typedef typename ValueTraits::value_type leaf_type;
for (;;) { for (;;) {
spine.step(block); spine.step(block);
node_ref<ValueTraits, BlockSize> leaf = spine.template get_node<ValueTraits>(); node_ref<ValueTraits> leaf = spine.template get_node<ValueTraits>();
optional<unsigned> mi = leaf.exact_search(key); optional<unsigned> mi = leaf.exact_search(key);
if (!mi) if (!mi)
@ -273,30 +271,30 @@ namespace persistent_data {
if (leaf.get_type() == btree_detail::LEAF) if (leaf.get_type() == btree_detail::LEAF)
return optional<leaf_type>(leaf.value_at(*mi)); return optional<leaf_type>(leaf.value_at(*mi));
node_ref<uint64_traits, BlockSize> internal = spine.template get_node<uint64_traits>(); node_ref<uint64_traits> internal = spine.template get_node<uint64_traits>();
block = internal.value_at(*mi); block = internal.value_at(*mi);
} }
} }
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
class btree { class btree {
public: public:
typedef boost::shared_ptr<btree<Levels, ValueTraits, BlockSize> > ptr; typedef boost::shared_ptr<btree<Levels, ValueTraits> > ptr;
typedef uint64_t key[Levels]; typedef uint64_t key[Levels];
typedef typename ValueTraits::value_type value_type; typedef typename ValueTraits::value_type value_type;
typedef boost::optional<value_type> maybe_value; typedef boost::optional<value_type> maybe_value;
typedef boost::optional<std::pair<unsigned, value_type> > maybe_pair; typedef boost::optional<std::pair<unsigned, value_type> > maybe_pair;
typedef typename block_manager<BlockSize>::read_ref read_ref; typedef typename block_manager<>::read_ref read_ref;
typedef typename block_manager<BlockSize>::write_ref write_ref; typedef typename block_manager<>::write_ref write_ref;
typedef typename btree_detail::node_ref<ValueTraits, BlockSize> leaf_node; typedef typename btree_detail::node_ref<ValueTraits> leaf_node;
typedef typename btree_detail::node_ref<uint64_traits, BlockSize> internal_node; typedef typename btree_detail::node_ref<uint64_traits> internal_node;
btree(typename persistent_data::transaction_manager<BlockSize>::ptr tm, btree(typename persistent_data::transaction_manager::ptr tm,
typename ValueTraits::ref_counter rc); typename ValueTraits::ref_counter rc);
btree(typename transaction_manager<BlockSize>::ptr tm, btree(typename transaction_manager::ptr tm,
block_address root, block_address root,
typename ValueTraits::ref_counter rc); typename ValueTraits::ref_counter rc);
@ -337,22 +335,22 @@ namespace persistent_data {
private: private:
template <typename ValueTraits2> template <typename ValueTraits2>
void split_node(btree_detail::shadow_spine<BlockSize> &spine, void split_node(btree_detail::shadow_spine &spine,
block_address parent_index, block_address parent_index,
uint64_t key, uint64_t key,
bool top); bool top);
template <typename ValueTraits2> template <typename ValueTraits2>
void split_beneath(btree_detail::shadow_spine<BlockSize> &spine, uint64_t key); void split_beneath(btree_detail::shadow_spine &spine, uint64_t key);
template <typename ValueTraits2> template <typename ValueTraits2>
void split_sibling(btree_detail::shadow_spine<BlockSize> &spine, void split_sibling(btree_detail::shadow_spine &spine,
block_address parent_index, block_address parent_index,
uint64_t key); uint64_t key);
template <typename ValueTraits2> template <typename ValueTraits2>
bool bool
insert_location(btree_detail::shadow_spine<BlockSize> &spine, insert_location(btree_detail::shadow_spine &spine,
block_address block, block_address block,
uint64_t key, uint64_t key,
int *index); int *index);
@ -361,7 +359,7 @@ namespace persistent_data {
unsigned level, bool is_root, unsigned level, bool is_root,
block_address b) const; block_address b) const;
typename persistent_data::transaction_manager<BlockSize>::ptr tm_; typename persistent_data::transaction_manager::ptr tm_;
bool destroy_; bool destroy_;
block_address root_; block_address root_;
NoOpRefCounter<uint64_t> internal_rc_; NoOpRefCounter<uint64_t> internal_rc_;

249
btree.tcc
View File

@ -9,23 +9,23 @@ using namespace std;
//---------------------------------------------------------------- //----------------------------------------------------------------
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
node_ref<ValueTraits, BlockSize>::node_ref(block_address location, disk_node *raw) node_ref<ValueTraits>::node_ref(block_address location, disk_node *raw)
: location_(location), : location_(location),
raw_(raw) raw_(raw)
{ {
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
block_address block_address
node_ref<ValueTraits, BlockSize>::get_block_nr() const node_ref<ValueTraits>::get_block_nr() const
{ {
return to_cpu<uint64_t>(raw_->header.blocknr); return to_cpu<uint64_t>(raw_->header.blocknr);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
btree_detail::node_type btree_detail::node_type
node_ref<ValueTraits, BlockSize>::get_type() const node_ref<ValueTraits>::get_type() const
{ {
uint32_t flags = to_cpu<uint32_t>(raw_->header.flags); uint32_t flags = to_cpu<uint32_t>(raw_->header.flags);
if (flags & INTERNAL_NODE) if (flags & INTERNAL_NODE)
@ -36,9 +36,9 @@ node_ref<ValueTraits, BlockSize>::get_type() const
throw runtime_error("unknow node type"); throw runtime_error("unknow node type");
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_type(node_type t) node_ref<ValueTraits>::set_type(node_type t)
{ {
uint32_t flags = to_cpu<uint32_t>(raw_->header.flags); uint32_t flags = to_cpu<uint32_t>(raw_->header.flags);
switch (t) { switch (t) {
@ -53,67 +53,67 @@ node_ref<ValueTraits, BlockSize>::set_type(node_type t)
raw_->header.flags = to_disk<__le32>(flags); raw_->header.flags = to_disk<__le32>(flags);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
unsigned unsigned
node_ref<ValueTraits, BlockSize>::get_nr_entries() const node_ref<ValueTraits>::get_nr_entries() const
{ {
return to_cpu<uint32_t>(raw_->header.nr_entries); return to_cpu<uint32_t>(raw_->header.nr_entries);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_nr_entries(unsigned n) node_ref<ValueTraits>::set_nr_entries(unsigned n)
{ {
raw_->header.nr_entries = to_disk<__le32>(n); raw_->header.nr_entries = to_disk<__le32>(n);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
unsigned unsigned
node_ref<ValueTraits, BlockSize>::get_max_entries() const node_ref<ValueTraits>::get_max_entries() const
{ {
return to_cpu<uint32_t>(raw_->header.max_entries); return to_cpu<uint32_t>(raw_->header.max_entries);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_max_entries(unsigned n) node_ref<ValueTraits>::set_max_entries(unsigned n)
{ {
raw_->header.max_entries = to_disk<__le32>(n); raw_->header.max_entries = to_disk<__le32>(n);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_max_entries() node_ref<ValueTraits>::set_max_entries()
{ {
set_max_entries(calc_max_entries()); set_max_entries(calc_max_entries());
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
size_t size_t
node_ref<ValueTraits, BlockSize>::get_value_size() const node_ref<ValueTraits>::get_value_size() const
{ {
return to_cpu<uint32_t>(raw_->header.value_size); return to_cpu<uint32_t>(raw_->header.value_size);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
uint64_t uint64_t
node_ref<ValueTraits, BlockSize>::key_at(unsigned i) const node_ref<ValueTraits>::key_at(unsigned i) const
{ {
if (i >= get_nr_entries()) if (i >= get_nr_entries())
throw runtime_error("key index out of bounds"); throw runtime_error("key index out of bounds");
return to_cpu<uint64_t>(raw_->keys[i]); return to_cpu<uint64_t>(raw_->keys[i]);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_key(unsigned i, uint64_t k) node_ref<ValueTraits>::set_key(unsigned i, uint64_t k)
{ {
raw_->keys[i] = to_disk<__le64>(k); raw_->keys[i] = to_disk<__le64>(k);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
typename ValueTraits::value_type typename ValueTraits::value_type
node_ref<ValueTraits, BlockSize>::value_at(unsigned i) const node_ref<ValueTraits>::value_at(unsigned i) const
{ {
if (i >= get_nr_entries()) if (i >= get_nr_entries())
throw runtime_error("value index out of bounds"); throw runtime_error("value index out of bounds");
@ -127,21 +127,21 @@ node_ref<ValueTraits, BlockSize>::value_at(unsigned i) const
return v; return v;
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::set_value(unsigned i, node_ref<ValueTraits>::set_value(unsigned i,
typename ValueTraits::value_type const &v) typename ValueTraits::value_type const &v)
{ {
typename ValueTraits::disk_type d; typename ValueTraits::disk_type d;
ValueTraits::pack(v, d); ValueTraits::pack(v, d);
::memcpy(value_ptr(i), &d, sizeof(d)); ::memcpy(value_ptr(i), &d, sizeof(d));
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::insert_at(unsigned i, node_ref<ValueTraits>::insert_at(unsigned i,
uint64_t key, uint64_t key,
typename ValueTraits::value_type const &v) typename ValueTraits::value_type const &v)
{ {
unsigned n = get_nr_entries(); unsigned n = get_nr_entries();
if ((n + 1) > get_max_entries()) if ((n + 1) > get_max_entries())
@ -153,21 +153,21 @@ node_ref<ValueTraits, BlockSize>::insert_at(unsigned i,
overwrite_at(i, key, v); overwrite_at(i, key, v);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::overwrite_at(unsigned i, node_ref<ValueTraits>::overwrite_at(unsigned i,
uint64_t key, uint64_t key,
typename ValueTraits::value_type const &v) typename ValueTraits::value_type const &v)
{ {
set_key(i, key); set_key(i, key);
set_value(i, v); set_value(i, v);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void void
node_ref<ValueTraits, BlockSize>::copy_entries(node_ref const &rhs, node_ref<ValueTraits>::copy_entries(node_ref const &rhs,
unsigned begin, unsigned begin,
unsigned end) unsigned end)
{ {
unsigned count = end - begin; unsigned count = end - begin;
unsigned n = get_nr_entries(); unsigned n = get_nr_entries();
@ -179,10 +179,9 @@ node_ref<ValueTraits, BlockSize>::copy_entries(node_ref const &rhs,
::memcpy(value_ptr(n), rhs.value_ptr(begin), sizeof(typename ValueTraits::disk_type) * count); ::memcpy(value_ptr(n), rhs.value_ptr(begin), sizeof(typename ValueTraits::disk_type) * count);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
int int
node_ref<ValueTraits, BlockSize>::bsearch(uint64_t key, node_ref<ValueTraits>::bsearch(uint64_t key, int want_hi) const
int want_hi) const
{ {
int lo = -1, hi = get_nr_entries(); int lo = -1, hi = get_nr_entries();
@ -202,9 +201,9 @@ node_ref<ValueTraits, BlockSize>::bsearch(uint64_t key,
return want_hi ? hi : lo; return want_hi ? hi : lo;
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
optional<unsigned> optional<unsigned>
node_ref<ValueTraits, BlockSize>::exact_search(uint64_t key) const node_ref<ValueTraits>::exact_search(uint64_t key) const
{ {
int i = bsearch(key, 0); int i = bsearch(key, 0);
if (i < 0 || static_cast<unsigned>(i) >= get_nr_entries()) if (i < 0 || static_cast<unsigned>(i) >= get_nr_entries())
@ -213,45 +212,45 @@ node_ref<ValueTraits, BlockSize>::exact_search(uint64_t key) const
return optional<unsigned>(i); return optional<unsigned>(i);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
int int
node_ref<ValueTraits, BlockSize>::lower_bound(uint64_t key) const node_ref<ValueTraits>::lower_bound(uint64_t key) const
{ {
return bsearch(key, 0); return bsearch(key, 0);
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
unsigned unsigned
node_ref<ValueTraits, BlockSize>::calc_max_entries(void) node_ref<ValueTraits>::calc_max_entries(void)
{ {
uint32_t total; uint32_t total;
// key + value // key + value
size_t elt_size = sizeof(uint64_t) + sizeof(typename ValueTraits::disk_type); size_t elt_size = sizeof(uint64_t) + sizeof(typename ValueTraits::disk_type);
total = (BlockSize - sizeof(struct node_header)) / elt_size; total = (MD_BLOCK_SIZE - sizeof(struct node_header)) / elt_size;
return (total / 3) * 3; // rounds down return (total / 3) * 3; // rounds down
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void * void *
node_ref<ValueTraits, BlockSize>::key_ptr(unsigned i) const node_ref<ValueTraits>::key_ptr(unsigned i) const
{ {
return raw_->keys + i; return raw_->keys + i;
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
void * void *
node_ref<ValueTraits, BlockSize>::value_ptr(unsigned i) const node_ref<ValueTraits>::value_ptr(unsigned i) const
{ {
void *value_base = &raw_->keys[to_cpu<uint32_t>(raw_->header.max_entries)]; void *value_base = &raw_->keys[to_cpu<uint32_t>(raw_->header.max_entries)];
return static_cast<unsigned char *>(value_base) + return static_cast<unsigned char *>(value_base) +
sizeof(typename ValueTraits::disk_type) * i; sizeof(typename ValueTraits::disk_type) * i;
} }
template <typename ValueTraits, uint32_t BlockSize> template <typename ValueTraits>
template <typename RefCounter> template <typename RefCounter>
void void
node_ref<ValueTraits, BlockSize>::inc_children(RefCounter &rc) node_ref<ValueTraits>::inc_children(RefCounter &rc)
{ {
unsigned nr_entries = get_nr_entries(); unsigned nr_entries = get_nr_entries();
for (unsigned i = 0; i < nr_entries; i++) { for (unsigned i = 0; i < nr_entries; i++) {
@ -265,9 +264,9 @@ node_ref<ValueTraits, BlockSize>::inc_children(RefCounter &rc)
//---------------------------------------------------------------- //----------------------------------------------------------------
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
btree<Levels, ValueTraits, BlockSize>:: btree<Levels, ValueTraits>::
btree(typename transaction_manager<BlockSize>::ptr tm, btree(typename transaction_manager::ptr tm,
typename ValueTraits::ref_counter rc) typename ValueTraits::ref_counter rc)
: tm_(tm), : tm_(tm),
destroy_(false), destroy_(false),
@ -277,7 +276,7 @@ btree(typename transaction_manager<BlockSize>::ptr tm,
write_ref root = tm_->new_block(); write_ref root = tm_->new_block();
leaf_node n = to_node<ValueTraits, BlockSize>(root); leaf_node n = to_node<ValueTraits>(root);
n.set_type(btree_detail::LEAF); n.set_type(btree_detail::LEAF);
n.set_nr_entries(0); n.set_nr_entries(0);
n.set_max_entries(); n.set_max_entries();
@ -285,9 +284,9 @@ btree(typename transaction_manager<BlockSize>::ptr tm,
root_ = root.get_location(); root_ = root.get_location();
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
btree<Levels, ValueTraits, BlockSize>:: btree<Levels, ValueTraits>::
btree(typename transaction_manager<BlockSize>::ptr tm, btree(typename transaction_manager::ptr tm,
block_address root, block_address root,
typename ValueTraits::ref_counter rc) typename ValueTraits::ref_counter rc)
: tm_(tm), : tm_(tm),
@ -297,54 +296,54 @@ btree(typename transaction_manager<BlockSize>::ptr tm,
{ {
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
btree<Levels, ValueTraits, BlockSize>::~btree() btree<Levels, ValueTraits>::~btree()
{ {
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
typename btree<Levels, ValueTraits, BlockSize>::maybe_value typename btree<Levels, ValueTraits>::maybe_value
btree<Levels, ValueTraits, BlockSize>::lookup(key const &key) const btree<Levels, ValueTraits>::lookup(key const &key) const
{ {
using namespace btree_detail; using namespace btree_detail;
ro_spine<BlockSize> spine(tm_); ro_spine spine(tm_);
block_address root = root_; block_address root = root_;
for (unsigned level = 0; level < Levels - 1; ++level) { for (unsigned level = 0; level < Levels - 1; ++level) {
optional<block_address> mroot = optional<block_address> mroot =
lookup_raw<uint64_traits, BlockSize>(spine, root, key[level]); lookup_raw<uint64_traits>(spine, root, key[level]);
if (!mroot) if (!mroot)
return maybe_value(); return maybe_value();
root = *mroot; root = *mroot;
} }
return lookup_raw<ValueTraits, BlockSize>(spine, root, key[Levels - 1]); return lookup_raw<ValueTraits>(spine, root, key[Levels - 1]);
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair typename btree<Levels, ValueTraits>::maybe_pair
btree<Levels, ValueTraits, BlockSize>::lookup_le(key const &key) const btree<Levels, ValueTraits>::lookup_le(key const &key) const
{ {
using namespace btree_detail; using namespace btree_detail;
return maybe_pair(); return maybe_pair();
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair typename btree<Levels, ValueTraits>::maybe_pair
btree<Levels, ValueTraits, BlockSize>::lookup_ge(key const &key) const btree<Levels, ValueTraits>::lookup_ge(key const &key) const
{ {
using namespace btree_detail; using namespace btree_detail;
return maybe_pair(); return maybe_pair();
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>:: btree<Levels, ValueTraits>::
insert(key const &key, insert(key const &key,
typename ValueTraits::value_type const &value) typename ValueTraits::value_type const &value)
{ {
@ -352,14 +351,14 @@ insert(key const &key,
block_address block = root_; block_address block = root_;
int index = 0; // FIXME: ??? int index = 0; // FIXME: ???
shadow_spine<BlockSize> spine(tm_); shadow_spine spine(tm_);
for (unsigned level = 0; level < Levels - 1; ++level) { for (unsigned level = 0; level < Levels - 1; ++level) {
bool need_insert = insert_location<uint64_traits>(spine, block, key[level], &index); bool need_insert = insert_location<uint64_traits>(spine, block, key[level], &index);
internal_node n = spine.template get_node<uint64_traits>(); internal_node n = spine.template get_node<uint64_traits>();
if (need_insert) { if (need_insert) {
btree<Levels - 1, ValueTraits, BlockSize> new_tree(tm_, rc_); btree<Levels - 1, ValueTraits> new_tree(tm_, rc_);
n.insert_at(index, key[level], new_tree.get_root()); n.insert_at(index, key[level], new_tree.get_root());
} }
@ -376,78 +375,78 @@ insert(key const &key,
n.set_value(index, value); n.set_value(index, value);
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>::remove(key const &key) btree<Levels, ValueTraits>::remove(key const &key)
{ {
using namespace btree_detail; using namespace btree_detail;
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
block_address block_address
btree<Levels, ValueTraits, BlockSize>::get_root() const btree<Levels, ValueTraits>::get_root() const
{ {
return root_; return root_;
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>::set_root(block_address root) btree<Levels, ValueTraits>::set_root(block_address root)
{ {
using namespace btree_detail; using namespace btree_detail;
root_ = root; root_ = root;
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
typename btree<Levels, ValueTraits, BlockSize>::ptr typename btree<Levels, ValueTraits>::ptr
btree<Levels, ValueTraits, BlockSize>::clone() const btree<Levels, ValueTraits>::clone() const
{ {
using namespace btree_detail; using namespace btree_detail;
ro_spine<BlockSize> spine(tm_); ro_spine spine(tm_);
spine.step(root_); spine.step(root_);
write_ref new_root = tm_->new_block(); write_ref new_root = tm_->new_block();
internal_node o = spine.template get_node<uint64_traits>(); internal_node o = spine.template get_node<uint64_traits>();
if (o.get_type() == INTERNAL) { if (o.get_type() == INTERNAL) {
internal_node n = to_node<uint64_traits, BlockSize>(new_root); internal_node n = to_node<uint64_traits>(new_root);
::memcpy(n.raw(), o.raw(), BlockSize); ::memcpy(n.raw(), o.raw(), MD_BLOCK_SIZE);
typename uint64_traits::ref_counter rc(internal_rc_); typename uint64_traits::ref_counter rc(internal_rc_);
n.inc_children(rc); n.inc_children(rc);
} else { } else {
leaf_node n = to_node<ValueTraits, BlockSize>(new_root); leaf_node n = to_node<ValueTraits>(new_root);
::memcpy(n.raw(), o.raw(), BlockSize); ::memcpy(n.raw(), o.raw(), MD_BLOCK_SIZE);
typename ValueTraits::ref_counter rc(rc_); typename ValueTraits::ref_counter rc(rc_);
n.inc_children(rc); n.inc_children(rc);
} }
return btree<Levels, ValueTraits, BlockSize>::ptr( return btree<Levels, ValueTraits>::ptr(
new btree<Levels, ValueTraits, BlockSize>( new btree<Levels, ValueTraits>(
tm_, new_root.get_location(), rc_)); tm_, new_root.get_location(), rc_));
} }
#if 0 #if 0
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>::destroy() btree<Levels, ValueTraits>::destroy()
{ {
using namespace btree_detail; using namespace btree_detail;
} }
#endif #endif
template <unsigned Levels, typename _, uint32_t BlockSize> template <unsigned Levels, typename _>
template <typename ValueTraits> template <typename ValueTraits>
void void
btree<Levels, _, BlockSize>:: btree<Levels, _>::
split_node(btree_detail::shadow_spine<BlockSize> &spine, split_node(btree_detail::shadow_spine &spine,
block_address parent_index, block_address parent_index,
uint64_t key, uint64_t key,
bool top) bool top)
{ {
node_ref<ValueTraits, BlockSize> n = spine.template get_node<ValueTraits>(); node_ref<ValueTraits> n = spine.template get_node<ValueTraits>();
if (n.get_nr_entries() == n.get_max_entries()) { if (n.get_nr_entries() == n.get_max_entries()) {
if (top) if (top)
split_beneath<ValueTraits>(spine, key); split_beneath<ValueTraits>(spine, key);
@ -456,11 +455,11 @@ split_node(btree_detail::shadow_spine<BlockSize> &spine,
} }
} }
template <unsigned Levels, typename _, uint32_t BlockSize> template <unsigned Levels, typename _>
template <typename ValueTraits> template <typename ValueTraits>
void void
btree<Levels, _, BlockSize>:: btree<Levels, _>::
split_beneath(btree_detail::shadow_spine<BlockSize> &spine, split_beneath(btree_detail::shadow_spine &spine,
uint64_t key) uint64_t key)
{ {
using namespace btree_detail; using namespace btree_detail;
@ -469,17 +468,17 @@ split_beneath(btree_detail::shadow_spine<BlockSize> &spine,
unsigned nr_left, nr_right; unsigned nr_left, nr_right;
write_ref left = tm_->new_block(); write_ref left = tm_->new_block();
node_ref<ValueTraits, BlockSize> l = to_node<ValueTraits, BlockSize>(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();
write_ref right = tm_->new_block(); write_ref right = tm_->new_block();
node_ref<ValueTraits, BlockSize> r = to_node<ValueTraits, BlockSize>(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();
{ {
node_ref<ValueTraits, BlockSize> p = spine.template get_node<ValueTraits>(); node_ref<ValueTraits> p = spine.template get_node<ValueTraits>();
nr_left = p.get_nr_entries() / 2; nr_left = p.get_nr_entries() / 2;
nr_right = p.get_nr_entries() - nr_left; nr_right = p.get_nr_entries() - nr_left;
type = p.get_type(); type = p.get_type();
@ -508,21 +507,21 @@ split_beneath(btree_detail::shadow_spine<BlockSize> &spine,
spine.step(right); spine.step(right);
} }
template <unsigned Levels, typename _, uint32_t BlockSize> template <unsigned Levels, typename _>
template <typename ValueTraits> template <typename ValueTraits>
void void
btree<Levels, _, BlockSize>:: btree<Levels, _>::
split_sibling(btree_detail::shadow_spine<BlockSize> &spine, split_sibling(btree_detail::shadow_spine &spine,
block_address parent_index, block_address parent_index,
uint64_t key) uint64_t key)
{ {
using namespace btree_detail; using namespace btree_detail;
node_ref<ValueTraits, BlockSize> 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();
node_ref<ValueTraits, BlockSize> r = to_node<ValueTraits, BlockSize>(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;
unsigned nr_right = l.get_nr_entries() - nr_left; unsigned nr_right = l.get_nr_entries() - nr_left;
@ -545,11 +544,11 @@ split_sibling(btree_detail::shadow_spine<BlockSize> &spine,
} }
// Returns true if we need a new insertion, rather than overwrite. // Returns true if we need a new insertion, rather than overwrite.
template <unsigned Levels, typename _, uint32_t BlockSize> template <unsigned Levels, typename _>
template <typename ValueTraits> template <typename ValueTraits>
bool bool
btree<Levels, _, BlockSize>:: btree<Levels, _>::
insert_location(btree_detail::shadow_spine<BlockSize> &spine, insert_location(btree_detail::shadow_spine &spine,
block_address block, block_address block,
uint64_t key, uint64_t key,
int *index) int *index)
@ -595,7 +594,7 @@ insert_location(btree_detail::shadow_spine<BlockSize> &spine,
top = false; top = false;
} }
node_ref<ValueTraits, BlockSize> leaf = spine.template get_node<ValueTraits>(); node_ref<ValueTraits> leaf = spine.template get_node<ValueTraits>();
// FIXME: gross // FIXME: gross
if (i < 0 || leaf.key_at(i) != key) if (i < 0 || leaf.key_at(i) != key)
i++; i++;
@ -611,16 +610,16 @@ insert_location(btree_detail::shadow_spine<BlockSize> &spine,
(leaf.key_at(i) != key)); (leaf.key_at(i) != key));
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>::visit(typename visitor::ptr visitor) const btree<Levels, ValueTraits>::visit(typename visitor::ptr visitor) const
{ {
walk_tree(visitor, 0, true, root_); walk_tree(visitor, 0, true, root_);
} }
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize> template <unsigned Levels, typename ValueTraits>
void void
btree<Levels, ValueTraits, BlockSize>:: btree<Levels, ValueTraits>::
walk_tree(typename visitor::ptr visitor, walk_tree(typename visitor::ptr visitor,
unsigned level, bool is_root, unsigned level, bool is_root,
block_address b) const block_address b) const
@ -628,7 +627,7 @@ walk_tree(typename visitor::ptr visitor,
using namespace btree_detail; using namespace btree_detail;
read_ref blk = tm_->read_lock(b); read_ref blk = tm_->read_lock(b);
internal_node o = to_node<uint64_traits, BlockSize>(blk); internal_node o = to_node<uint64_traits>(blk);
if (o.get_type() == INTERNAL) { if (o.get_type() == INTERNAL) {
if (visitor->visit_internal(level, is_root, o)) if (visitor->visit_internal(level, is_root, o))
for (unsigned i = 0; i < o.get_nr_entries(); i++) for (unsigned i = 0; i < o.get_nr_entries(); i++)
@ -640,7 +639,7 @@ walk_tree(typename visitor::ptr visitor,
walk_tree(visitor, level + 1, true, o.value_at(i)); walk_tree(visitor, level + 1, true, o.value_at(i));
} else { } else {
leaf_node ov = to_node<ValueTraits, BlockSize>(blk); leaf_node ov = to_node<ValueTraits>(blk);
visitor->visit_leaf(level, is_root, ov); visitor->visit_leaf(level, is_root, ov);
} }
} }

View File

@ -64,8 +64,8 @@ namespace persistent_data {
// - checksum // - checksum
// - leaf | internal flags (this can be inferred from siblings) // - leaf | internal flags (this can be inferred from siblings)
//---------------------------------------------------------------- //----------------------------------------------------------------
template <uint32_t Levels, typename ValueTraits, uint32_t BlockSize> template <uint32_t Levels, typename ValueTraits>
class btree_validator : public btree<Levels, ValueTraits, BlockSize>::visitor { class btree_validator : public btree<Levels, ValueTraits>::visitor {
public: public:
btree_validator(block_counter &counter) btree_validator(block_counter &counter)
: counter_(counter), : counter_(counter),
@ -73,7 +73,7 @@ namespace persistent_data {
} }
bool visit_internal(unsigned level, bool is_root, bool visit_internal(unsigned level, bool is_root,
btree_detail::node_ref<uint64_traits, BlockSize> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
if (already_visited(n)) if (already_visited(n))
return false; return false;
@ -84,7 +84,7 @@ namespace persistent_data {
} }
bool visit_internal_leaf(unsigned level, bool is_root, bool visit_internal_leaf(unsigned level, bool is_root,
btree_detail::node_ref<uint64_traits, BlockSize> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
if (already_visited(n)) if (already_visited(n))
return false; return false;
@ -95,7 +95,7 @@ namespace persistent_data {
} }
bool visit_leaf(unsigned level, bool is_root, bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<ValueTraits, BlockSize> const &n) { btree_detail::node_ref<ValueTraits> const &n) {
if (already_visited(n)) if (already_visited(n))
return false; return false;
@ -143,7 +143,7 @@ namespace persistent_data {
template <typename node> template <typename node>
void check_max_entries(node const &n) const { void check_max_entries(node const &n) const {
size_t elt_size = sizeof(uint64_t) + n.get_value_size(); size_t elt_size = sizeof(uint64_t) + n.get_value_size();
if (elt_size * n.get_max_entries() + sizeof(node_header) > BlockSize) { if (elt_size * n.get_max_entries() + sizeof(node_header) > MD_BLOCK_SIZE) {
std::ostringstream out; std::ostringstream out;
out << "max entries too large: " << n.get_max_entries(); out << "max entries too large: " << n.get_max_entries();
errs_->add_child(out.str()); errs_->add_child(out.str());

View File

@ -25,17 +25,17 @@ namespace {
// FIXME: get the file size // FIXME: get the file size
unsigned const NR_BLOCKS = 1024; unsigned const NR_BLOCKS = 1024;
transaction_manager<4096>::ptr transaction_manager::ptr
open_tm(string const &dev_path) { open_tm(string const &dev_path) {
block_manager<4096>::ptr bm(new block_manager<4096>(dev_path, NR_BLOCKS)); block_manager<>::ptr bm(new block_manager<>(dev_path, NR_BLOCKS));
space_map::ptr sm(new core_map(NR_BLOCKS)); space_map::ptr sm(new core_map(NR_BLOCKS));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm)); transaction_manager::ptr tm(new transaction_manager(bm, sm));
return tm; return tm;
} }
superblock read_superblock(block_manager<4096>::ptr bm) { superblock read_superblock(block_manager<>::ptr bm) {
superblock sb; superblock sb;
block_manager<4096>::read_ref r = bm->read_lock(SUPERBLOCK_LOCATION); block_manager<>::read_ref r = bm->read_lock(SUPERBLOCK_LOCATION);
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data()); superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(&r.data());
superblock_traits::unpack(*sbd, sb); superblock_traits::unpack(*sbd, sb);
return sb; return sb;
@ -45,21 +45,21 @@ namespace {
// devices having mappings defined, which can later be cross // devices having mappings defined, which can later be cross
// referenced with the details tree. A separate block_counter is // referenced with the details tree. A separate block_counter is
// used to later verify the data space map. // used to later verify the data space map.
class mapping_validator : public btree_validator<2, block_traits, MD_BLOCK_SIZE> { class mapping_validator : public btree_validator<2, block_traits> {
public: public:
typedef boost::shared_ptr<mapping_validator> ptr; typedef boost::shared_ptr<mapping_validator> ptr;
mapping_validator(block_counter &metadata_counter, block_counter &data_counter) mapping_validator(block_counter &metadata_counter, block_counter &data_counter)
: btree_validator<2, block_traits, MD_BLOCK_SIZE>(metadata_counter), : btree_validator<2, block_traits>(metadata_counter),
data_counter_(data_counter) { data_counter_(data_counter) {
} }
// Sharing can only occur in level 1 nodes. // Sharing can only occur in level 1 nodes.
// FIXME: not true once we start having held roots. // FIXME: not true once we start having held roots.
bool visit_internal_leaf(unsigned level, bool is_root, bool visit_internal_leaf(unsigned level, bool is_root,
btree_detail::node_ref<uint64_traits, MD_BLOCK_SIZE> const &n) { btree_detail::node_ref<uint64_traits> const &n) {
bool r = btree_validator<2, block_traits, MD_BLOCK_SIZE>::visit_internal_leaf(level, is_root, n); bool r = btree_validator<2, block_traits>::visit_internal_leaf(level, is_root, n);
if (!r && level == 0) { if (!r && level == 0) {
throw runtime_error("unexpected sharing in level 0 of mapping tree."); throw runtime_error("unexpected sharing in level 0 of mapping tree.");
} }
@ -71,8 +71,8 @@ namespace {
} }
bool visit_leaf(unsigned level, bool is_root, bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<block_traits, MD_BLOCK_SIZE> const &n) { btree_detail::node_ref<block_traits> const &n) {
bool r = btree_validator<2, block_traits, MD_BLOCK_SIZE>::visit_leaf(level, is_root, n); bool r = btree_validator<2, block_traits>::visit_leaf(level, is_root, n);
if (r) if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++) for (unsigned i = 0; i < n.get_nr_entries(); i++)
@ -90,17 +90,17 @@ namespace {
set<uint64_t> devices_; set<uint64_t> devices_;
}; };
class details_validator : public btree_validator<1, device_details_traits, MD_BLOCK_SIZE> { class details_validator : public btree_validator<1, device_details_traits> {
public: public:
typedef boost::shared_ptr<details_validator> ptr; typedef boost::shared_ptr<details_validator> ptr;
details_validator(block_counter &counter) details_validator(block_counter &counter)
: btree_validator<1, device_details_traits, MD_BLOCK_SIZE>(counter) { : btree_validator<1, device_details_traits>(counter) {
} }
bool visit_leaf(unsigned level, bool is_root, bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<device_details_traits, MD_BLOCK_SIZE> const &n) { btree_detail::node_ref<device_details_traits> const &n) {
bool r = btree_validator<1, device_details_traits, MD_BLOCK_SIZE>::visit_leaf(level, is_root, n); bool r = btree_validator<1, device_details_traits>::visit_leaf(level, is_root, n);
if (r) if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++) for (unsigned i = 0; i < n.get_nr_entries(); i++)
@ -196,10 +196,10 @@ thin::set_mapped_blocks(block_address count)
metadata::metadata(std::string const &dev_path) metadata::metadata(std::string const &dev_path)
: tm_(open_tm(dev_path)), : tm_(open_tm(dev_path)),
sb_(read_superblock(tm_->get_bm())), sb_(read_superblock(tm_->get_bm())),
metadata_sm_(open_metadata_sm<MD_BLOCK_SIZE>(tm_, static_cast<void *>(&sb_.metadata_space_map_root_))), metadata_sm_(open_metadata_sm(tm_, static_cast<void *>(&sb_.metadata_space_map_root_))),
data_sm_(open_disk_sm<MD_BLOCK_SIZE>(tm_, static_cast<void *>(&sb_.data_space_map_root_))), data_sm_(open_disk_sm(tm_, static_cast<void *>(&sb_.data_space_map_root_))),
details_(tm_, sb_.device_details_root_, device_details_traits::ref_counter()), details_(tm_, sb_.device_details_root_, device_details_traits::ref_counter()),
mappings_top_level_(tm_, sb_.data_mapping_root_, mtree_ref_counter<MD_BLOCK_SIZE>(tm_)), mappings_top_level_(tm_, sb_.data_mapping_root_, mtree_ref_counter(tm_)),
mappings_(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_)) mappings_(tm_, sb_.data_mapping_root_, block_time_ref_counter(data_sm_))
{ {
#if 0 #if 0

View File

@ -16,8 +16,6 @@
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace thin_provisioning { namespace thin_provisioning {
unsigned const MD_BLOCK_SIZE = 4096;
// FIXME: don't use namespaces in a header // FIXME: don't use namespaces in a header
using namespace base; using namespace base;
using namespace persistent_data; using namespace persistent_data;
@ -87,10 +85,9 @@ namespace thin_provisioning {
//------------------------------------------------ //------------------------------------------------
template <uint32_t BlockSize>
class mtree_ref_counter { class mtree_ref_counter {
public: public:
mtree_ref_counter(typename transaction_manager<BlockSize>::ptr tm) mtree_ref_counter(transaction_manager::ptr tm)
: tm_(tm) { : tm_(tm) {
} }
@ -101,14 +98,13 @@ namespace thin_provisioning {
} }
private: private:
typename transaction_manager<BlockSize>::ptr tm_; transaction_manager::ptr tm_;
}; };
template <uint32_t BlockSize>
struct mtree_traits { struct mtree_traits {
typedef base::__le64 disk_type; typedef base::__le64 disk_type;
typedef uint64_t value_type; typedef uint64_t value_type;
typedef mtree_ref_counter<BlockSize> ref_counter; typedef mtree_ref_counter ref_counter;
static void unpack(disk_type const &disk, value_type &value) { static void unpack(disk_type const &disk, value_type &value) {
value = base::to_cpu<uint64_t>(disk); value = base::to_cpu<uint64_t>(disk);
@ -146,8 +142,8 @@ namespace thin_provisioning {
class metadata { class metadata {
public: public:
typedef boost::shared_ptr<metadata> ptr; typedef boost::shared_ptr<metadata> ptr;
typedef block_manager<MD_BLOCK_SIZE>::read_ref read_ref; typedef block_manager<>::read_ref read_ref;
typedef block_manager<MD_BLOCK_SIZE>::write_ref write_ref; typedef block_manager<>::write_ref write_ref;
metadata(std::string const &dev_path); metadata(std::string const &dev_path);
~metadata(); ~metadata();
@ -173,27 +169,30 @@ namespace thin_provisioning {
thin::ptr open_thin(thin_dev_t); thin::ptr open_thin(thin_dev_t);
// Validation and repair // Validation
boost::optional<persistent_data::error_set::ptr> check(); boost::optional<persistent_data::error_set::ptr> check();
// Dumping metadata
void dump();
private: private:
friend class thin; friend class thin;
bool device_exists(thin_dev_t dev) const; bool device_exists(thin_dev_t dev) const;
typedef persistent_data::transaction_manager<MD_BLOCK_SIZE>::ptr tm_ptr; typedef persistent_data::transaction_manager::ptr tm_ptr;
typedef persistent_data::btree<1, device_details_traits, MD_BLOCK_SIZE> detail_tree; typedef persistent_data::btree<1, device_details_traits> detail_tree;
typedef persistent_data::btree<1, mtree_traits<MD_BLOCK_SIZE>, MD_BLOCK_SIZE> dev_tree; typedef persistent_data::btree<1, mtree_traits> dev_tree;
typedef persistent_data::btree<2, block_traits, MD_BLOCK_SIZE> mapping_tree; typedef persistent_data::btree<2, block_traits> mapping_tree;
typedef persistent_data::btree<1, block_traits, MD_BLOCK_SIZE> single_mapping_tree; typedef persistent_data::btree<1, block_traits> single_mapping_tree;
// Declaration order is important here // Declaration order is important here
tm_ptr tm_; tm_ptr tm_;
superblock sb_; superblock sb_;
sm_disk_detail::sm_metadata<MD_BLOCK_SIZE>::ptr metadata_sm_; checked_space_map::ptr metadata_sm_;
sm_disk_detail::sm_disk<MD_BLOCK_SIZE>::ptr data_sm_; checked_space_map::ptr data_sm_;
detail_tree details_; detail_tree details_;
dev_tree mappings_top_level_; dev_tree mappings_top_level_;
mapping_tree mappings_; mapping_tree mappings_;

513
space_map_disk.cc Normal file
View File

@ -0,0 +1,513 @@
#include "space_map_disk.h"
#include "endian_utils.h"
#include "math_utils.h"
#include "space_map_disk_structures.h"
#include "transaction_manager.h"
using namespace boost;
using namespace persistent_data;
using namespace std;
using namespace sm_disk_detail;
//----------------------------------------------------------------
namespace {
class bitmap {
public:
typedef transaction_manager::read_ref read_ref;
typedef transaction_manager::write_ref write_ref;
bitmap(transaction_manager::ptr tm,
index_entry const &ie)
: tm_(tm),
ie_(ie) {
}
ref_t lookup(unsigned b) const {
read_ref rr = tm_->read_lock(ie_.blocknr_);
void const *bits = bitmap_data(rr);
ref_t b1 = test_bit_le(bits, b * 2);
ref_t b2 = test_bit_le(bits, b * 2 + 1);
ref_t result = b2 ? 1 : 0;
result |= b1 ? 0b10 : 0;
return result;
}
void insert(unsigned b, ref_t n) {
write_ref wr = tm_->shadow(ie_.blocknr_).first;
void *bits = bitmap_data(wr);
bool was_free = !test_bit_le(bits, b * 2) && !test_bit_le(bits, b * 2 + 1);
if (n == 1 || n == 3)
set_bit_le(bits, b * 2 + 1);
else
clear_bit_le(bits, b * 2 + 1);
if (n == 2 || n == 3)
set_bit_le(bits, b * 2);
else
clear_bit_le(bits, b * 2);
ie_.blocknr_ = wr.get_location();
if (was_free && n > 0) {
ie_.nr_free_--;
if (b == ie_.none_free_before_)
ie_.none_free_before_++;
}
if (!was_free && n == 0) {
ie_.nr_free_++;
if (b < ie_.none_free_before_)
ie_.none_free_before_ = b;
}
}
unsigned find_free(unsigned end) {
for (unsigned i = ie_.none_free_before_; i < end; i++) {
if (lookup(i) == 0) {
insert(i, 1);
ie_.none_free_before_ = i + 1;
return i;
}
}
throw std::runtime_error("no free entry in bitmap");
}
index_entry const &get_ie() const {
return ie_;
}
private:
void *bitmap_data(typename transaction_manager::write_ref &wr) {
bitmap_header *h = reinterpret_cast<bitmap_header *>(&wr.data()[0]);
return h + 1;
}
void const *bitmap_data(typename transaction_manager::read_ref &rr) const {
bitmap_header const *h = reinterpret_cast<bitmap_header const *>(&rr.data()[0]);
return h + 1;
}
typename transaction_manager::ptr tm_;
index_entry ie_;
};
struct ref_count_traits {
typedef __le32 disk_type;
typedef uint32_t value_type;
typedef NoOpRefCounter<uint32_t> ref_counter;
static void unpack(disk_type const &d, value_type &v) {
v = to_cpu<value_type>(d);
}
static void pack(value_type const &v, disk_type &d) {
d = to_disk<disk_type>(v);
}
};
class ref_count_validator : public btree_validator<1, ref_count_traits> {
public:
typedef boost::shared_ptr<ref_count_validator> ptr;
ref_count_validator(block_counter &counter)
: btree_validator<1, ref_count_traits>(counter) {
}
};
class sm_disk_base : public checked_space_map {
public:
typedef boost::shared_ptr<sm_disk_base> ptr;
typedef transaction_manager::read_ref read_ref;
typedef transaction_manager::write_ref write_ref;
sm_disk_base(transaction_manager::ptr tm)
: tm_(tm),
entries_per_block_((MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4),
nr_blocks_(0),
nr_allocated_(0),
ref_counts_(tm_, ref_count_traits::ref_counter()) {
}
sm_disk_base(typename transaction_manager::ptr tm,
sm_root const &root)
: tm_(tm),
entries_per_block_((MD_BLOCK_SIZE - sizeof(bitmap_header)) * 4),
nr_blocks_(root.nr_blocks_),
nr_allocated_(root.nr_allocated_),
ref_counts_(tm_, root.ref_count_root_, ref_count_traits::ref_counter()) {
}
block_address get_nr_blocks() const {
return nr_blocks_;
}
block_address get_nr_free() const {
return nr_blocks_ - nr_allocated_;
}
ref_t get_count(block_address b) const {
ref_t count = lookup_bitmap(b);
if (count == 3)
return lookup_ref_count(b);
return count;
}
void set_count(block_address b, ref_t c) {
ref_t old = get_count(b);
if (c == old)
return;
if (c > 2) {
if (old < 3)
insert_bitmap(b, 3);
insert_ref_count(b, c);
} else {
if (old > 2)
remove_ref_count(b);
insert_bitmap(b, c);
}
if (old == 0)
nr_allocated_++;
else if (c == 0)
nr_allocated_--;
}
void commit() {
commit_ies();
}
void inc(block_address b) {
// FIXME: 2 get_counts
ref_t old = get_count(b);
set_count(b, old + 1);
}
void dec(block_address b) {
ref_t old = get_count(b);
set_count(b, old - 1);
}
block_address new_block() {
// silly to always start searching from the
// beginning.
block_address nr_indexes = div_up<block_address>(nr_blocks_, entries_per_block_);
for (block_address index = 0; index < nr_indexes; index++) {
index_entry ie = find_ie(index);
bitmap bm(tm_, ie);
block_address b = bm.find_free((index == nr_indexes - 1) ?
nr_blocks_ % entries_per_block_ : entries_per_block_);
save_ie(b, bm.get_ie());
nr_allocated_++;
b = (index * entries_per_block_) + b;
assert(get_count(b) == 1);
return b;
}
throw runtime_error("out of space");
}
bool count_possibly_greater_than_one(block_address b) const {
return get_count(b) > 1;
}
virtual void extend(block_address extra_blocks) {
block_address nr_blocks = nr_blocks_ + extra_blocks;
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_);
for (block_address i = old_bitmap_count; i < bitmap_count; i++) {
write_ref wr = tm_->new_block();
struct index_entry ie;
ie.blocknr_ = wr.get_location();
ie.nr_free_ = i == (bitmap_count - 1) ?
(nr_blocks % entries_per_block_) : entries_per_block_;
ie.none_free_before_ = 0;
save_ie(i, ie);
}
nr_blocks_ = nr_blocks;
}
virtual void check(block_counter &counter) const {
typename ref_count_validator::ptr v(new ref_count_validator(counter));
ref_counts_.visit(v);
}
protected:
typename transaction_manager::ptr get_tm() const {
return tm_;
}
block_address get_nr_allocated() const {
return nr_allocated_;
}
block_address get_ref_count_root() const {
return ref_counts_.get_root();
}
unsigned get_entries_per_block() const {
return entries_per_block_;
}
private:
virtual index_entry find_ie(block_address b) const = 0;
virtual void save_ie(block_address b, struct index_entry ie) = 0;
virtual void commit_ies() = 0;
ref_t lookup_bitmap(block_address b) const {
index_entry ie = find_ie(b / entries_per_block_);
bitmap bm(tm_, ie);
return bm.lookup(b % entries_per_block_);
}
void insert_bitmap(block_address b, unsigned n) {
if (n > 3)
throw runtime_error("bitmap can only hold 2 bit values");
index_entry ie = find_ie(b / entries_per_block_);
bitmap bm(tm_, ie);
bm.insert(b % entries_per_block_, n);
save_ie(b, bm.get_ie());
}
ref_t lookup_ref_count(block_address b) const {
uint64_t key[1] = {b};
optional<ref_t> mvalue = ref_counts_.lookup(key);
if (!mvalue)
throw runtime_error("ref count not in tree");
return *mvalue;
}
void insert_ref_count(block_address b, ref_t count) {
uint64_t key[1] = {b};
ref_counts_.insert(key, count);
}
void remove_ref_count(block_address b) {
uint64_t key[1] = {b};
ref_counts_.remove(key);
}
transaction_manager::ptr tm_;
uint32_t entries_per_block_;
block_address nr_blocks_;
block_address nr_allocated_;
btree<1, ref_count_traits> ref_counts_;
};
class bitmap_tree_validator : public btree_validator<1, index_entry_traits> {
public:
typedef boost::shared_ptr<bitmap_tree_validator> ptr;
bitmap_tree_validator(block_counter &counter)
: btree_validator<1, index_entry_traits>(counter) {
}
bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<index_entry_traits> const &n) {
bool r = btree_validator<1, index_entry_traits>::visit_leaf(level, is_root, n);
if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++)
btree_validator<1, index_entry_traits>::get_counter().inc(n.value_at(i).blocknr_);
return r;
}
};
class sm_disk : public sm_disk_base {
public:
typedef boost::shared_ptr<sm_disk> ptr;
sm_disk(transaction_manager::ptr tm)
: sm_disk_base(tm),
bitmaps_(sm_disk_base::get_tm(), index_entry_traits::ref_counter()) {
}
sm_disk(transaction_manager::ptr tm,
sm_root const &root)
: sm_disk_base(tm, root),
bitmaps_(sm_disk_base::get_tm(), root.bitmap_root_, index_entry_traits::ref_counter()) {
}
size_t root_size() {
return sizeof(sm_root_disk);
}
void copy_root(void *dest, size_t len) {
sm_root_disk d;
sm_root v;
if (len < sizeof(d))
throw runtime_error("root too small");
v.nr_blocks_ = sm_disk_base::get_nr_blocks();
v.nr_allocated_ = sm_disk_base::get_nr_allocated();
v.bitmap_root_ = bitmaps_.get_root();
v.ref_count_root_ = sm_disk_base::get_ref_count_root();
sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d));
}
void check(block_counter &counter) const {
sm_disk_base::check(counter);
typename bitmap_tree_validator::ptr v(new bitmap_tree_validator(counter));
bitmaps_.visit(v);
}
private:
index_entry find_ie(block_address ie_index) const {
uint64_t key[1] = {ie_index};
optional<index_entry> mindex = bitmaps_.lookup(key);
if (!mindex)
throw runtime_error("Couldn't lookup bitmap");
return *mindex;
}
void save_ie(block_address ie_index, struct index_entry ie) {
uint64_t key[1] = {ie_index};
bitmaps_.insert(key, ie);
}
void commit_ies() {
}
btree<1, index_entry_traits> bitmaps_;
};
class sm_metadata : public sm_disk_base {
public:
typedef boost::shared_ptr<sm_metadata> ptr;
sm_metadata(transaction_manager::ptr tm)
: sm_disk_base(tm),
entries_(MAX_METADATA_BITMAPS) {
// FIXME: allocate a new bitmap root
}
sm_metadata(transaction_manager::ptr tm,
sm_root const &root)
: sm_disk_base(tm, root),
bitmap_root_(root.bitmap_root_),
entries_(MAX_METADATA_BITMAPS) {
load_ies();
}
size_t root_size() {
return sizeof(sm_root_disk);
}
// FIXME: common code
void copy_root(void *dest, size_t len) {
sm_root_disk d;
sm_root v;
if (len < sizeof(d))
throw runtime_error("root too small");
v.nr_blocks_ = sm_disk_base::get_nr_blocks();
v.nr_allocated_ = sm_disk_base::get_nr_allocated();
v.bitmap_root_ = bitmap_root_;
v.ref_count_root_ = sm_disk_base::get_ref_count_root();
sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d));
}
void check(block_counter &counter) const {
sm_disk_base::check(counter);
counter.inc(bitmap_root_);
for (unsigned i = 0; i < entries_.size(); i++)
if (entries_[i].blocknr_ != 0) // superblock
counter.inc(entries_[i].blocknr_);
}
private:
index_entry find_ie(block_address ie_index) const {
return entries_[ie_index];
}
void save_ie(block_address ie_index, struct index_entry ie) {
entries_[ie_index] = ie;
}
void load_ies() {
typename block_manager<>::read_ref rr =
sm_disk_base::get_tm()->read_lock(bitmap_root_);
metadata_index const *mdi = reinterpret_cast<metadata_index const *>(&rr.data());
unsigned nr_indexes = div_up<block_address>(sm_disk_base::get_nr_blocks(),
sm_disk_base::get_entries_per_block());
for (unsigned i = 0; i < nr_indexes; i++)
index_entry_traits::unpack(*(mdi->index + i), entries_[i]);
}
void commit_ies() {
std::pair<typename block_manager<>::write_ref, bool> p =
sm_disk_base::get_tm()->shadow(bitmap_root_);
bitmap_root_ = p.first.get_location();
metadata_index *mdi = reinterpret_cast<metadata_index *>(&p.first.data());
mdi->csum_ = to_disk<__le32, uint32_t>(0);
mdi->padding_ = to_disk<__le32, uint32_t>(0);
mdi->blocknr_ = to_disk<__le64>(bitmap_root_);
for (unsigned i = 0; i < entries_.size(); i++)
index_entry_traits::pack(entries_[i], mdi->index[i]);
}
block_address bitmap_root_;
std::vector<index_entry> entries_;
};
}
//----------------------------------------------------------------
checked_space_map::ptr
persistent_data::create_disk_sm(transaction_manager::ptr tm,
block_address nr_blocks)
{
checked_space_map::ptr sm(new sm_disk(tm));
sm->extend(nr_blocks);
return sm;
}
checked_space_map::ptr
persistent_data::open_disk_sm(transaction_manager::ptr tm, void *root)
{
sm_root_disk d;
sm_root v;
::memcpy(&d, root, sizeof(d));
sm_root_traits::unpack(d, v);
return checked_space_map::ptr(new sm_disk(tm, v));
}
checked_space_map::ptr
persistent_data::open_metadata_sm(transaction_manager::ptr tm, void * root)
{
sm_root_disk d;
sm_root v;
::memcpy(&d, root, sizeof(d));
sm_root_traits::unpack(d, v);
return checked_space_map::ptr(new sm_metadata(tm, v));
}
//----------------------------------------------------------------

View File

@ -3,531 +3,25 @@
#include "btree_validator.h" #include "btree_validator.h"
#include "space_map.h" #include "space_map.h"
#include "transaction_manager.h"
#include "endian_utils.h"
#include "space_map_disk_structures.h"
#include "math_utils.h"
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace persistent_data { namespace persistent_data {
class checked_space_map : public persistent_space_map {
public:
typedef boost::shared_ptr<checked_space_map> ptr;
namespace sm_disk_detail { virtual void check(block_counter &counter) const = 0;
using namespace base; };
using namespace persistent_data;
template <uint32_t BlockSize> checked_space_map::ptr
class bitmap { create_disk_sm(transaction_manager::ptr tm, block_address nr_blocks);
public:
typedef typename transaction_manager<BlockSize>::read_ref read_ref;
typedef typename transaction_manager<BlockSize>::write_ref write_ref;
bitmap(typename transaction_manager<BlockSize>::ptr tm, checked_space_map::ptr
index_entry const &ie) open_disk_sm(transaction_manager::ptr tm, void *root);
: tm_(tm),
ie_(ie) {
}
ref_t lookup(unsigned b) const { checked_space_map::ptr
read_ref rr = tm_->read_lock(ie_.blocknr_); open_metadata_sm(transaction_manager::ptr tm, void * root);
void const *bits = bitmap_data(rr);
ref_t b1 = test_bit_le(bits, b * 2);
ref_t b2 = test_bit_le(bits, b * 2 + 1);
ref_t result = b2 ? 1 : 0;
result |= b1 ? 0b10 : 0;
return result;
}
void insert(unsigned b, ref_t n) {
write_ref wr = tm_->shadow(ie_.blocknr_).first;
void *bits = bitmap_data(wr);
bool was_free = !test_bit_le(bits, b * 2) && !test_bit_le(bits, b * 2 + 1);
if (n == 1 || n == 3)
set_bit_le(bits, b * 2 + 1);
else
clear_bit_le(bits, b * 2 + 1);
if (n == 2 || n == 3)
set_bit_le(bits, b * 2);
else
clear_bit_le(bits, b * 2);
ie_.blocknr_ = wr.get_location();
if (was_free && n > 0) {
ie_.nr_free_--;
if (b == ie_.none_free_before_)
ie_.none_free_before_++;
}
if (!was_free && n == 0) {
ie_.nr_free_++;
if (b < ie_.none_free_before_)
ie_.none_free_before_ = b;
}
}
unsigned find_free(unsigned end) {
for (unsigned i = ie_.none_free_before_; i < end; i++) {
if (lookup(i) == 0) {
insert(i, 1);
ie_.none_free_before_ = i + 1;
return i;
}
}
throw std::runtime_error("no free entry in bitmap");
}
index_entry const &get_ie() const {
return ie_;
}
private:
void *bitmap_data(typename transaction_manager<BlockSize>::write_ref &wr) {
bitmap_header *h = reinterpret_cast<bitmap_header *>(&wr.data()[0]);
return h + 1;
}
void const *bitmap_data(typename transaction_manager<BlockSize>::read_ref &rr) const {
bitmap_header const *h = reinterpret_cast<bitmap_header const *>(&rr.data()[0]);
return h + 1;
}
typename transaction_manager<BlockSize>::ptr tm_;
index_entry ie_;
};
struct ref_count_traits {
typedef __le32 disk_type;
typedef uint32_t value_type;
typedef NoOpRefCounter<uint32_t> ref_counter;
static void unpack(disk_type const &d, value_type &v) {
v = to_cpu<value_type>(d);
}
static void pack(value_type const &v, disk_type &d) {
d = to_disk<disk_type>(v);
}
};
template <uint32_t BlockSize>
class ref_count_validator : public btree_validator<1, ref_count_traits, BlockSize> {
public:
typedef boost::shared_ptr<ref_count_validator> ptr;
ref_count_validator(block_counter &counter)
: btree_validator<1, ref_count_traits, BlockSize>(counter) {
}
};
template <uint32_t BlockSize>
class sm_disk_base : public persistent_space_map {
public:
typedef boost::shared_ptr<sm_disk_base<BlockSize> > ptr;
typedef typename transaction_manager<BlockSize>::read_ref read_ref;
typedef typename transaction_manager<BlockSize>::write_ref write_ref;
sm_disk_base(typename transaction_manager<BlockSize>::ptr tm)
: tm_(tm),
entries_per_block_((BlockSize - sizeof(bitmap_header)) * 4),
nr_blocks_(0),
nr_allocated_(0),
ref_counts_(tm_, ref_count_traits::ref_counter()) {
}
sm_disk_base(typename transaction_manager<BlockSize>::ptr tm,
sm_root const &root)
: tm_(tm),
entries_per_block_((BlockSize - sizeof(bitmap_header)) * 4),
nr_blocks_(root.nr_blocks_),
nr_allocated_(root.nr_allocated_),
ref_counts_(tm_, root.ref_count_root_, ref_count_traits::ref_counter()) {
}
block_address get_nr_blocks() const {
return nr_blocks_;
}
block_address get_nr_free() const {
return nr_blocks_ - nr_allocated_;
}
ref_t get_count(block_address b) const {
ref_t count = lookup_bitmap(b);
if (count == 3)
return lookup_ref_count(b);
return count;
}
void set_count(block_address b, ref_t c) {
ref_t old = get_count(b);
if (c == old)
return;
if (c > 2) {
if (old < 3)
insert_bitmap(b, 3);
insert_ref_count(b, c);
} else {
if (old > 2)
remove_ref_count(b);
insert_bitmap(b, c);
}
if (old == 0)
nr_allocated_++;
else if (c == 0)
nr_allocated_--;
}
void commit() {
commit_ies();
}
void inc(block_address b) {
// FIXME: 2 get_counts
ref_t old = get_count(b);
set_count(b, old + 1);
}
void dec(block_address b) {
ref_t old = get_count(b);
set_count(b, old - 1);
}
block_address new_block() {
// silly to always start searching from the
// beginning.
block_address nr_indexes = div_up<block_address>(nr_blocks_, entries_per_block_);
for (block_address index = 0; index < nr_indexes; index++) {
index_entry ie = find_ie(index);
bitmap<BlockSize> bm(tm_, ie);
block_address b = bm.find_free((index == nr_indexes - 1) ?
nr_blocks_ % entries_per_block_ : entries_per_block_);
save_ie(b, bm.get_ie());
nr_allocated_++;
b = (index * entries_per_block_) + b;
assert(get_count(b) == 1);
return b;
}
throw runtime_error("out of space");
}
bool count_possibly_greater_than_one(block_address b) const {
return get_count(b) > 1;
}
virtual void extend(block_address extra_blocks) {
block_address nr_blocks = nr_blocks_ + extra_blocks;
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_);
for (block_address i = old_bitmap_count; i < bitmap_count; i++) {
write_ref wr = tm_->new_block();
struct index_entry ie;
ie.blocknr_ = wr.get_location();
ie.nr_free_ = i == (bitmap_count - 1) ?
(nr_blocks % entries_per_block_) : entries_per_block_;
ie.none_free_before_ = 0;
save_ie(i, ie);
}
nr_blocks_ = nr_blocks;
}
virtual void check(block_counter &counter) const {
typename ref_count_validator<BlockSize>::ptr v(new ref_count_validator<BlockSize>(counter));
ref_counts_.visit(v);
}
protected:
typename transaction_manager<BlockSize>::ptr get_tm() const {
return tm_;
}
block_address get_nr_allocated() const {
return nr_allocated_;
}
block_address get_ref_count_root() const {
return ref_counts_.get_root();
}
unsigned get_entries_per_block() const {
return entries_per_block_;
}
private:
virtual index_entry find_ie(block_address b) const = 0;
virtual void save_ie(block_address b, struct index_entry ie) = 0;
virtual void commit_ies() = 0;
ref_t lookup_bitmap(block_address b) const {
index_entry ie = find_ie(b / entries_per_block_);
bitmap<BlockSize> bm(tm_, ie);
return bm.lookup(b % entries_per_block_);
}
void insert_bitmap(block_address b, unsigned n) {
if (n > 3)
throw runtime_error("bitmap can only hold 2 bit values");
index_entry ie = find_ie(b / entries_per_block_);
bitmap<BlockSize> bm(tm_, ie);
bm.insert(b % entries_per_block_, n);
save_ie(b, bm.get_ie());
}
ref_t lookup_ref_count(block_address b) const {
uint64_t key[1] = {b};
optional<ref_t> mvalue = ref_counts_.lookup(key);
if (!mvalue)
throw runtime_error("ref count not in tree");
return *mvalue;
}
void insert_ref_count(block_address b, ref_t count) {
uint64_t key[1] = {b};
ref_counts_.insert(key, count);
}
void remove_ref_count(block_address b) {
uint64_t key[1] = {b};
ref_counts_.remove(key);
}
typename transaction_manager<BlockSize>::ptr tm_;
uint32_t entries_per_block_;
block_address nr_blocks_;
block_address nr_allocated_;
btree<1, ref_count_traits, BlockSize> ref_counts_;
};
template <uint32_t BlockSize>
class bitmap_tree_validator : public btree_validator<1, index_entry_traits, BlockSize> {
public:
typedef boost::shared_ptr<bitmap_tree_validator> ptr;
bitmap_tree_validator(block_counter &counter)
: btree_validator<1, index_entry_traits, BlockSize>(counter) {
}
bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<index_entry_traits, BlockSize> const &n) {
bool r = btree_validator<1, index_entry_traits, BlockSize>::visit_leaf(level, is_root, n);
if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++)
btree_validator<1, index_entry_traits, BlockSize>::get_counter().inc(n.value_at(i).blocknr_);
return r;
}
};
template <uint32_t BlockSize>
class sm_disk : public sm_disk_base<BlockSize> {
public:
typedef boost::shared_ptr<sm_disk<BlockSize> > ptr;
sm_disk(typename transaction_manager<BlockSize>::ptr tm)
: sm_disk_base<BlockSize>(tm),
bitmaps_(sm_disk_base<BlockSize>::get_tm(), typename index_entry_traits::ref_counter()) {
}
sm_disk(typename transaction_manager<BlockSize>::ptr tm,
sm_root const &root)
: sm_disk_base<BlockSize>(tm, root),
bitmaps_(sm_disk_base<BlockSize>::get_tm(), root.bitmap_root_, typename index_entry_traits::ref_counter()) {
}
size_t root_size() {
return sizeof(sm_root_disk);
}
void copy_root(void *dest, size_t len) {
sm_root_disk d;
sm_root v;
if (len < sizeof(d))
throw runtime_error("root too small");
v.nr_blocks_ = sm_disk_base<BlockSize>::get_nr_blocks();
v.nr_allocated_ = sm_disk_base<BlockSize>::get_nr_allocated();
v.bitmap_root_ = bitmaps_.get_root();
v.ref_count_root_ = sm_disk_base<BlockSize>::get_ref_count_root();
sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d));
}
void check(block_counter &counter) const {
sm_disk_base<BlockSize>::check(counter);
typename bitmap_tree_validator<BlockSize>::ptr v(new bitmap_tree_validator<BlockSize>(counter));
bitmaps_.visit(v);
}
private:
index_entry find_ie(block_address ie_index) const {
uint64_t key[1] = {ie_index};
optional<index_entry> mindex = bitmaps_.lookup(key);
if (!mindex)
throw runtime_error("Couldn't lookup bitmap");
return *mindex;
}
void save_ie(block_address ie_index, struct index_entry ie) {
uint64_t key[1] = {ie_index};
bitmaps_.insert(key, ie);
}
void commit_ies() {
}
btree<1, index_entry_traits, BlockSize> bitmaps_;
};
template <uint32_t BlockSize>
class sm_metadata : public sm_disk_base<BlockSize> {
public:
typedef boost::shared_ptr<sm_metadata<BlockSize> > ptr;
sm_metadata(typename transaction_manager<BlockSize>::ptr tm)
: sm_disk_base<BlockSize>(tm),
entries_(MAX_METADATA_BITMAPS) {
// FIXME: allocate a new bitmap root
}
sm_metadata(typename transaction_manager<BlockSize>::ptr tm,
sm_root const &root)
: sm_disk_base<BlockSize>(tm, root),
bitmap_root_(root.bitmap_root_),
entries_(MAX_METADATA_BITMAPS) {
load_ies();
}
size_t root_size() {
return sizeof(sm_root_disk);
}
// FIXME: common code
void copy_root(void *dest, size_t len) {
sm_root_disk d;
sm_root v;
if (len < sizeof(d))
throw runtime_error("root too small");
v.nr_blocks_ = sm_disk_base<BlockSize>::get_nr_blocks();
v.nr_allocated_ = sm_disk_base<BlockSize>::get_nr_allocated();
v.bitmap_root_ = bitmap_root_;
v.ref_count_root_ = sm_disk_base<BlockSize>::get_ref_count_root();
sm_root_traits::pack(v, d);
::memcpy(dest, &d, sizeof(d));
}
void check(block_counter &counter) const {
sm_disk_base<BlockSize>::check(counter);
counter.inc(bitmap_root_);
for (unsigned i = 0; i < entries_.size(); i++)
if (entries_[i].blocknr_ != 0) // superblock
counter.inc(entries_[i].blocknr_);
}
private:
index_entry find_ie(block_address ie_index) const {
return entries_[ie_index];
}
void save_ie(block_address ie_index, struct index_entry ie) {
entries_[ie_index] = ie;
}
void load_ies() {
typename block_manager<BlockSize>::read_ref rr =
sm_disk_base<BlockSize>::get_tm()->read_lock(bitmap_root_);
metadata_index const *mdi = reinterpret_cast<metadata_index const *>(&rr.data());
unsigned nr_indexes = div_up<block_address>(sm_disk_base<BlockSize>::get_nr_blocks(),
sm_disk_base<BlockSize>::get_entries_per_block());
for (unsigned i = 0; i < nr_indexes; i++)
index_entry_traits::unpack(*(mdi->index + i), entries_[i]);
}
void commit_ies() {
std::pair<typename block_manager<BlockSize>::write_ref, bool> p =
sm_disk_base<BlockSize>::get_tm()->shadow(bitmap_root_);
bitmap_root_ = p.first.get_location();
metadata_index *mdi = reinterpret_cast<metadata_index *>(&p.first.data());
mdi->csum_ = to_disk<__le32, uint32_t>(0);
mdi->padding_ = to_disk<__le32, uint32_t>(0);
mdi->blocknr_ = to_disk<__le64>(bitmap_root_);
for (unsigned i = 0; i < entries_.size(); i++)
index_entry_traits::pack(entries_[i], mdi->index[i]);
}
block_address bitmap_root_;
std::vector<index_entry> entries_;
};
}
template <uint32_t MetadataBlockSize>
typename sm_disk_detail::sm_disk<MetadataBlockSize>::ptr
create_disk_sm(typename transaction_manager<MetadataBlockSize>::ptr tm,
block_address nr_blocks)
{
using namespace sm_disk_detail;
typename sm_disk_detail::sm_disk<MetadataBlockSize>::ptr sm(
new sm_disk<MetadataBlockSize>(tm));
sm->extend(nr_blocks);
return sm;
}
template <uint32_t MetadataBlockSize>
typename sm_disk_detail::sm_disk<MetadataBlockSize>::ptr
open_disk_sm(typename transaction_manager<MetadataBlockSize>::ptr tm,
void *root)
{
using namespace sm_disk_detail;
sm_root_disk d;
sm_root v;
::memcpy(&d, root, sizeof(d));
sm_root_traits::unpack(d, v);
return typename sm_disk<MetadataBlockSize>::ptr(
new sm_disk<MetadataBlockSize>(tm, v));
}
template <uint32_t MetadataBlockSize>
typename sm_disk_detail::sm_metadata<MetadataBlockSize>::ptr
open_metadata_sm(typename transaction_manager<MetadataBlockSize>::ptr tm,
void * root)
{
using namespace sm_disk_detail;
sm_root_disk d;
sm_root v;
::memcpy(&d, root, sizeof(d));
sm_root_traits::unpack(d, v);
return typename sm_metadata<MetadataBlockSize>::ptr(
new sm_metadata<MetadataBlockSize>(tm, v));
}
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -6,11 +6,14 @@ using namespace persistent_data;
using namespace std; using namespace std;
using namespace thin_provisioning; using namespace thin_provisioning;
//----------------------------------------------------------------
namespace { namespace {
void dump(string const &path) { void dump(string const &path) {
metadata md(path); metadata md(path);
human_readable::ptr emitter(new human_readable);
md.check(); md.dump();
} }
void usage(string const &cmd) { void usage(string const &cmd) {
@ -29,3 +32,5 @@ int main(int argc, char **argv)
return 0; return 0;
} }
//----------------------------------------------------------------

View File

@ -8,32 +8,27 @@ using namespace std;
//---------------------------------------------------------------- //----------------------------------------------------------------
template <uint32_t BlockSize> transaction_manager::transaction_manager(typename block_manager<>::ptr bm,
transaction_manager<BlockSize>::transaction_manager(typename block_manager<BlockSize>::ptr bm, space_map::ptr sm)
space_map::ptr sm)
: bm_(bm), : bm_(bm),
sm_(sm) sm_(sm)
{ {
} }
template <uint32_t BlockSize> transaction_manager::~transaction_manager()
transaction_manager<BlockSize>::~transaction_manager()
{ {
} }
template <uint32_t BlockSize> transaction_manager::write_ref
typename transaction_manager<BlockSize>::write_ref transaction_manager::begin(block_address superblock)
transaction_manager<BlockSize>::begin(block_address superblock)
{ {
write_ref wr = bm_->superblock(superblock); write_ref wr = bm_->superblock(superblock);
wipe_shadow_table(); wipe_shadow_table();
return wr; return wr;
} }
template <uint32_t BlockSize> transaction_manager::write_ref
typename transaction_manager<BlockSize>::write_ref transaction_manager::begin(block_address superblock, validator v)
transaction_manager<BlockSize>::begin(block_address superblock,
validator v)
{ {
write_ref wr = bm_->superblock(superblock, v); write_ref wr = bm_->superblock(superblock, v);
wipe_shadow_table(); wipe_shadow_table();
@ -41,9 +36,8 @@ transaction_manager<BlockSize>::begin(block_address superblock,
} }
// FIXME: these explicit try/catches are gross // FIXME: these explicit try/catches are gross
template <uint32_t BlockSize> transaction_manager::write_ref
typename transaction_manager<BlockSize>::write_ref transaction_manager::new_block()
transaction_manager<BlockSize>::new_block()
{ {
block_address b = sm_->new_block(); block_address b = sm_->new_block();
try { try {
@ -61,9 +55,8 @@ transaction_manager<BlockSize>::new_block()
} }
} }
template <uint32_t BlockSize> transaction_manager::write_ref
typename transaction_manager<BlockSize>::write_ref transaction_manager::new_block(validator v)
transaction_manager<BlockSize>::new_block(validator v)
{ {
block_address b = sm_->new_block(); block_address b = sm_->new_block();
try { try {
@ -81,9 +74,8 @@ transaction_manager<BlockSize>::new_block(validator v)
} }
// FIXME: make exception safe // FIXME: make exception safe
template <uint32_t BlockSize> pair<transaction_manager::write_ref, bool>
pair<typename transaction_manager<BlockSize>::write_ref, bool> transaction_manager::shadow(block_address orig)
transaction_manager<BlockSize>::shadow(block_address orig)
{ {
if (is_shadow(orig) && if (is_shadow(orig) &&
!sm_->count_possibly_greater_than_one(orig)) !sm_->count_possibly_greater_than_one(orig))
@ -91,7 +83,7 @@ transaction_manager<BlockSize>::shadow(block_address orig)
read_ref src = bm_->read_lock(orig); read_ref src = bm_->read_lock(orig);
write_ref dest = bm_->write_lock_zero(sm_->new_block()); write_ref dest = bm_->write_lock_zero(sm_->new_block());
::memcpy(dest.data(), src.data(), BlockSize); ::memcpy(dest.data(), src.data(), MD_BLOCK_SIZE);
ref_t count = sm_->get_count(orig); ref_t count = sm_->get_count(orig);
if (count == 0) if (count == 0)
@ -102,9 +94,8 @@ transaction_manager<BlockSize>::shadow(block_address orig)
} }
// FIXME: duplicate code // FIXME: duplicate code
template <uint32_t BlockSize> pair<transaction_manager::write_ref, bool>
pair<typename transaction_manager<BlockSize>::write_ref, bool> transaction_manager::shadow(block_address orig, validator v)
transaction_manager<BlockSize>::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))
@ -112,54 +103,48 @@ transaction_manager<BlockSize>::shadow(block_address orig, validator v)
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);
::memcpy(dest->data_, src->data_, BlockSize); ::memcpy(dest.data(), src.data(), MD_BLOCK_SIZE);
ref_t count = sm_->get_count(orig); ref_t count = sm_->get_count(orig);
if (count == 0) if (count == 0)
throw runtime_error("shadowing free block"); throw runtime_error("shadowing free block");
sm_->dec(orig); sm_->dec(orig);
add_shadow(dest->location_); add_shadow(dest.get_location());
return make_pair(dest, count > 1); return make_pair(dest, count > 1);
} }
template <uint32_t BlockSize> transaction_manager::read_ref
typename transaction_manager<BlockSize>::read_ref transaction_manager::read_lock(block_address b)
transaction_manager<BlockSize>::read_lock(block_address b)
{ {
return bm_->read_lock(b); return bm_->read_lock(b);
} }
template <uint32_t BlockSize> transaction_manager::read_ref
typename transaction_manager<BlockSize>::read_ref transaction_manager::read_lock(block_address b, validator v)
transaction_manager<BlockSize>::read_lock(block_address b, validator v)
{ {
return bm_->read_lock(b, v); return bm_->read_lock(b, v);
} }
template <uint32_t BlockSize>
void void
transaction_manager<BlockSize>::add_shadow(block_address b) transaction_manager::add_shadow(block_address b)
{ {
shadows_.insert(b); shadows_.insert(b);
} }
template <uint32_t BlockSize>
void void
transaction_manager<BlockSize>::remove_shadow(block_address b) transaction_manager::remove_shadow(block_address b)
{ {
shadows_.erase(b); shadows_.erase(b);
} }
template <uint32_t BlockSize>
bool bool
transaction_manager<BlockSize>::is_shadow(block_address b) const transaction_manager::is_shadow(block_address b) const
{ {
return shadows_.count(b) > 0; return shadows_.count(b) > 0;
} }
template <uint32_t BlockSize>
void void
transaction_manager<BlockSize>::wipe_shadow_table() transaction_manager::wipe_shadow_table()
{ {
shadows_.clear(); shadows_.clear();
} }

View File

@ -10,19 +10,18 @@
//---------------------------------------------------------------- //----------------------------------------------------------------
namespace persistent_data { namespace persistent_data {
template <uint32_t MetadataBlockSize>
class transaction_manager : boost::noncopyable { class transaction_manager : boost::noncopyable {
public: public:
typedef boost::shared_ptr<transaction_manager<MetadataBlockSize> > ptr; typedef boost::shared_ptr<transaction_manager> ptr;
typedef typename block_manager<MetadataBlockSize>::read_ref read_ref; typedef typename block_manager<>::read_ref read_ref;
typedef typename block_manager<MetadataBlockSize>::write_ref write_ref; typedef typename block_manager<>::write_ref write_ref;
typedef typename block_manager<MetadataBlockSize>::validator::ptr validator; typedef typename block_manager<>::validator::ptr validator;
// If the space map is persistent, then the caller should // If the space map is persistent, then the caller should
// hold onto a reference and remember to call sm_->commit() // hold onto a reference and remember to call sm_->commit()
// and update the superblock before dropping the superblock // and update the superblock before dropping the superblock
// reference. // reference.
transaction_manager(typename block_manager<MetadataBlockSize>::ptr bm, transaction_manager(typename block_manager<>::ptr bm,
space_map::ptr sm); space_map::ptr sm);
~transaction_manager(); ~transaction_manager();
@ -45,7 +44,7 @@ namespace persistent_data {
return sm_; return sm_;
} }
typename block_manager<MetadataBlockSize>::ptr get_bm() { typename block_manager<>::ptr get_bm() {
return bm_; return bm_;
} }
@ -55,15 +54,13 @@ namespace persistent_data {
bool is_shadow(block_address b) const; bool is_shadow(block_address b) const;
void wipe_shadow_table(); void wipe_shadow_table();
typename block_manager<MetadataBlockSize>::ptr bm_; typename block_manager<>::ptr bm_;
space_map::ptr sm_; space_map::ptr sm_;
std::set<block_address> shadows_; std::set<block_address> shadows_;
}; };
} }
#include "transaction_manager.tcc"
//---------------------------------------------------------------- //----------------------------------------------------------------
#endif #endif

View File

@ -14,40 +14,39 @@ using namespace persistent_data;
namespace { namespace {
block_address const NR_BLOCKS = 102400; block_address const NR_BLOCKS = 102400;
transaction_manager<4096>::ptr transaction_manager::ptr
create_tm() { create_tm() {
block_manager<4096>::ptr bm(new block_manager<4096>("./test.data", NR_BLOCKS)); block_manager<>::ptr bm(new block_manager<>("./test.data", NR_BLOCKS));
space_map::ptr sm(new core_map(NR_BLOCKS)); space_map::ptr sm(new core_map(NR_BLOCKS));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm)); transaction_manager::ptr tm(new transaction_manager(bm, sm));
return tm; return tm;
} }
btree<1, uint64_traits, 4096>::ptr btree<1, uint64_traits>::ptr
create_btree() { create_btree() {
uint64_traits::ref_counter rc; uint64_traits::ref_counter rc;
return btree<1, uint64_traits, 4096>::ptr( return btree<1, uint64_traits>::ptr(
new btree<1, uint64_traits, 4096>( new btree<1, uint64_traits>(create_tm(), rc));
create_tm(), rc));
} }
// Checks that a btree is well formed. // Checks that a btree is well formed.
// //
// i) No block should be in the tree more than once. // i) No block should be in the tree more than once.
// //
class constraint_visitor : public btree<1, uint64_traits, 4096>::visitor { class constraint_visitor : public btree<1, uint64_traits>::visitor {
public: public:
bool visit_internal(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits, 4096> const &n) { bool visit_internal(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits> const &n) {
check_duplicate_block(n.get_location()); check_duplicate_block(n.get_location());
return true; return true;
} }
bool visit_internal_leaf(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits, 4096> const &n) { bool visit_internal_leaf(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits> const &n) {
check_duplicate_block(n.get_location()); check_duplicate_block(n.get_location());
return true; return true;
} }
bool visit_leaf(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits, 4096> const &n) { bool visit_leaf(unsigned level, bool is_root, btree_detail::node_ref<uint64_traits> const &n) {
check_duplicate_block(n.get_location()); check_duplicate_block(n.get_location());
return true; return true;
} }
@ -66,8 +65,8 @@ namespace {
set<block_address> seen_; set<block_address> seen_;
}; };
void check_constraints(btree<1, uint64_traits, 4096>::ptr tree) { void check_constraints(btree<1, uint64_traits>::ptr tree) {
typedef btree<1, uint64_traits, 4096> tree_type; typedef btree<1, uint64_traits> tree_type;
tree_type::visitor::ptr v(new constraint_visitor); tree_type::visitor::ptr v(new constraint_visitor);
tree->visit(v); tree->visit(v);

View File

@ -13,22 +13,21 @@ using namespace persistent_data;
namespace { namespace {
block_address const NR_BLOCKS = 10237; block_address const NR_BLOCKS = 10237;
block_address const SUPERBLOCK = 0; block_address const SUPERBLOCK = 0;
unsigned const BLOCK_SIZE = 4096;
transaction_manager<BLOCK_SIZE>::ptr transaction_manager::ptr
create_tm() { create_tm() {
block_manager<BLOCK_SIZE>::ptr bm( block_manager<>::ptr bm(
new block_manager<BLOCK_SIZE>("./test.data", NR_BLOCKS)); new block_manager<>("./test.data", NR_BLOCKS));
space_map::ptr sm(new core_map(1024)); space_map::ptr sm(new core_map(1024));
transaction_manager<BLOCK_SIZE>::ptr tm( transaction_manager::ptr tm(
new transaction_manager<BLOCK_SIZE>(bm, sm)); new transaction_manager(bm, sm));
return tm; return tm;
} }
persistent_space_map::ptr persistent_space_map::ptr
create_sm_disk() { create_sm_disk() {
auto tm = create_tm(); auto tm = create_tm();
return persistent_data::create_disk_sm<BLOCK_SIZE>(tm, NR_BLOCKS); return persistent_data::create_disk_sm(tm, NR_BLOCKS);
} }
} }
@ -136,7 +135,7 @@ BOOST_AUTO_TEST_CASE(test_reopen)
{ {
auto tm = create_tm(); auto tm = create_tm();
auto sm = persistent_data::open_disk_sm<BLOCK_SIZE>(tm, buffer); auto sm = persistent_data::open_disk_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);

View File

@ -13,11 +13,11 @@ using namespace persistent_data;
namespace { namespace {
block_address const NR_BLOCKS = 1024; block_address const NR_BLOCKS = 1024;
transaction_manager<4096>::ptr transaction_manager::ptr
create_tm() { create_tm() {
block_manager<4096>::ptr bm(new block_manager<4096>("./test.data", NR_BLOCKS)); block_manager<>::ptr bm(new block_manager<>("./test.data", NR_BLOCKS));
space_map::ptr sm(new core_map(NR_BLOCKS)); space_map::ptr sm(new core_map(NR_BLOCKS));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm)); transaction_manager::ptr tm(new transaction_manager(bm, sm));
tm->get_sm()->inc(0); tm->get_sm()->inc(0);
return tm; return tm;
} }