write a lot of the persistent data classes

This commit is contained in:
Joe Thornber 2011-06-23 14:47:08 +01:00
parent 6b8b16c70a
commit 2e39670ff9
12 changed files with 1300 additions and 3 deletions

View File

@ -1,8 +1,11 @@
SOURCE=\
main.cc
block.cc \
main.cc \
metadata.cc \
transaction_manager.cc
OBJECTS=$(subst .cc,.o,$(SOURCE))
CPPFLAGS=-Wall -Weffc++ -std=c++0x
CPPFLAGS=-Wall -std=c++0x
INCLUDES=
LIBS=-lstdc++
@ -13,4 +16,9 @@ LIBS=-lstdc++
g++ -c $(CPPFLAGS) $(INCLUDES) -o $@ $<
multisnap_display: $(OBJECTS)
g++ -o $@ $+ $(LIBS)
g++ -o $@ $+ $(LIBS)
main.o: block.h
block.o: block.h
transaction_manager.o: transaction_manager.h block.h
metadata.o: block.h transaction_manager.h btree.h metadata.h

116
block.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef BLOCK_H
#define BLOCK_H
#include <stdint.h>
#include <map>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
//----------------------------------------------------------------
namespace persistent_data {
typedef uint64_t block_address;
template <uint32_t BlockSize>
class block_manager : private boost::noncopyable {
public:
typedef boost::shared_ptr<block_manager> ptr;
block_manager(std::string const &path);
~block_manager();
typedef unsigned char buffer[BlockSize];
typedef unsigned char const const_buffer[BlockSize];
class block;
class block_validator {
public:
virtual ~block_validator() {}
virtual void check(block const &b) const = 0;
virtual void prepare(block &b) const = 0;
};
struct block {
typedef boost::optional<block_validator> maybe_validator;
block(block_address location,
maybe_validator v = maybe_validator())
: location_(location),
validator_(v) {
}
block_address location_;
buffer data_;
boost::optional<block_validator> validator_;
};
typedef boost::shared_ptr<block> block_ptr;
class read_ref {
public:
read_ref(block_ptr b);
virtual ~read_ref() {}
block_address get_location() const;
const_buffer &data() const;
protected:
block_ptr block_;
};
// Inherited from read_ref, since you can read a block that's write
// locked.
class write_ref : public read_ref {
public:
using read_ref::data;
buffer &data();
};
// Locking methods
read_ref
read_lock(block_address location);
boost::optional<read_ref>
read_try_lock(block_address location);
write_ref
write_lock(block_address location);
write_ref
write_lock_zero(block_address location);
// Validator variants
read_ref
read_lock(block_address location, block_validator const &v);
boost::optional<read_ref>
read_try_lock(block_address location, block_validator const &v);
write_ref
write_lock(block_address location, block_validator const &v);
write_ref
write_lock_zero(block_address location, block_validator const &v);
// Use this to commit changes
void flush(write_ref super_block);
private:
void read_block(block &b);
void write_block(block const &b);
void zero_block(block &b);
void write_and_release(block *b);
int fd_;
};
}
//----------------------------------------------------------------
#endif

207
block.tcc Normal file
View File

