write a lot of the persistent data classes
This commit is contained in:
parent
6b8b16c70a
commit
2e39670ff9
14
Makefile
14
Makefile
@ -1,8 +1,11 @@
|
|||||||
SOURCE=\
|
SOURCE=\
|
||||||
main.cc
|
block.cc \
|
||||||
|
main.cc \
|
||||||
|
metadata.cc \
|
||||||
|
transaction_manager.cc
|
||||||
|
|
||||||
OBJECTS=$(subst .cc,.o,$(SOURCE))
|
OBJECTS=$(subst .cc,.o,$(SOURCE))
|
||||||
CPPFLAGS=-Wall -Weffc++ -std=c++0x
|
CPPFLAGS=-Wall -std=c++0x
|
||||||
INCLUDES=
|
INCLUDES=
|
||||||
LIBS=-lstdc++
|
LIBS=-lstdc++
|
||||||
|
|
||||||
@ -13,4 +16,9 @@ LIBS=-lstdc++
|
|||||||
g++ -c $(CPPFLAGS) $(INCLUDES) -o $@ $<
|
g++ -c $(CPPFLAGS) $(INCLUDES) -o $@ $<
|
||||||
|
|
||||||
multisnap_display: $(OBJECTS)
|
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
116
block.h
Normal 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
207
block.tcc
Normal 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
49
btree.h
Normal 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
255
btree.tcc
Normal 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
61
core-map.h
Normal 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
|
2
main.cc
2
main.cc
@ -1,3 +1,5 @@
|
|||||||
|
#include "block.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
215
metadata.cc
Normal file
215
metadata.cc
Normal 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
110
metadata.h
Normal 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
41
space_map.h
Normal 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
59
transaction_manager.h
Normal 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
174
transaction_manager.tcc
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
Loading…
Reference in New Issue
Block a user