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 \
error_set.cc \
metadata.cc \
metadata_disk_structures.cc
metadata_disk_structures.cc \
space_map_disk.cc \
transaction_manager.cc
TEST_SOURCE=\
unit-tests/block_t.cc \
@ -48,16 +50,16 @@ thin_repair: $(OBJECTS) thin_repair.o
unit-tests/block_t: unit-tests/block_t.o
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)
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)
unit-tests/space_map_disk_t: unit-tests/space_map_disk_t.o $(OBJECTS)
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)
unit-tests/metadata_t: unit-tests/metadata_t.o $(OBJECTS)

View File

@ -15,6 +15,8 @@
namespace persistent_data {
uint32_t const MD_BLOCK_SIZE = 4096;
class count_adjuster {
public:
count_adjuster(unsigned &c)
@ -32,7 +34,7 @@ namespace persistent_data {
typedef uint64_t block_address;
template <uint32_t BlockSize>
template <uint32_t BlockSize = MD_BLOCK_SIZE>
class block_manager : private boost::noncopyable {
public:
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
// node data.
template <typename ValueTraits, uint32_t BlockSize>
template <typename ValueTraits>
class node_ref {
public:
explicit node_ref(block_address b, disk_node *raw);
@ -142,31 +142,30 @@ namespace persistent_data {
//------------------------------------------------
//
template <typename ValueTraits, uint32_t BlockSize>
node_ref<ValueTraits, BlockSize>
to_node(typename block_manager<BlockSize>::read_ref &b)
template <typename ValueTraits>
node_ref<ValueTraits>
to_node(typename block_manager<>::read_ref &b)
{
// FIXME: this should return a const read_ref somehow.
return node_ref<ValueTraits, BlockSize>(
return node_ref<ValueTraits>(
b.get_location(),
reinterpret_cast<disk_node *>(
const_cast<unsigned char *>(b.data())));
}
template <typename ValueTraits, uint32_t BlockSize>
node_ref<ValueTraits, BlockSize>
to_node(typename block_manager<BlockSize>::write_ref &b)
template <typename ValueTraits>
node_ref<ValueTraits>
to_node(typename block_manager<>::write_ref &b)
{
return node_ref<ValueTraits, BlockSize>(
return node_ref<ValueTraits>(
b.get_location(),
reinterpret_cast<disk_node *>(
const_cast<unsigned char *>(b.data())));
}
template <uint32_t BlockSize>
class ro_spine : private noncopyable {
public:
ro_spine(typename transaction_manager<BlockSize>::ptr tm)
ro_spine(typename transaction_manager::ptr tm)
: tm_(tm) {
}
@ -177,22 +176,21 @@ namespace persistent_data {
}
template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> get_node() {
return to_node<ValueTraits, BlockSize>(spine_.back());
node_ref<ValueTraits> get_node() {
return to_node<ValueTraits>(spine_.back());
}
private:
typename transaction_manager<BlockSize>::ptr tm_;
std::list<typename block_manager<BlockSize>::read_ref> spine_;
typename transaction_manager::ptr tm_;
std::list<typename block_manager<>::read_ref> spine_;
};
template <uint32_t BlockSize>
class shadow_spine : private noncopyable {
public:
typedef typename transaction_manager<BlockSize>::read_ref read_ref;
typedef typename transaction_manager<BlockSize>::write_ref write_ref;
typedef typename transaction_manager::read_ref read_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) {
}
@ -208,7 +206,7 @@ namespace persistent_data {
return p.second;
}
void step(typename transaction_manager<BlockSize>::write_ref b) {
void step(typename transaction_manager::write_ref b) {
spine_.push_back(b);
if (spine_.size() == 1)
root_ = spine_.front().get_location();
@ -221,8 +219,8 @@ namespace persistent_data {
}
template <typename ValueTraits>
node_ref<ValueTraits, BlockSize> get_node() {
return to_node<ValueTraits, BlockSize>(spine_.back());
node_ref<ValueTraits> get_node() {
return to_node<ValueTraits>(spine_.back());
}
block_address get_block() const {
@ -233,11 +231,11 @@ namespace persistent_data {
return spine_.size() > 1;
}
node_ref<uint64_traits, BlockSize> get_parent() {
node_ref<uint64_traits> get_parent() {
if (spine_.size() < 2)
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 {
@ -249,22 +247,22 @@ namespace persistent_data {
}
private:
typename transaction_manager<BlockSize>::ptr tm_;
std::list<typename block_manager<BlockSize>::write_ref> spine_;
typename transaction_manager::ptr tm_;
std::list<typename block_manager<>::write_ref> spine_;
block_address root_;
};
// FIXME: make a member of btree
template <typename ValueTraits, uint32_t BlockSize>
template <typename ValueTraits>
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;
typedef typename ValueTraits::value_type leaf_type;
for (;;) {
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);
if (!mi)
@ -273,30 +271,30 @@ namespace persistent_data {
if (leaf.get_type() == btree_detail::LEAF)
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);
}
}
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
template <unsigned Levels, typename ValueTraits>
class btree {
public:
typedef boost::shared_ptr<btree<Levels, ValueTraits, BlockSize> > ptr;
typedef boost::shared_ptr<btree<Levels, ValueTraits> > ptr;
typedef uint64_t key[Levels];
typedef typename ValueTraits::value_type value_type;
typedef boost::optional<value_type> maybe_value;
typedef boost::optional<std::pair<unsigned, value_type> > maybe_pair;
typedef typename block_manager<BlockSize>::read_ref read_ref;
typedef typename block_manager<BlockSize>::write_ref write_ref;
typedef typename btree_detail::node_ref<ValueTraits, BlockSize> leaf_node;
typedef typename btree_detail::node_ref<uint64_traits, BlockSize> internal_node;
typedef typename block_manager<>::read_ref read_ref;
typedef typename block_manager<>::write_ref write_ref;
typedef typename btree_detail::node_ref<ValueTraits> leaf_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);
btree(typename transaction_manager<BlockSize>::ptr tm,
btree(typename transaction_manager::ptr tm,
block_address root,
typename ValueTraits::ref_counter rc);
@ -337,22 +335,22 @@ namespace persistent_data {
private:
template <typename ValueTraits2>
void split_node(btree_detail::shadow_spine<BlockSize> &spine,
void split_node(btree_detail::shadow_spine &spine,
block_address parent_index,
uint64_t key,
bool top);
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>
void split_sibling(btree_detail::shadow_spine<BlockSize> &spine,
void split_sibling(btree_detail::shadow_spine &spine,
block_address parent_index,
uint64_t key);
template <typename ValueTraits2>
bool
insert_location(btree_detail::shadow_spine<BlockSize> &spine,
insert_location(btree_detail::shadow_spine &spine,
block_address block,
uint64_t key,
int *index);
@ -361,7 +359,7 @@ namespace persistent_data {
unsigned level, bool is_root,
block_address b) const;
typename persistent_data::transaction_manager<BlockSize>::ptr tm_;
typename persistent_data::transaction_manager::ptr tm_;
bool destroy_;
block_address root_;
NoOpRefCounter<uint64_t> internal_rc_;

249
btree.tcc
View File

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

View File

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

View File

@ -25,17 +25,17 @@ namespace {
// FIXME: get the file size
unsigned const NR_BLOCKS = 1024;
transaction_manager<4096>::ptr
transaction_manager::ptr
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));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm));
transaction_manager::ptr tm(new transaction_manager(bm, sm));
return tm;
}
superblock read_superblock(block_manager<4096>::ptr bm) {
superblock read_superblock(block_manager<>::ptr bm) {
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_traits::unpack(*sbd, sb);
return sb;
@ -45,21 +45,21 @@ namespace {
// devices having mappings defined, which can later be cross
// referenced with the details tree. A separate block_counter is
// 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:
typedef boost::shared_ptr<mapping_validator> ptr;
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) {
}
// Sharing can only occur in level 1 nodes.
// FIXME: not true once we start having held roots.
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) {
throw runtime_error("unexpected sharing in level 0 of mapping tree.");
}
@ -71,8 +71,8 @@ namespace {
}
bool visit_leaf(unsigned level, bool is_root,
btree_detail::node_ref<block_traits, MD_BLOCK_SIZE> const &n) {
bool r = btree_validator<2, block_traits, MD_BLOCK_SIZE>::visit_leaf(level, is_root, n);
btree_detail::node_ref<block_traits> const &n) {
bool r = btree_validator<2, block_traits>::visit_leaf(level, is_root, n);
if (r)
for (unsigned i = 0; i < n.get_nr_entries(); i++)
@ -90,17 +90,17 @@ namespace {
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:
typedef boost::shared_ptr<details_validator> ptr;
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,
btree_detail::node_ref<device_details_traits, MD_BLOCK_SIZE> const &n) {
bool r = btree_validator<1, device_details_traits, MD_BLOCK_SIZE>::visit_leaf(level, is_root, n);
btree_detail::node_ref<device_details_traits> const &n) {
bool r = btree_validator<1, device_details_traits>::visit_leaf(level, is_root, n);
if (r)
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)
: tm_(open_tm(dev_path)),
sb_(read_superblock(tm_->get_bm())),
metadata_sm_(open_metadata_sm<MD_BLOCK_SIZE>(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_))),
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_(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_))
{
#if 0

View File

@ -16,8 +16,6 @@
//----------------------------------------------------------------
namespace thin_provisioning {
unsigned const MD_BLOCK_SIZE = 4096;
// FIXME: don't use namespaces in a header
using namespace base;
using namespace persistent_data;
@ -87,10 +85,9 @@ namespace thin_provisioning {
//------------------------------------------------
template <uint32_t BlockSize>
class mtree_ref_counter {
public:
mtree_ref_counter(typename transaction_manager<BlockSize>::ptr tm)
mtree_ref_counter(transaction_manager::ptr tm)
: tm_(tm) {
}
@ -101,14 +98,13 @@ namespace thin_provisioning {
}
private:
typename transaction_manager<BlockSize>::ptr tm_;
transaction_manager::ptr tm_;
};
template <uint32_t BlockSize>
struct mtree_traits {
typedef base::__le64 disk_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) {
value = base::to_cpu<uint64_t>(disk);
@ -146,8 +142,8 @@ namespace thin_provisioning {
class metadata {
public:
typedef boost::shared_ptr<metadata> ptr;
typedef block_manager<MD_BLOCK_SIZE>::read_ref read_ref;
typedef block_manager<MD_BLOCK_SIZE>::write_ref write_ref;
typedef block_manager<>::read_ref read_ref;
typedef block_manager<>::write_ref write_ref;
metadata(std::string const &dev_path);
~metadata();
@ -173,27 +169,30 @@ namespace thin_provisioning {
thin::ptr open_thin(thin_dev_t);
// Validation and repair
// Validation
boost::optional<persistent_data::error_set::ptr> check();
// Dumping metadata
void dump();
private:
friend class thin;
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, mtree_traits<MD_BLOCK_SIZE>, MD_BLOCK_SIZE> dev_tree;
typedef persistent_data::btree<2, block_traits, MD_BLOCK_SIZE> mapping_tree;
typedef persistent_data::btree<1, block_traits, MD_BLOCK_SIZE> single_mapping_tree;
typedef persistent_data::btree<1, device_details_traits> detail_tree;
typedef persistent_data::btree<1, mtree_traits> dev_tree;
typedef persistent_data::btree<2, block_traits> mapping_tree;
typedef persistent_data::btree<1, block_traits> single_mapping_tree;
// Declaration order is important here
tm_ptr tm_;
superblock sb_;
sm_disk_detail::sm_metadata<MD_BLOCK_SIZE>::ptr metadata_sm_;
sm_disk_detail::sm_disk<MD_BLOCK_SIZE>::ptr data_sm_;
checked_space_map::ptr metadata_sm_;
checked_space_map::ptr data_sm_;
detail_tree details_;
dev_tree mappings_top_level_;
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 "space_map.h"
#include "transaction_manager.h"
#include "endian_utils.h"
#include "space_map_disk_structures.h"
#include "math_utils.h"
//----------------------------------------------------------------
namespace persistent_data {
class checked_space_map : public persistent_space_map {
public:
typedef boost::shared_ptr<checked_space_map> ptr;
namespace sm_disk_detail {
using namespace base;
using namespace persistent_data;
virtual void check(block_counter &counter) const = 0;
};
template <uint32_t BlockSize>
class bitmap {
public:
typedef typename transaction_manager<BlockSize>::read_ref read_ref;
typedef typename transaction_manager<BlockSize>::write_ref write_ref;
checked_space_map::ptr
create_disk_sm(transaction_manager::ptr tm, block_address nr_blocks);
bitmap(typename transaction_manager<BlockSize>::ptr tm,
index_entry const &ie)
: tm_(tm),
ie_(ie) {
}
checked_space_map::ptr
open_disk_sm(transaction_manager::ptr tm, void *root);
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<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));
}
checked_space_map::ptr
open_metadata_sm(transaction_manager::ptr tm, void * root);
}
//----------------------------------------------------------------

View File

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

View File

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

View File

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

View File

@ -14,40 +14,39 @@ using namespace persistent_data;
namespace {
block_address const NR_BLOCKS = 102400;
transaction_manager<4096>::ptr
transaction_manager::ptr
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));
transaction_manager<4096>::ptr tm(new transaction_manager<4096>(bm, sm));
transaction_manager::ptr tm(new transaction_manager(bm, sm));
return tm;
}
btree<1, uint64_traits, 4096>::ptr
btree<1, uint64_traits>::ptr
create_btree() {
uint64_traits::ref_counter rc;
return btree<1, uint64_traits, 4096>::ptr(
new btree<1, uint64_traits, 4096>(
create_tm(), rc));
return btree<1, uint64_traits>::ptr(
new btree<1, uint64_traits>(create_tm(), rc));
}
// Checks that a btree is well formed.
//
// 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:
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());
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());
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());
return true;
}
@ -66,8 +65,8 @@ namespace {
set<block_address> seen_;
};
void check_constraints(btree<1, uint64_traits, 4096>::ptr tree) {
typedef btree<1, uint64_traits, 4096> tree_type;
void check_constraints(btree<1, uint64_traits>::ptr tree) {
typedef btree<1, uint64_traits> tree_type;
tree_type::visitor::ptr v(new constraint_visitor);
tree->visit(v);

View File

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

View File

@ -13,11 +13,11 @@ using namespace persistent_data;
namespace {
block_address const NR_BLOCKS = 1024;
transaction_manager<4096>::ptr
transaction_manager::ptr
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));
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);
return tm;
}