@ -0,0 +1,207 @@
#include "block.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <stdexcept>
using namespace boost;
using namespace persistent_data;
//----------------------------------------------------------------
template <uint32_t BlockSize>
block_manager<BlockSize>::read_ref::read_ref(block_manager::block_ptr b)
: block_(b)
{
}
template <uint32_t BlockSize>
block_address
block_manager<BlockSize>::read_ref::get_location() const
{
return block_->location_;
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::const_buffer &
block_manager<BlockSize>::read_ref::data() const
{
return block_->data_;
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::buffer &
block_manager<BlockSize>::write_ref::data()
{
return read_ref::block_->data_;
}
//----------------------------------------------------------------
template <uint32_t BlockSize>
block_manager<BlockSize>::block_manager(std::string const &path)
{
fd_ = ::open(path.c_str(), O_RDWR | O_EXCL);
if (fd_ < 0)
throw std::runtime_error("couldn't open file");
}
template <uint32_t BlockSize>
block_manager<BlockSize>::~block_manager()
{
::close(fd_);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::read_ref
block_manager<BlockSize>::read_lock(block_address location)
{
block_ptr b(new block(location));
read_block(b);
return read_ref(b);
}
template <uint32_t BlockSize>
optional<typename block_manager<BlockSize>::read_ref>
block_manager<BlockSize>::read_try_lock(block_address location)
{
return read_lock(location);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::write_ref
block_manager<BlockSize>::write_lock(block_address location)
{
block_ptr b(new block(location), write_and_release);
read_block(b);
return write_ref(b);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::write_ref
block_manager<BlockSize>::write_lock_zero(block_address location)
{
block_ptr b(new block(location), write_and_release);
zero_block(b);
return write_ref(b);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::read_ref
block_manager<BlockSize>::read_lock(block_address location,
block_manager<BlockSize>::block_validator const &v)
{
block_ptr b(new block(location, v));
read_block(b);
return read_ref(b);
}
template <uint32_t BlockSize>
optional<typename block_manager<BlockSize>::read_ref>
block_manager<BlockSize>::read_try_lock(block_address location,
block_manager<BlockSize>::block_validator const &v)
{
return read_lock(location, v);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::write_ref
block_manager<BlockSize>::write_lock(block_address location,
block_manager<BlockSize>::block_validator const &v)
{
block_ptr b(new block(location, v), write_and_release);
read_block(b);
return write_ref(b);
}
template <uint32_t BlockSize>
typename block_manager<BlockSize>::write_ref
block_manager<BlockSize>::write_lock_zero(block_address location,
block_manager<BlockSize>::block_validator const &v)
{
block_ptr b(new block(location, v), write_and_release);
zero_block(b);
return write_ref(b);
}
template <uint32_t BlockSize>
void
block_manager<BlockSize>::flush(block_manager<BlockSize>::write_ref super_block)
{
write_block(super_block);
::fsync(fd_);
}
template <uint32_t BlockSize>
void
block_manager<BlockSize>::read_block(block &b)
{
std::cerr << "reading block: " << b->location << std::endl;
off_t r;
r = ::lseek(fd_, BlockSize * b->location_, SEEK_SET);
if (r == (off_t) -1)
throw std::runtime_error("lseek failed");
ssize_t n;
size_t remaining = BlockSize;
unsigned char *buf = b->data_;
do {
n = ::read(fd_, buf, remaining);
if (n > 0) {
remaining -= n;
buf += n;
}
} while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN)));
if (n < 0)
throw std::runtime_error("read failed");
}
template <uint32_t BlockSize>
void
block_manager<BlockSize>::write_block(block const &b)
{
std::cerr << "writing block: " << b->location << std::endl;
off_t r;
r = ::lseek(fd_, BlockSize * b->location_, SEEK_SET);
if (r == (off_t) -1)
throw std::runtime_error("lseek failed");
ssize_t n;
size_t remaining = BlockSize;
unsigned char *buf = b->data_;
do {
n = ::read(fd_, buf, remaining);
if (n > 0) {
remaining -= n;
buf += n;
}
} while (remaining && ((n > 0) || (n == EINTR) || (n == EAGAIN)));
if (n < 0)
throw std::runtime_error("write failed");
}
template <uint32_t BlockSize>
void
block_manager<BlockSize>::zero_block(block &b)
{
memset(b->data_, 0, BlockSize);
}
template <uint32_t BlockSize>
void
block_manager<BlockSize>::write_and_release(block *b)
{
write_block(b);
delete b;
}
//----------------------------------------------------------------

49
btree.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef BTREE_H
#define BTREE_H
#include "transaction_manager.h"
//----------------------------------------------------------------
namespace persistent_data {
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
class btree {
public:
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 boost::shared_ptr<btree<Levels, ValueTraits, BlockSize> > ptr;
typedef typename block_manager<BlockSize>::read_ref read_ref;
typedef typename block_manager<BlockSize>::write_ref write_ref;
btree(boost::shared_ptr<transaction_manager<BlockSize> > tm);
btree(boost::shared_ptr<transaction_manager<BlockSize> > tm,
block_address root);
~btree();
maybe_value lookup(key const &key) const;
maybe_pair lookup_le(key const &key) const;
maybe_pair lookup_ge(key const &key) const;
void insert(key const &key, typename ValueTraits::value_type const &value);
void remove(key const &key);
void set_root(block_address root);
block_address get_root() const;
ptr clone() const;
// free the on disk btree when the destructor is called
void destroy();
private:
typename persistent_data::transaction_manager<BlockSize>::ptr tm_;
bool destroy_;
block_address root_;
};
};
//----------------------------------------------------------------
#endif

255
btree.tcc Normal file
View File

@ -0,0 +1,255 @@
#include "btree.h"
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
using namespace boost;
using namespace persistent_data;
//----------------------------------------------------------------
namespace {
//------------------------------------------------
// On disk data layout for btree nodes
enum node_flags {
INTERNAL_NODE = 1,
LEAF_NODE = 1 << 1
};
struct node_header {
__le32 csum;
__le32 flags;
__le64 blocknr; /* which block this node is supposed to live in */
__le32 nr_entries;
__le32 max_entries;
} __attribute__((packed));
struct node {
struct node_header header;
__le64 keys[0];
} __attribute__((packed));
//------------------------------------------------
// Class that acts as an interface over the raw little endian btree
// node data.
class node {
public:
enum type {
INTERNAL,
LEAF
};
type get_type() const;
void set_type(type t);
unsigned get_nr_entries() const;
void set_nr_entries(unsigned n);
unsigned get_max_entries() const;
void set_max_entries(unsigned n);
uint64_t key_at(unsigned i) const;
template <typename ValueTraits>
typename ValueTraits::value_type value_at(unsigned i) const;
private:
struct node *raw_;
};
//------------------------------------------------
// Various searches
int bsearch(node const &n, uint64_t key, int want_hi)
{
int lo = -1, hi = n.get_nr_entries();
while(hi - lo > 1) {
int mid = lo + ((hi - lo) / 2);
uint64_t mid_key = n.key_at(mid);
if (mid_key == key)
return mid;
if (mid_key < key)
lo = mid;
else
hi = mid;
}
return want_hi ? hi : lo;
}
optional<unsigned> exact_search(node const &n, uint64_t key) {
int i = bsearch(n, key, 0);
if (i < 0 || static_cast<unsigned>(i) >= n.get_nr_entries())
return optional<unsigned>();
return optional<unsigned>(i);
}
//------------------------------------------------
//
template <uint32_t BlockSize>
node &to_node(typename block_manager<BlockSize>::write_ref b);
unsigned
calc_max_entries(uint32_t bs);
// Spines
template <uint32_t BlockSize>
class ro_spine : private noncopyable {
public:
void step(block_address b);
node get_node() const;
private:
};
class internal_traits {
public:
typedef uint64_t value_type;
};
template <typename ValueTraits, uint32_t BlockSize, typename Search>
optional<typename ValueTraits::value_type>
lookup_raw(ro_spine<BlockSize> &spine, block_address block, uint64_t key) {
using namespace boost;
typedef typename ValueTraits::value_type leaf_type;
typedef typename internal_traits::value_type internal_type;
Search find;
for (;;) {
spine.step(block);
node &n = spine.node();
auto mi = find(n, key);
if (!mi)
return optional<leaf_type>();
if (n.get_type() == node::LEAF)
return optional<leaf_type>(n.value_at(*mi));
block = n.value_at<internal_type>(*mi);
}
}
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
btree<Levels, ValueTraits, BlockSize>::btree(shared_ptr<transaction_manager<BlockSize> > tm)
: tm_(tm),
destroy_(false)
{
write_ref root = tm_.new_block();
node &n = to_node(root);
n.set_type(node::LEAF);
n.set_nr_entries(0);
n.set_max_entries(calc_max_entries(BlockSize));
root_ = root.location();
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
btree<Levels, ValueTraits, BlockSize>::btree(shared_ptr<transaction_manager<BlockSize> > tm,
block_address root)
: tm_(tm),
destroy_(false),
root_(root)
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
btree<Levels, ValueTraits, BlockSize>::~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
{
ro_spine<BlockSize> spine;
block_address root = root_;
for (unsigned level = 0; level < Levels - 1; ++level) {
auto mroot = lookup_raw<internal_traits, BlockSize, exact_search>(spine, root, key[level]);
if (!mroot)
return maybe_value();
root = *mroot;
}
return lookup_raw<ValueTraits, BlockSize, exact_search>(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
{
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
{
return maybe_pair();
}
#if 0
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
void
btree<Levels, ValueTraits, BlockSize>::insert(key const &key, typename ValueTraits::value_type const &value)
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
void
btree<Levels, ValueTraits, BlockSize>::remove(key const &key)
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
block_address
btree<Levels, ValueTraits, BlockSize>::get_root() const
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
void
btree<Levels, ValueTraits, BlockSize>::set_root(block_address root)
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
block_address
btree<Levels, ValueTraits, BlockSize>::get_root() const
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
ptr
btree<Levels, ValueTraits, BlockSize>::clone() const
{
}
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
void
btree<Levels, ValueTraits, BlockSize>::destroy()
{
}
#endif
//----------------------------------------------------------------

61
core-map.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef CORE_MAP_H
#define CORE_MAP_H
#include "space_map.h"
//----------------------------------------------------------------
namespace persistent_data {
class core_map : public space_map {
public:
core_map(block_address nr_blocks)
: counts_(nr_blocks, 0) {
}
block_address get_nr_blocks() const {
counts_.size();
}
block_address get_nr_free() const {
nr_free_;
}
ref_t get_count(block_address b) const {
return counts_[b];
}
void set_count(block_address b, ref_t c) {
counts_[b] = c;
}
void commit() {
}
void inc_block(block_address b) {
counts_[b]++;
}
void dec_block(block_address b) {
counts_[b]--;
}
block_address new_block() {
for (block_address i = 0; i < counts_.size(); i++)
if (counts_[i] == 0) {
counts_[i] = 1;
return i;
}
}
bool count_possibly_greater_than_one(block_address b) const {
return counts_[i] > 1;
}
private:
std::vector<ref_t> counts_;
};
}
//----------------------------------------------------------------
#endif

View File

@ -1,3 +1,5 @@
#include "block.h"
#include <iostream>
int main(int argc, char **argv)

215
metadata.cc Normal file
View File

@ -0,0 +1,215 @@
#include "metadata.h"
#include <stdexcept>
using namespace persistent_data;
using namespace multisnap;
//----------------------------------------------------------------
namespace {
typedef uint8_t __le8;
typedef uint8_t __u8;
typedef uint32_t __le32;
typedef uint64_t __le64;
uint32_t const SUPERBLOCK_MAGIC = 27022010;
block_address const SUPERBLOCK_LOCATION = 0;
uint32_t const VERSION = 1;
unsigned const METADATA_CACHE_SIZE = 1024;
unsigned const SECTOR_TO_BLOCK_SHIFT = 3;
unsigned const SPACE_MAP_ROOT_SIZE = 128;
struct multisnap_super_block {
__le32 csum_;
__le32 flags_;
__le64 blocknr_; /* this block number, dm_block_t */
__u8 uuid_[16];
__le64 magic_;
__le32 version_;
__le32 time_;
__le64 trans_id_;
/* root for userspace's transaction (for migration and friends) */
__le64 held_root_;
__u8 data_space_map_root_[SPACE_MAP_ROOT_SIZE];
__u8 metadata_space_map_root_[SPACE_MAP_ROOT_SIZE];
/* 2 level btree mapping (dev_id, (dev block, time)) -> data block */
__le64 data_mapping_root_;
/* device detail root mapping dev_id -> device_details */
__le64 device_details_root_;
__le32 data_block_size_; /* in 512-byte sectors */
__le32 metadata_block_size_; /* in 512-byte sectors */
__le64 metadata_nr_blocks_;
__le32 compat_flags_;
__le32 incompat_flags_;
} __attribute__ ((packed));
struct device_details {
__le64 dev_size_;
__le64 mapped_blocks_;
__le64 transaction_id_; /* when created */
__le32 creation_time_;
__le32 snapshotted_time_;
} __attribute__ ((packed));
}
//----------------------------------------------------------------
metadata::thin::maybe_address
metadata::thin::lookup(block_address thin_block)
{
uint64_t key[2] = {dev_, thin_block};
return metadata_->mappings_.lookup(key);
}
void
metadata::thin::insert(block_address thin_block, block_address data_block)
{
uint64_t key[2] = {dev_, thin_block};
return metadata_->mappings_.insert(key, data_block);
}
void
metadata::thin::remove(block_address thin_block)
{
uint64_t key[2] = {dev_, thin_block};
metadata_->mappings_.remove(key);
}
#if 0
//--------------------------------
metadata::metadata(std::string const &metadata_dev,
sector_t data_block_size,
block_address nr_data_blocks)
{
}
metadata::~metadata()
{
}
void
metadata::commit()
{
}
#endif
void
metadata::create_thin(dev_t dev)
{
uint64_t key[1] = {dev};
if (device_exists(dev))
throw std::runtime_error("Device already exists");
single_mapping_tree::ptr new_tree(new single_mapping_tree(tm_));
mappings_top_level_.insert(key, *new_tree);
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
}
void
metadata::create_snap(dev_t dev, dev_t origin)
{
uint64_t snap_key[1] = {dev};
uint64_t origin_key[1] = {origin};
auto mtree = mappings_top_level_.lookup(origin_key);
if (!mtree)
throw std::runtime_error("unknown origin");
single_mapping_tree::ptr clone(mtree->clone());
mappings_top_level_.insert(snap_key, *clone);
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
time_++;
auto o = open(origin);
auto s = open(dev);
o->set_snapshot_time(time_);
s->set_snapshot_time(time_);
s->set_mapped_blocks(o->get_mapped_blocks());
}
void
metadata::del(dev_t dev)
{
uint64_t key[1] = {dev};
mappings_top_level_.remove(key);
}
#if 0
void
metadata::set_transaction_id(uint64_t id)
{
}
uint64_t
metadata::get_transaction_id() const
{
}
block_address
metadata::get_held_root() const
{
}
thin_ptr
metadata::open_device(dev_t)
{
}
block_address
metadata::alloc_data_block()
{
}
void
metadata::free_data_block(block_address b)
{
}
block_address
metadata::get_nr_free_data_blocks() const
{
}
sector_t
metadata::get_data_block_size() const
{
}
block_address
metadata::get_data_dev_size() const
{
}
#endif
bool
metadata::device_exists(dev_t dev) const
{
uint64_t key[1] = {dev};
auto mval = details_.lookup(key);
return mval;
}
//----------------------------------------------------------------

110
metadata.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef MULTISNAP_METADATA_H
#define MULTISNAP_METADATA_H
#include "block.h"
#include "transaction_manager.h"
#include "btree.h"
#include <string>
#include <boost/shared_ptr.hpp>
//----------------------------------------------------------------
// FIXME: make a const
#define BLOCK_SIZE 4096
namespace multisnap {
typedef uint64_t sector_t;
class metadata {
public:
typedef boost::shared_ptr<metadata> ptr;
typedef persistent_data::block_address block_address;
metadata(std::string const &metadata_dev,
sector_t data_block_size,
persistent_data::block_address nr_data_blocks);
~metadata();
void commit();
typedef uint32_t dev_t;
void create_thin(dev_t dev);
void create_snap(dev_t dev, dev_t origin);
void del(dev_t);
void set_transaction_id(uint64_t id);
uint64_t get_transaction_id() const;
block_address get_held_root() const;
block_address alloc_data_block();
void free_data_block(block_address b);
// accessors
block_address get_nr_free_data_blocks() const;
sector_t get_data_block_size() const;
block_address get_data_dev_size() const;
class thin {
public:
typedef boost::shared_ptr<thin> ptr;
dev_t get_dev_t() const;
typedef boost::optional<block_address> maybe_address;
maybe_address lookup(block_address thin_block);
void insert(block_address thin_block, block_address data_block);
void remove(block_address thin_block);
void set_snapshot_time(uint32_t time);
persistent_data::block_address get_mapped_blocks() const;
void set_mapped_blocks(persistent_data::block_address count);
private:
dev_t dev_;
metadata::ptr metadata_;
};
thin::ptr open(dev_t);
private:
friend class thin;
bool device_exists(dev_t dev) const;
class detail_traits {
public:
typedef uint64_t value_type;
};
class map_traits {
public:
typedef block_address value_type;
};
class dev_traits {
public:
typedef persistent_data::btree<1, map_traits, BLOCK_SIZE> value_type;
};
uint32_t time_;
persistent_data::transaction_manager<BLOCK_SIZE>::ptr tm_;
typedef persistent_data::btree<1, detail_traits, BLOCK_SIZE> detail_tree;
typedef persistent_data::btree<1, dev_traits, BLOCK_SIZE> dev_tree;
typedef persistent_data::btree<2, map_traits, BLOCK_SIZE> mapping_tree;
typedef persistent_data::btree<1, map_traits, BLOCK_SIZE> single_mapping_tree;
detail_tree details_;
dev_tree mappings_top_level_;
mapping_tree mappings_;
};
};
//----------------------------------------------------------------
#endif

41
space_map.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef SPACE_MAP_H
#define SPACE_MAP_H
#include "block.h"
#include <boost/shared_ptr.hpp>
//----------------------------------------------------------------
namespace persistent_data {
typedef uint32_t ref_t;
class space_map {
public:
typedef boost::shared_ptr<space_map> ptr;
virtual ~space_map() {};
virtual block_address get_nr_blocks() const = 0;
virtual block_address get_nr_free() const = 0;
virtual ref_t get_count(block_address b) const = 0;
virtual void set_count(block_address b, ref_t c) = 0;
virtual void commit() = 0;
virtual void inc_block(block_address b) = 0;
virtual void dec_block(block_address b) = 0;
virtual block_address new_block() = 0;
virtual bool count_possibly_greater_than_one(block_address b) const = 0;
};
class persistent_space_map {
public:
virtual size_t root_size() = 0;
virtual void copy_root(void *dest, size_t len) = 0;
};
}
//----------------------------------------------------------------
#endif

59
transaction_manager.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef TRANSACTION_MANAGER_H
#define TRANSACTION_MANAGER_H
#include "block.h"
#include "space_map.h"
#include <set>
#include <boost/shared_ptr.hpp>
//----------------------------------------------------------------
namespace persistent_data {
template <uint32_t MetadataBlockSize>
class transaction_manager : public boost::noncopyable {
public:
typedef boost::shared_ptr<transaction_manager<MetadataBlockSize> > ptr;
transaction_manager(typename block_manager<MetadataBlockSize>::ptr bm,
space_map::ptr sm);
~transaction_manager();
typedef typename block_manager<MetadataBlockSize>::read_ref read_ref;
typedef typename block_manager<MetadataBlockSize>::write_ref write_ref;
typedef typename block_manager<MetadataBlockSize>::block_validator block_validator;
void reserve_block(block_address location);
void begin();
void pre_commit();
void commit(write_ref superblock);
block_address alloc_block();
write_ref new_block();
write_ref new_block(block_validator const &v);
write_ref shadow(block_address orig, bool &inc_children);
write_ref shadow(block_address orig, block_validator const &v, bool &inc_children);
read_ref read_lock(block_address b);
read_ref read_lock(block_address b, block_validator const &v);
void inc(block_address b);
void dec(block_address b);
uint32_t ref_count(block_address b) const;
private:
void add_shadow(block_address b);
bool is_shadow(block_address b);
void wipe_shadow_table();
typename block_manager<MetadataBlockSize>::ptr bm_;
space_map::ptr sm_;
std::set<block_address> shadows_;
};
}
//----------------------------------------------------------------
#endif

174
transaction_manager.tcc Normal file
View File

@ -0,0 +1,174 @@
#include "transaction_manager.h"
#include <string.h>
using namespace boost;
using namespace persistent_data;
//----------------------------------------------------------------
template <uint32_t BlockSize>
transaction_manager<BlockSize>::transaction_manager(typename block_manager<BlockSize>::ptr bm,
space_map::ptr sm)
: bm_(bm),
sm_(sm)
{
}
template <uint32_t BlockSize>
transaction_manager<BlockSize>::~transaction_manager()
{
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::reserve_block(block_address location)
{
sm_->inc_block(location);
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::begin()
{
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::pre_commit()
{
sm_->commit();
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::commit(write_ref superblock)
{
bm_->flush(superblock);
wipe_shadow_table();
}
template <uint32_t BlockSize>
block_address
transaction_manager<BlockSize>::alloc_block()
{
return sm_->new_block();
}
template <uint32_t BlockSize>
typename transaction_manager<BlockSize>::write_ref
transaction_manager<BlockSize>::new_block()
{
block_address b = sm_->new_block();
add_shadow(b);
return bm_->write_lock_zero(b);
}
template <uint32_t BlockSize>
typename transaction_manager<BlockSize>::write_ref
transaction_manager<BlockSize>::new_block(block_validator const &v)
{
block_address b = sm_->new_block();
add_shadow(b);
return bm_->write_lock_zero(b, v);
}
template <uint32_t BlockSize>
typename transaction_manager<BlockSize>::write_ref
transaction_manager<BlockSize>::shadow(block_address orig, bool &inc_children)
{
if (is_shadow(orig) &&
sm_->count_possibly_greater_than_one(orig)) {
inc_children = false;
return bm_->write_lock(orig);
}
auto src = bm_->read_lock(orig);
auto dest = bm_->write_lock_zero(sm_->new_block());
::memcpy(dest->data_, src->data_, BlockSize);
ref_t count = sm_->get_count(orig);
sm_->dec_block(orig);
inc_children = count > 1;
add_shadow(dest->location_);
return dest;
}
template <uint32_t BlockSize>
typename transaction_manager<BlockSize>::write_ref
transaction_manager<BlockSize>::shadow(block_address orig, block_validator const &v, bool &inc_children)
{
if (is_shadow(orig) &&
sm_->count_possibly_greater_than_one(orig)) {
inc_children = false;
return bm_->write_lock(orig);
}
auto src = bm_->read_lock(orig, v);
auto dest = bm_->write_lock_zero(sm_->new_block(), v);
::memcpy(dest->data_, src->data_, BlockSize);
ref_t count = sm_->get_count(orig);
sm_->dec_block(orig);
inc_children = count > 1;
add_shadow(dest->location_);
return dest;
}
template <uint32_t BlockSize>
typename transaction_manager<BlockSize>::read_ref
transaction_manager<BlockSize>::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, block_validator const &v)
{
return bm_->read_lock(b, v);
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::inc(block_address b)
{
sm_->inc_block(b);
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::dec(block_address b)
{
sm_->dec_block(b);
}
template <uint32_t BlockSize>
uint32_t
transaction_manager<BlockSize>::ref_count(block_address b) const
{
return sm_->get_count(b);
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::add_shadow(block_address b)
{
shadows_.insert(b);
}
template <uint32_t BlockSize>
bool
transaction_manager<BlockSize>::is_shadow(block_address b)
{
return shadows_.count(b) > 0;
}
template <uint32_t BlockSize>
void
transaction_manager<BlockSize>::wipe_shadow_table()
{
shadows_.clear();
}
//----------------------------------------------------------------