write some code
This commit is contained in:
parent
2e39670ff9
commit
c090bb88b5
15
Makefile
15
Makefile
@ -1,16 +1,18 @@
|
|||||||
SOURCE=\
|
SOURCE=\
|
||||||
block.cc \
|
|
||||||
main.cc \
|
main.cc \
|
||||||
metadata.cc \
|
metadata.cc
|
||||||
transaction_manager.cc
|
|
||||||
|
|
||||||
OBJECTS=$(subst .cc,.o,$(SOURCE))
|
OBJECTS=$(subst .cc,.o,$(SOURCE))
|
||||||
CPPFLAGS=-Wall -std=c++0x
|
CPPFLAGS=-Wall -std=c++0x
|
||||||
INCLUDES=
|
INCLUDES=
|
||||||
LIBS=-lstdc++
|
LIBS=-lstdc++
|
||||||
|
|
||||||
|
.SUFFIXES: .cc .o .d
|
||||||
|
|
||||||
.SUFFIXES: .cc .o
|
%.d: %.cc
|
||||||
|
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
|
||||||
|
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||||
|
rm -f $@.$$$$
|
||||||
|
|
||||||
.cc.o:
|
.cc.o:
|
||||||
g++ -c $(CPPFLAGS) $(INCLUDES) -o $@ $<
|
g++ -c $(CPPFLAGS) $(INCLUDES) -o $@ $<
|
||||||
@ -18,7 +20,4 @@ LIBS=-lstdc++
|
|||||||
multisnap_display: $(OBJECTS)
|
multisnap_display: $(OBJECTS)
|
||||||
g++ -o $@ $+ $(LIBS)
|
g++ -o $@ $+ $(LIBS)
|
||||||
|
|
||||||
main.o: block.h
|
include $(subst .cc,.d,$(SOURCE))
|
||||||
block.o: block.h
|
|
||||||
transaction_manager.o: transaction_manager.h block.h
|
|
||||||
metadata.o: block.h transaction_manager.h btree.h metadata.h
|
|
22
block.h
22
block.h
@ -30,6 +30,8 @@ namespace persistent_data {
|
|||||||
|
|
||||||
class block_validator {
|
class block_validator {
|
||||||
public:
|
public:
|
||||||
|
typedef boost::shared_ptr<block_validator> ptr;
|
||||||
|
|
||||||
virtual ~block_validator() {}
|
virtual ~block_validator() {}
|
||||||
|
|
||||||
virtual void check(block const &b) const = 0;
|
virtual void check(block const &b) const = 0;
|
||||||
@ -37,7 +39,7 @@ namespace persistent_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct block {
|
struct block {
|
||||||
typedef boost::optional<block_validator> maybe_validator;
|
typedef boost::optional<typename block_validator::ptr> maybe_validator;
|
||||||
|
|
||||||
block(block_address location,
|
block(block_address location,
|
||||||
maybe_validator v = maybe_validator())
|
maybe_validator v = maybe_validator())
|
||||||
@ -47,7 +49,7 @@ namespace persistent_data {
|
|||||||
|
|
||||||
block_address location_;
|
block_address location_;
|
||||||
buffer data_;
|
buffer data_;
|
||||||
boost::optional<block_validator> validator_;
|
maybe_validator validator_;
|
||||||
};
|
};
|
||||||
typedef boost::shared_ptr<block> block_ptr;
|
typedef boost::shared_ptr<block> block_ptr;
|
||||||
|
|
||||||
@ -67,6 +69,8 @@ namespace persistent_data {
|
|||||||
// locked.
|
// locked.
|
||||||
class write_ref : public read_ref {
|
class write_ref : public read_ref {
|
||||||
public:
|
public:
|
||||||
|
write_ref(block_ptr b);
|
||||||
|
|
||||||
using read_ref::data;
|
using read_ref::data;
|
||||||
buffer &data();
|
buffer &data();
|
||||||
};
|
};
|
||||||
@ -86,16 +90,20 @@ namespace persistent_data {
|
|||||||
|
|
||||||
// Validator variants
|
// Validator variants
|
||||||
read_ref
|
read_ref
|
||||||
read_lock(block_address location, block_validator const &v);
|
read_lock(block_address location,
|
||||||
|
typename block_validator::ptr const &v);
|
||||||
|
|
||||||
boost::optional<read_ref>
|
boost::optional<read_ref>
|
||||||
read_try_lock(block_address location, block_validator const &v);
|
read_try_lock(block_address location,
|
||||||
|
typename block_validator::ptr const &v);
|
||||||
|
|
||||||
write_ref
|
write_ref
|
||||||
write_lock(block_address location, block_validator const &v);
|
write_lock(block_address location,
|
||||||
|
typename block_validator::ptr const &v);
|
||||||
|
|
||||||
write_ref
|
write_ref
|
||||||
write_lock_zero(block_address location, block_validator const &v);
|
write_lock_zero(block_address location,
|
||||||
|
typename block_validator::ptr const &v);
|
||||||
|
|
||||||
// Use this to commit changes
|
// Use this to commit changes
|
||||||
void flush(write_ref super_block);
|
void flush(write_ref super_block);
|
||||||
@ -111,6 +119,8 @@ namespace persistent_data {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "block.tcc"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
50
block.tcc
50
block.tcc
@ -5,11 +5,13 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
using namespace persistent_data;
|
using namespace persistent_data;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
@ -33,6 +35,12 @@ block_manager<BlockSize>::read_ref::data() const
|
|||||||
return block_->data_;
|
return block_->data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <uint32_t BlockSize>
|
||||||
|
block_manager<BlockSize>::write_ref::write_ref(block_manager::block_ptr b)
|
||||||
|
: read_ref(b)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
typename block_manager<BlockSize>::buffer &
|
typename block_manager<BlockSize>::buffer &
|
||||||
block_manager<BlockSize>::write_ref::data()
|
block_manager<BlockSize>::write_ref::data()
|
||||||
@ -61,7 +69,7 @@ typename block_manager<BlockSize>::read_ref
|
|||||||
block_manager<BlockSize>::read_lock(block_address location)
|
block_manager<BlockSize>::read_lock(block_address location)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location));
|
block_ptr b(new block(location));
|
||||||
read_block(b);
|
read_block(*b);
|
||||||
return read_ref(b);
|
return read_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +84,8 @@ template <uint32_t BlockSize>
|
|||||||
typename block_manager<BlockSize>::write_ref
|
typename block_manager<BlockSize>::write_ref
|
||||||
block_manager<BlockSize>::write_lock(block_address location)
|
block_manager<BlockSize>::write_lock(block_address location)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location), write_and_release);
|
block_ptr b(new block(location), bind(&block_manager::write_and_release, this, _1));
|
||||||
read_block(b);
|
read_block(*b);
|
||||||
return write_ref(b);
|
return write_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,25 +93,25 @@ template <uint32_t BlockSize>
|
|||||||
typename block_manager<BlockSize>::write_ref
|
typename block_manager<BlockSize>::write_ref
|
||||||
block_manager<BlockSize>::write_lock_zero(block_address location)
|
block_manager<BlockSize>::write_lock_zero(block_address location)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location), write_and_release);
|
block_ptr b(new block(location), bind(&block_manager<BlockSize>::write_and_release, this, _1));
|
||||||
zero_block(b);
|
zero_block(*b);
|
||||||
return write_ref(b);
|
return write_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
typename block_manager<BlockSize>::read_ref
|
typename block_manager<BlockSize>::read_ref
|
||||||
block_manager<BlockSize>::read_lock(block_address location,
|
block_manager<BlockSize>::read_lock(block_address location,
|
||||||
block_manager<BlockSize>::block_validator const &v)
|
typename block_manager<BlockSize>::block_validator::ptr const &v)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location, v));
|
block_ptr b(new block(location, v));
|
||||||
read_block(b);
|
read_block(*b);
|
||||||
return read_ref(b);
|
return read_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
optional<typename block_manager<BlockSize>::read_ref>
|
optional<typename block_manager<BlockSize>::read_ref>
|
||||||
block_manager<BlockSize>::read_try_lock(block_address location,
|
block_manager<BlockSize>::read_try_lock(block_address location,
|
||||||
block_manager<BlockSize>::block_validator const &v)
|
typename block_manager<BlockSize>::block_validator::ptr const &v)
|
||||||
{
|
{
|
||||||
return read_lock(location, v);
|
return read_lock(location, v);
|
||||||
}
|
}
|
||||||
@ -111,20 +119,20 @@ block_manager<BlockSize>::read_try_lock(block_address location,
|
|||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
typename block_manager<BlockSize>::write_ref
|
typename block_manager<BlockSize>::write_ref
|
||||||
block_manager<BlockSize>::write_lock(block_address location,
|
block_manager<BlockSize>::write_lock(block_address location,
|
||||||
block_manager<BlockSize>::block_validator const &v)
|
typename block_manager<BlockSize>::block_validator::ptr const &v)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location, v), write_and_release);
|
block_ptr b(new block(location, v), write_and_release);
|
||||||
read_block(b);
|
read_block(*b);
|
||||||
return write_ref(b);
|
return write_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
typename block_manager<BlockSize>::write_ref
|
typename block_manager<BlockSize>::write_ref
|
||||||
block_manager<BlockSize>::write_lock_zero(block_address location,
|
block_manager<BlockSize>::write_lock_zero(block_address location,
|
||||||
block_manager<BlockSize>::block_validator const &v)
|
typename block_manager<BlockSize>::block_validator::ptr const &v)
|
||||||
{
|
{
|
||||||
block_ptr b(new block(location, v), write_and_release);
|
block_ptr b(new block(location, v), write_and_release);
|
||||||
zero_block(b);
|
zero_block(*b);
|
||||||
return write_ref(b);
|
return write_ref(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,16 +148,16 @@ template <uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
block_manager<BlockSize>::read_block(block &b)
|
block_manager<BlockSize>::read_block(block &b)
|
||||||
{
|
{
|
||||||
std::cerr << "reading block: " << b->location << std::endl;
|
std::cerr << "reading block: " << b.location_ << std::endl;
|
||||||
|
|
||||||
off_t r;
|
off_t r;
|
||||||
r = ::lseek(fd_, BlockSize * b->location_, SEEK_SET);
|
r = ::lseek(fd_, BlockSize * b.location_, SEEK_SET);
|
||||||
if (r == (off_t) -1)
|
if (r == (off_t) -1)
|
||||||
throw std::runtime_error("lseek failed");
|
throw std::runtime_error("lseek failed");
|
||||||
|
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
size_t remaining = BlockSize;
|
size_t remaining = BlockSize;
|
||||||
unsigned char *buf = b->data_;
|
unsigned char *buf = b.data_;
|
||||||
do {
|
do {
|
||||||
n = ::read(fd_, buf, remaining);
|
n = ::read(fd_, buf, remaining);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
@ -167,18 +175,18 @@ void
|
|||||||
block_manager<BlockSize>::write_block(block const &b)
|
block_manager<BlockSize>::write_block(block const &b)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::cerr << "writing block: " << b->location << std::endl;
|
std::cerr << "writing block: " << b.location_ << std::endl;
|
||||||
|
|
||||||
off_t r;
|
off_t r;
|
||||||
r = ::lseek(fd_, BlockSize * b->location_, SEEK_SET);
|
r = ::lseek(fd_, BlockSize * b.location_, SEEK_SET);
|
||||||
if (r == (off_t) -1)
|
if (r == (off_t) -1)
|
||||||
throw std::runtime_error("lseek failed");
|
throw std::runtime_error("lseek failed");
|
||||||
|
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
size_t remaining = BlockSize;
|
size_t remaining = BlockSize;
|
||||||
unsigned char *buf = b->data_;
|
unsigned char const *buf = b.data_;
|
||||||
do {
|
do {
|
||||||
n = ::read(fd_, buf, remaining);
|
n = ::write(fd_, buf, remaining);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
remaining -= n;
|
remaining -= n;
|
||||||
buf += n;
|
buf += n;
|
||||||
@ -193,14 +201,14 @@ template <uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
block_manager<BlockSize>::zero_block(block &b)
|
block_manager<BlockSize>::zero_block(block &b)
|
||||||
{
|
{
|
||||||
memset(b->data_, 0, BlockSize);
|
memset(b.data_, 0, BlockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
void
|
void
|
||||||
block_manager<BlockSize>::write_and_release(block *b)
|
block_manager<BlockSize>::write_and_release(block *b)
|
||||||
{
|
{
|
||||||
write_block(b);
|
write_block(*b);
|
||||||
delete b;
|
delete b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
btree.h
20
btree.h
@ -1,6 +1,7 @@
|
|||||||
#ifndef BTREE_H
|
#ifndef BTREE_H
|
||||||
#define BTREE_H
|
#define BTREE_H
|
||||||
|
|
||||||
|
#include "endian.h"
|
||||||
#include "transaction_manager.h"
|
#include "transaction_manager.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@ -17,8 +18,8 @@ namespace persistent_data {
|
|||||||
typedef typename block_manager<BlockSize>::read_ref read_ref;
|
typedef typename block_manager<BlockSize>::read_ref read_ref;
|
||||||
typedef typename block_manager<BlockSize>::write_ref write_ref;
|
typedef typename block_manager<BlockSize>::write_ref write_ref;
|
||||||
|
|
||||||
btree(boost::shared_ptr<transaction_manager<BlockSize> > tm);
|
btree(typename persistent_data::transaction_manager<BlockSize>::ptr tm);
|
||||||
btree(boost::shared_ptr<transaction_manager<BlockSize> > tm,
|
btree(typename transaction_manager<BlockSize>::ptr tm,
|
||||||
block_address root);
|
block_address root);
|
||||||
~btree();
|
~btree();
|
||||||
|
|
||||||
@ -42,8 +43,23 @@ namespace persistent_data {
|
|||||||
bool destroy_;
|
bool destroy_;
|
||||||
block_address root_;
|
block_address root_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct uint64_traits {
|
||||||
|
typedef base::__le64 disk_type;
|
||||||
|
typedef uint64_t value_type;
|
||||||
|
|
||||||
|
static value_type construct(void *data) {
|
||||||
|
// extra memcpy because I'm paranoid about alignment issues
|
||||||
|
base::__le64 disk;
|
||||||
|
|
||||||
|
::memcpy(&disk, data, sizeof(disk));
|
||||||
|
return base::to_cpu<uint64_t>(disk);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "btree.tcc"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
192
btree.tcc
192
btree.tcc
@ -1,14 +1,20 @@
|
|||||||
#include "btree.h"
|
#include "btree.h"
|
||||||
|
|
||||||
|
#include "endian.h"
|
||||||
|
#include "transaction_manager.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
// FIXME: can't have using clauses in a header
|
||||||
|
using namespace base;
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
using namespace persistent_data;
|
using namespace persistent_data;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
namespace {
|
namespace btree_detail {
|
||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
// On disk data layout for btree nodes
|
// On disk data layout for btree nodes
|
||||||
enum node_flags {
|
enum node_flags {
|
||||||
@ -25,7 +31,7 @@ namespace {
|
|||||||
__le32 max_entries;
|
__le32 max_entries;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct node {
|
struct disk_node {
|
||||||
struct node_header header;
|
struct node_header header;
|
||||||
__le64 keys[0];
|
__le64 keys[0];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
@ -34,34 +40,76 @@ namespace {
|
|||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
// Class that acts as an interface over the raw little endian btree
|
// Class that acts as an interface over the raw little endian btree
|
||||||
// node data.
|
// node data.
|
||||||
class node {
|
class node_ref {
|
||||||
public:
|
public:
|
||||||
enum type {
|
enum type {
|
||||||
INTERNAL,
|
INTERNAL,
|
||||||
LEAF
|
LEAF
|
||||||
};
|
};
|
||||||
|
|
||||||
type get_type() const;
|
node_ref(disk_node *raw)
|
||||||
void set_type(type t);
|
: raw_(raw) {
|
||||||
|
}
|
||||||
|
|
||||||
unsigned get_nr_entries() const;
|
type get_type() const {
|
||||||
void set_nr_entries(unsigned n);
|
uint32_t flags = to_cpu<uint32_t>(raw_->header.flags);
|
||||||
|
if (flags & INTERNAL_NODE)
|
||||||
|
return INTERNAL;
|
||||||
|
else if (flags & LEAF_NODE)
|
||||||
|
return LEAF;
|
||||||
|
else
|
||||||
|
throw runtime_error("unknow node type");
|
||||||
|
}
|
||||||
|
|
||||||
unsigned get_max_entries() const;
|
void set_type(type t){
|
||||||
void set_max_entries(unsigned n);
|
uint32_t flags = to_cpu<uint32_t>(raw_->header.flags);
|
||||||
|
switch (t) {
|
||||||
|
case INTERNAL:
|
||||||
|
flags |= INTERNAL_NODE;
|
||||||
|
break;
|
||||||
|
|
||||||
uint64_t key_at(unsigned i) const;
|
case LEAF:
|
||||||
|
flags |= LEAF_NODE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
raw_->header.flags = to_disk<__le32>(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned get_nr_entries() const {
|
||||||
|
return to_cpu<uint32_t>(raw_->header.nr_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nr_entries(unsigned n) {
|
||||||
|
raw_->header.nr_entries = to_disk<__le32>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned get_max_entries() const {
|
||||||
|
return to_cpu<uint32_t>(raw_->header.max_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_max_entries(unsigned n) {
|
||||||
|
raw_->header.max_entries = to_disk<__le32>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t key_at(unsigned i) const {
|
||||||
|
return to_cpu<uint64_t>(raw_->keys[i]);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ValueTraits>
|
template <typename ValueTraits>
|
||||||
typename ValueTraits::value_type value_at(unsigned i) const;
|
typename ValueTraits::value_type value_at(unsigned i) const {
|
||||||
|
void *value_base = &raw_->keys[to_cpu<uint32_t>(raw_->header.max_entries)];
|
||||||
|
void *value_ptr = static_cast<unsigned char *>(value_base) +
|
||||||
|
sizeof(typename ValueTraits::disk_type) * i;
|
||||||
|
return ValueTraits::construct(value_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct node *raw_;
|
disk_node *raw_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
// Various searches
|
// Various searches
|
||||||
int bsearch(node const &n, uint64_t key, int want_hi)
|
int bsearch(node_ref const &n, uint64_t key, int want_hi)
|
||||||
{
|
{
|
||||||
int lo = -1, hi = n.get_nr_entries();
|
int lo = -1, hi = n.get_nr_entries();
|
||||||
|
|
||||||
@ -81,7 +129,7 @@ namespace {
|
|||||||
return want_hi ? hi : lo;
|
return want_hi ? hi : lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<unsigned> exact_search(node const &n, uint64_t key) {
|
optional<unsigned> exact_search(node_ref const &n, uint64_t key) {
|
||||||
int i = bsearch(n, key, 0);
|
int i = bsearch(n, key, 0);
|
||||||
if (i < 0 || static_cast<unsigned>(i) >= n.get_nr_entries())
|
if (i < 0 || static_cast<unsigned>(i) >= n.get_nr_entries())
|
||||||
return optional<unsigned>();
|
return optional<unsigned>();
|
||||||
@ -92,7 +140,19 @@ namespace {
|
|||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
//
|
//
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
node &to_node(typename block_manager<BlockSize>::write_ref b);
|
node_ref to_node(typename block_manager<BlockSize>::read_ref &b)
|
||||||
|
{
|
||||||
|
// FIXME: this should return a const read_ref somehow.
|
||||||
|
return node_ref(
|
||||||
|
reinterpret_cast<disk_node *>(const_cast<unsigned char *>(b.data())));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint32_t BlockSize>
|
||||||
|
node_ref to_node(typename block_manager<BlockSize>::write_ref &b)
|
||||||
|
{
|
||||||
|
return node_ref(
|
||||||
|
reinterpret_cast<disk_node *>(const_cast<unsigned char *>(b.data())));
|
||||||
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
calc_max_entries(uint32_t bs);
|
calc_max_entries(uint32_t bs);
|
||||||
@ -101,62 +161,103 @@ namespace {
|
|||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
class ro_spine : private noncopyable {
|
class ro_spine : private noncopyable {
|
||||||
public:
|
public:
|
||||||
void step(block_address b);
|
ro_spine(typename transaction_manager<BlockSize>::ptr tm)
|
||||||
node get_node() const;
|
: tm_(tm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void step(block_address b) {
|
||||||
|
spine_.push_back(tm_->read_lock(b));
|
||||||
|
if (spine_.size() > 2)
|
||||||
|
spine_.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref get_node() {
|
||||||
|
return to_node<BlockSize>(spine_.back());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typename transaction_manager<BlockSize>::ptr tm_;
|
||||||
|
std::list<typename block_manager<BlockSize>::read_ref> spine_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class internal_traits {
|
template <uint32_t BlockSize>
|
||||||
|
class shadow_spine : private noncopyable {
|
||||||
public:
|
public:
|
||||||
typedef uint64_t value_type;
|
shadow_spine(typename transaction_manager<BlockSize>::ptr tm)
|
||||||
|
: tm_(tm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void step(block_address b) {
|
||||||
|
spine_.push_back(tm_->shadow(b));
|
||||||
|
if (spine_.size() == 1)
|
||||||
|
root_ = spine_.front().get_location();
|
||||||
|
else if (spine_.size() > 2)
|
||||||
|
spine_.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref get_node() {
|
||||||
|
return to_node<BlockSize>(spine_.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref get_parent() {
|
||||||
|
if (spine_.size() < 2)
|
||||||
|
throw std::runtime_error("no parent");
|
||||||
|
|
||||||
|
return to_node<BlockSize>(spine_.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ref get_root() {
|
||||||
|
return root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename transaction_manager<BlockSize>::ptr tm_;
|
||||||
|
std::list<typename block_manager<BlockSize>::write_ref> spine_;
|
||||||
|
block_address root_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ValueTraits, uint32_t BlockSize, typename Search>
|
template <typename ValueTraits, uint32_t BlockSize> //, typename Search>
|
||||||
optional<typename ValueTraits::value_type>
|
optional<typename ValueTraits::value_type>
|
||||||
lookup_raw(ro_spine<BlockSize> &spine, block_address block, uint64_t key) {
|
lookup_raw(ro_spine<BlockSize> &spine, block_address block, uint64_t key) {
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
typedef typename ValueTraits::value_type leaf_type;
|
typedef typename ValueTraits::value_type leaf_type;
|
||||||
typedef typename internal_traits::value_type internal_type;
|
|
||||||
|
|
||||||
Search find;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
spine.step(block);
|
spine.step(block);
|
||||||
node &n = spine.node();
|
node_ref const &n = spine.get_node();
|
||||||
|
|
||||||
auto mi = find(n, key);
|
auto mi = exact_search(n, key);
|
||||||
if (!mi)
|
if (!mi)
|
||||||
return optional<leaf_type>();
|
return optional<leaf_type>();
|
||||||
|
|
||||||
if (n.get_type() == node::LEAF)
|
if (n.get_type() == node_ref::LEAF)
|
||||||
return optional<leaf_type>(n.value_at(*mi));
|
return optional<leaf_type>(n.value_at<ValueTraits>(*mi));
|
||||||
|
|
||||||
block = n.value_at<internal_type>(*mi);
|
block = n.value_at<uint64_traits>(*mi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
||||||
btree<Levels, ValueTraits, BlockSize>::btree(shared_ptr<transaction_manager<BlockSize> > tm)
|
btree<Levels, ValueTraits, BlockSize>::btree(typename transaction_manager<BlockSize>::ptr tm)
|
||||||
: tm_(tm),
|
: tm_(tm),
|
||||||
destroy_(false)
|
destroy_(false)
|
||||||
{
|
{
|
||||||
write_ref root = tm_.new_block();
|
using namespace btree_detail;
|
||||||
|
|
||||||
node &n = to_node(root);
|
write_ref root = tm_->new_block();
|
||||||
n.set_type(node::LEAF);
|
|
||||||
|
node_ref n = to_node<BlockSize>(root);
|
||||||
|
n.set_type(node_ref::LEAF);
|
||||||
n.set_nr_entries(0);
|
n.set_nr_entries(0);
|
||||||
n.set_max_entries(calc_max_entries(BlockSize));
|
n.set_max_entries(calc_max_entries(BlockSize));
|
||||||
|
|
||||||
root_ = root.location();
|
root_ = root.get_location();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
||||||
btree<Levels, ValueTraits, BlockSize>::btree(shared_ptr<transaction_manager<BlockSize> > tm,
|
btree<Levels, ValueTraits, BlockSize>::btree(typename transaction_manager<BlockSize>::ptr tm,
|
||||||
block_address root)
|
block_address root)
|
||||||
: tm_(tm),
|
: tm_(tm),
|
||||||
destroy_(false),
|
destroy_(false),
|
||||||
@ -174,24 +275,29 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
typename btree<Levels, ValueTraits, BlockSize>::maybe_value
|
typename btree<Levels, ValueTraits, BlockSize>::maybe_value
|
||||||
btree<Levels, ValueTraits, BlockSize>::lookup(key const &key) const
|
btree<Levels, ValueTraits, BlockSize>::lookup(key const &key) const
|
||||||
{
|
{
|
||||||
ro_spine<BlockSize> spine;
|
using namespace btree_detail;
|
||||||
|
|
||||||
|
ro_spine<BlockSize> spine(tm_);
|
||||||
block_address root = root_;
|
block_address root = root_;
|
||||||
|
|
||||||
for (unsigned level = 0; level < Levels - 1; ++level) {
|
for (unsigned level = 0; level < Levels - 1; ++level) {
|
||||||
auto mroot = lookup_raw<internal_traits, BlockSize, exact_search>(spine, root, key[level]);
|
optional<block_address> mroot =
|
||||||
|
lookup_raw<uint64_traits, BlockSize>(spine, root, key[level]);
|
||||||
if (!mroot)
|
if (!mroot)
|
||||||
return maybe_value();
|
return maybe_value();
|
||||||
|
|
||||||
root = *mroot;
|
root = *mroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
return lookup_raw<ValueTraits, BlockSize, exact_search>(spine, root, key[Levels - 1]);
|
return lookup_raw<ValueTraits, BlockSize>(spine, root, key[Levels - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
||||||
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair
|
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair
|
||||||
btree<Levels, ValueTraits, BlockSize>::lookup_le(key const &key) const
|
btree<Levels, ValueTraits, BlockSize>::lookup_le(key const &key) const
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
return maybe_pair();
|
return maybe_pair();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +305,8 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair
|
typename btree<Levels, ValueTraits, BlockSize>::maybe_pair
|
||||||
btree<Levels, ValueTraits, BlockSize>::lookup_ge(key const &key) const
|
btree<Levels, ValueTraits, BlockSize>::lookup_ge(key const &key) const
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
return maybe_pair();
|
return maybe_pair();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,6 +315,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
btree<Levels, ValueTraits, BlockSize>::insert(key const &key, typename ValueTraits::value_type const &value)
|
btree<Levels, ValueTraits, BlockSize>::insert(key const &key, typename ValueTraits::value_type const &value)
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +323,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
btree<Levels, ValueTraits, BlockSize>::remove(key const &key)
|
btree<Levels, ValueTraits, BlockSize>::remove(key const &key)
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +338,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
btree<Levels, ValueTraits, BlockSize>::set_root(block_address root)
|
btree<Levels, ValueTraits, BlockSize>::set_root(block_address root)
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +346,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
block_address
|
block_address
|
||||||
btree<Levels, ValueTraits, BlockSize>::get_root() const
|
btree<Levels, ValueTraits, BlockSize>::get_root() const
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +354,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
ptr
|
ptr
|
||||||
btree<Levels, ValueTraits, BlockSize>::clone() const
|
btree<Levels, ValueTraits, BlockSize>::clone() const
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +362,7 @@ template <unsigned Levels, typename ValueTraits, uint32_t BlockSize>
|
|||||||
void
|
void
|
||||||
btree<Levels, ValueTraits, BlockSize>::destroy()
|
btree<Levels, ValueTraits, BlockSize>::destroy()
|
||||||
{
|
{
|
||||||
|
using namespace btree_detail;
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
83
endian.h
Normal file
83
endian.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#ifndef ENDIAN_H
|
||||||
|
#define ENDIAN_H
|
||||||
|
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
// These are just little wrapper types to make the compiler
|
||||||
|
// understand that the le types are not assignable to the
|
||||||
|
// corresponding cpu type.
|
||||||
|
|
||||||
|
struct __le16 {
|
||||||
|
explicit __le16(uint16_t v = 0.0)
|
||||||
|
: v_(v) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t v_;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct __le32 {
|
||||||
|
explicit __le32(uint32_t v = 0.0)
|
||||||
|
: v_(v) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t v_;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct __le64 {
|
||||||
|
explicit __le64(uint64_t v = 0.0)
|
||||||
|
: v_(v) {
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t v_;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
template <typename CPUType, typename DiskType>
|
||||||
|
CPUType to_cpu(DiskType const &d) {
|
||||||
|
BOOST_STATIC_ASSERT(sizeof(d) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DiskType, typename CPUType>
|
||||||
|
DiskType to_disk(CPUType const &v) {
|
||||||
|
BOOST_STATIC_ASSERT(sizeof(v) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
uint16_t to_cpu<uint16_t, __le16>(__le16 const &d) {
|
||||||
|
return d.v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
__le16 to_disk<__le16, uint16_t>(uint16_t const &v) {
|
||||||
|
return __le16(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
uint32_t to_cpu<uint32_t, __le32>(__le32 const &d) {
|
||||||
|
return d.v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
__le32 to_disk<__le32, uint32_t>(uint32_t const &v) {
|
||||||
|
return __le32(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
uint64_t to_cpu<uint64_t, __le64>(__le64 const &d) {
|
||||||
|
return d.v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
__le64 to_disk<__le64, uint64_t>(uint64_t const &v) {
|
||||||
|
return __le64(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
12
metadata.cc
12
metadata.cc
@ -115,7 +115,7 @@ metadata::create_thin(dev_t dev)
|
|||||||
throw std::runtime_error("Device already exists");
|
throw std::runtime_error("Device already exists");
|
||||||
|
|
||||||
single_mapping_tree::ptr new_tree(new single_mapping_tree(tm_));
|
single_mapping_tree::ptr new_tree(new single_mapping_tree(tm_));
|
||||||
mappings_top_level_.insert(key, *new_tree);
|
mappings_top_level_.insert(key, new_tree->get_root());
|
||||||
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
|
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,12 +125,14 @@ metadata::create_snap(dev_t dev, dev_t origin)
|
|||||||
uint64_t snap_key[1] = {dev};
|
uint64_t snap_key[1] = {dev};
|
||||||
uint64_t origin_key[1] = {origin};
|
uint64_t origin_key[1] = {origin};
|
||||||
|
|
||||||
auto mtree = mappings_top_level_.lookup(origin_key);
|
auto mtree_root = mappings_top_level_.lookup(origin_key);
|
||||||
if (!mtree)
|
if (!mtree_root)
|
||||||
throw std::runtime_error("unknown origin");
|
throw std::runtime_error("unknown origin");
|
||||||
|
|
||||||
single_mapping_tree::ptr clone(mtree->clone());
|
single_mapping_tree otree(tm_, *mtree_root);
|
||||||
mappings_top_level_.insert(snap_key, *clone);
|
|
||||||
|
single_mapping_tree::ptr clone(otree.clone());
|
||||||
|
mappings_top_level_.insert(snap_key, clone->get_root());
|
||||||
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
|
mappings_.set_root(mappings_top_level_.get_root()); // FIXME: ugly
|
||||||
|
|
||||||
time_++;
|
time_++;
|
||||||
|
69
metadata.h
69
metadata.h
@ -17,6 +17,54 @@
|
|||||||
namespace multisnap {
|
namespace multisnap {
|
||||||
typedef uint64_t sector_t;
|
typedef uint64_t sector_t;
|
||||||
|
|
||||||
|
struct device_details_disk {
|
||||||
|
__le64 dev_size;
|
||||||
|
__le64 mapped_blocks;
|
||||||
|
__le64 transaction_id; /* when created */
|
||||||
|
__le32 creation_time;
|
||||||
|
__le32 snapshotted_time;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct device_details {
|
||||||
|
uint64_t dev_size;
|
||||||
|
uint64_t mapped_blocks;
|
||||||
|
uint64_t transaction_id; /* when created */
|
||||||
|
uint32_t creation_time;
|
||||||
|
uint32_t snapshotted_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct detail_traits {
|
||||||
|
typedef device_details_disk disk_type;
|
||||||
|
typedef device_details value_type;
|
||||||
|
|
||||||
|
static value_type construct(void *data) {
|
||||||
|
struct device_details_disk disk;
|
||||||
|
struct device_details cpu;
|
||||||
|
|
||||||
|
::memcpy(&disk, data, sizeof(disk));
|
||||||
|
cpu.dev_size = to_cpu<uint64_t>(disk.dev_size);
|
||||||
|
cpu.mapped_blocks = to_cpu<uint64_t>(disk.mapped_blocks);
|
||||||
|
cpu.transaction_id = to_cpu<uint64_t>(disk.transaction_id);
|
||||||
|
cpu.creation_time = to_cpu<uint32_t>(disk.creation_time);
|
||||||
|
cpu.snapshotted_time = to_cpu<uint32_t>(disk.snapshotted_time);
|
||||||
|
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#if 0
|
||||||
|
class dev_traits {
|
||||||
|
public:
|
||||||
|
typedef base::__le64 disk_type;
|
||||||
|
typedef persistent_data::btree<1, uint64_traits, BLOCK_SIZE> value_type;
|
||||||
|
|
||||||
|
static value_type construct(void *data) {
|
||||||
|
uint64_t root = uint64_traits::construct(data);
|
||||||
|
|
||||||
|
return value_type
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
class metadata {
|
class metadata {
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<metadata> ptr;
|
typedef boost::shared_ptr<metadata> ptr;
|
||||||
@ -75,29 +123,14 @@ namespace multisnap {
|
|||||||
|
|
||||||
bool device_exists(dev_t dev) const;
|
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_;
|
uint32_t time_;
|
||||||
|
|
||||||
persistent_data::transaction_manager<BLOCK_SIZE>::ptr tm_;
|
persistent_data::transaction_manager<BLOCK_SIZE>::ptr tm_;
|
||||||
|
|
||||||
typedef persistent_data::btree<1, detail_traits, BLOCK_SIZE> detail_tree;
|
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<1, uint64_traits, BLOCK_SIZE> dev_tree;
|
||||||
typedef persistent_data::btree<2, map_traits, BLOCK_SIZE> mapping_tree;
|
typedef persistent_data::btree<2, uint64_traits, BLOCK_SIZE> mapping_tree;
|
||||||
typedef persistent_data::btree<1, map_traits, BLOCK_SIZE> single_mapping_tree;
|
typedef persistent_data::btree<1, uint64_traits, BLOCK_SIZE> single_mapping_tree;
|
||||||
|
|
||||||
detail_tree details_;
|
detail_tree details_;
|
||||||
dev_tree mappings_top_level_;
|
dev_tree mappings_top_level_;
|
||||||
|
@ -54,6 +54,8 @@ namespace persistent_data {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "transaction_manager.tcc"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user