Merge branch 'master' into space-map-checking
This commit is contained in:
@ -31,9 +31,9 @@ namespace persistent_data {
|
||||
namespace array_detail {
|
||||
uint32_t const ARRAY_CSUM_XOR = 595846735;
|
||||
|
||||
struct array_block_validator : public block_manager<>::validator {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
array_block_disk const *data = reinterpret_cast<array_block_disk const *>(&b);
|
||||
struct array_block_validator : public bcache::validator {
|
||||
virtual void check(void const *raw, block_address location) const {
|
||||
array_block_disk const *data = reinterpret_cast<array_block_disk const *>(raw);
|
||||
crc32c sum(ARRAY_CSUM_XOR);
|
||||
sum.append(&data->max_entries, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
if (sum.get_sum() != to_cpu<uint32_t>(data->csum))
|
||||
@ -43,8 +43,8 @@ namespace persistent_data {
|
||||
throw checksum_error("bad block nr in array block");
|
||||
}
|
||||
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
array_block_disk *data = reinterpret_cast<array_block_disk *>(&b);
|
||||
virtual void prepare(void *raw, block_address location) const {
|
||||
array_block_disk *data = reinterpret_cast<array_block_disk *>(raw);
|
||||
data->blocknr = to_disk<base::le64, uint64_t>(location);
|
||||
|
||||
crc32c sum(ARRAY_CSUM_XOR);
|
||||
@ -172,7 +172,7 @@ namespace persistent_data {
|
||||
unsigned visit_array_block(ValueVisitor &vv,
|
||||
btree_path const &p,
|
||||
typename block_traits::value_type const &v) const {
|
||||
rblock rb(tm_->read_lock(v, validator_), rc_);
|
||||
rblock rb(tm_.read_lock(v, validator_), rc_);
|
||||
|
||||
for (uint32_t i = 0; i < rb.nr_entries(); i++)
|
||||
vv.visit(p[0] * rb.max_entries() + i, rb.get(i));
|
||||
@ -207,8 +207,6 @@ namespace persistent_data {
|
||||
unsigned entries_per_block_;
|
||||
};
|
||||
|
||||
typedef typename persistent_data::transaction_manager::ptr tm_ptr;
|
||||
|
||||
typedef block_manager<>::write_ref write_ref;
|
||||
typedef block_manager<>::read_ref read_ref;
|
||||
|
||||
@ -219,23 +217,23 @@ namespace persistent_data {
|
||||
typedef typename ValueTraits::value_type value_type;
|
||||
typedef typename ValueTraits::ref_counter ref_counter;
|
||||
|
||||
array(tm_ptr tm, ref_counter rc)
|
||||
array(transaction_manager &tm, ref_counter rc)
|
||||
: tm_(tm),
|
||||
entries_per_block_(rblock::calc_max_entries()),
|
||||
nr_entries_(0),
|
||||
block_rc_(tm->get_sm(), *this),
|
||||
block_rc_(tm.get_sm(), *this),
|
||||
block_tree_(tm, block_rc_),
|
||||
rc_(rc),
|
||||
validator_(new array_detail::array_block_validator) {
|
||||
}
|
||||
|
||||
array(tm_ptr tm, ref_counter rc,
|
||||
array(transaction_manager &tm, ref_counter rc,
|
||||
block_address root,
|
||||
unsigned nr_entries)
|
||||
: tm_(tm),
|
||||
entries_per_block_(rblock::calc_max_entries()),
|
||||
nr_entries_(nr_entries),
|
||||
block_rc_(tm->get_sm(), *this),
|
||||
block_rc_(tm.get_sm(), *this),
|
||||
block_tree_(tm, root, block_rc_),
|
||||
rc_(rc),
|
||||
validator_(new array_detail::array_block_validator) {
|
||||
@ -378,7 +376,7 @@ namespace persistent_data {
|
||||
|
||||
wblock new_ablock(unsigned ablock_index) {
|
||||
uint64_t key[1] = {ablock_index};
|
||||
write_ref b = tm_->new_block(validator_);
|
||||
write_ref b = tm_.new_block(validator_);
|
||||
block_address location = b.get_location();
|
||||
|
||||
wblock wb(b, rc_);
|
||||
@ -389,13 +387,13 @@ namespace persistent_data {
|
||||
|
||||
rblock get_ablock(unsigned ablock_index) const {
|
||||
block_address addr = lookup_block_address(ablock_index);
|
||||
return rblock(tm_->read_lock(addr, validator_), rc_);
|
||||
return rblock(tm_.read_lock(addr, validator_), rc_);
|
||||
}
|
||||
|
||||
wblock shadow_ablock(unsigned ablock_index) {
|
||||
uint64_t key[1] = {ablock_index};
|
||||
block_address addr = lookup_block_address(ablock_index);
|
||||
std::pair<write_ref, bool> p = tm_->shadow(addr, validator_);
|
||||
std::pair<write_ref, bool> p = tm_.shadow(addr, validator_);
|
||||
wblock wb = wblock(p.first, rc_);
|
||||
|
||||
if (p.second)
|
||||
@ -407,17 +405,17 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
void dec_ablock_entries(block_address addr) {
|
||||
rblock b(tm_->read_lock(addr, validator_), rc_);
|
||||
rblock b(tm_.read_lock(addr, validator_), rc_);
|
||||
b.dec_all_entries();
|
||||
}
|
||||
|
||||
tm_ptr tm_;
|
||||
transaction_manager &tm_;
|
||||
unsigned entries_per_block_;
|
||||
unsigned nr_entries_;
|
||||
block_ref_counter block_rc_;
|
||||
btree<1, block_traits> block_tree_;
|
||||
typename ValueTraits::ref_counter rc_;
|
||||
block_manager<>::validator::ptr validator_;
|
||||
bcache::validator::ptr validator_;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#ifndef ARRAY_BLOCK_H
|
||||
#define ARRAY_BLOCK_H
|
||||
|
||||
#include "persistent-data/endian_utils.h"
|
||||
#include "base/endian_utils.h"
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@ -163,11 +163,11 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
array_block_disk *get_header() {
|
||||
return reinterpret_cast<array_block_disk *>(ref_.data().raw());
|
||||
return reinterpret_cast<array_block_disk *>(ref_.data());
|
||||
}
|
||||
|
||||
array_block_disk const *get_header() const {
|
||||
return reinterpret_cast<array_block_disk const *>(ref_.data().raw());
|
||||
return reinterpret_cast<array_block_disk const *>(ref_.data());
|
||||
}
|
||||
|
||||
disk_type &element_at(unsigned int index) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "persistent-data/data-structures/bitset.h"
|
||||
#include "persistent-data/math_utils.h"
|
||||
|
||||
using namespace boost;
|
||||
using namespace persistent_data;
|
||||
using namespace persistent_data::bitset_detail;
|
||||
using namespace std;
|
||||
@ -12,7 +11,7 @@ using namespace std;
|
||||
namespace {
|
||||
struct bitset_traits {
|
||||
typedef base::le64 disk_type;
|
||||
typedef uint64_t value_type;
|
||||
typedef ::uint64_t value_type;
|
||||
typedef no_op_ref_counter<uint64_t> ref_counter;
|
||||
|
||||
static void unpack(disk_type const &disk, value_type &value) {
|
||||
@ -27,25 +26,31 @@ namespace {
|
||||
|
||||
namespace persistent_data {
|
||||
namespace bitset_detail {
|
||||
size_t BITS_PER_ULL = 64;
|
||||
|
||||
class bitset_impl {
|
||||
public:
|
||||
typedef boost::shared_ptr<bitset_impl> ptr;
|
||||
typedef persistent_data::transaction_manager::ptr tm_ptr;
|
||||
|
||||
bitset_impl(tm_ptr tm)
|
||||
bitset_impl(transaction_manager &tm)
|
||||
: nr_bits_(0),
|
||||
array_(tm, rc_) {
|
||||
}
|
||||
|
||||
bitset_impl(tm_ptr tm, block_address root, unsigned nr_bits)
|
||||
bitset_impl(transaction_manager &tm, block_address root, unsigned nr_bits)
|
||||
: nr_bits_(nr_bits),
|
||||
array_(tm, rc_, root, nr_bits) {
|
||||
array_(tm, rc_, root, div_up<unsigned>(nr_bits, BITS_PER_ULL)) {
|
||||
}
|
||||
|
||||
block_address get_root() const {
|
||||
return array_.get_root();
|
||||
}
|
||||
|
||||
unsigned get_nr_bits() const {
|
||||
return nr_bits_;
|
||||
}
|
||||
|
||||
void grow(unsigned new_nr_bits, bool default_value) {
|
||||
pad_last_block(default_value);
|
||||
resize_array(new_nr_bits, default_value);
|
||||
@ -77,7 +82,7 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
void walk_bitset(bitset_visitor &v) const {
|
||||
bit_visitor vv(v);
|
||||
bit_visitor vv(v, nr_bits_);
|
||||
damage_visitor dv(v);
|
||||
array_.visit_values(vv, dv);
|
||||
}
|
||||
@ -85,18 +90,20 @@ namespace persistent_data {
|
||||
private:
|
||||
class bit_visitor {
|
||||
public:
|
||||
bit_visitor(bitset_visitor &v)
|
||||
: v_(v) {
|
||||
bit_visitor(bitset_visitor &v, unsigned nr_bits)
|
||||
: v_(v),
|
||||
nr_bits_(nr_bits) {
|
||||
}
|
||||
|
||||
void visit(uint32_t word_index, uint64_t word) {
|
||||
uint32_t bit_index = word_index * 64;
|
||||
for (unsigned bit = 0; bit < 64; bit++, bit_index++)
|
||||
v_.visit(bit_index, !!(word & (1 << bit)));
|
||||
for (unsigned bit = 0; bit < 64 && bit_index < nr_bits_; bit++, bit_index++)
|
||||
v_.visit(bit_index, !!(word & (1ULL << bit)));
|
||||
}
|
||||
|
||||
private:
|
||||
bitset_visitor &v_;
|
||||
unsigned nr_bits_;
|
||||
};
|
||||
|
||||
class damage_visitor {
|
||||
@ -112,11 +119,11 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
private:
|
||||
optional<uint32_t> lifted_mult64(optional<uint32_t> const &m) {
|
||||
boost::optional<uint32_t> lifted_mult64(boost::optional<uint32_t> const &m) {
|
||||
if (!m)
|
||||
return m;
|
||||
|
||||
return optional<uint32_t>(*m * 64);
|
||||
return boost::optional<uint32_t>(*m * 64);
|
||||
}
|
||||
|
||||
bitset_visitor &v_;
|
||||
@ -184,7 +191,7 @@ namespace persistent_data {
|
||||
if (n >= nr_bits_) {
|
||||
std::ostringstream str;
|
||||
str << "bitset index out of bounds ("
|
||||
<< n << " >= " << nr_bits_ << endl;
|
||||
<< n << " >= " << nr_bits_ << ")";
|
||||
throw runtime_error(str.str());
|
||||
}
|
||||
}
|
||||
@ -198,12 +205,12 @@ namespace persistent_data {
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
persistent_data::bitset::bitset(tm_ptr tm)
|
||||
persistent_data::bitset::bitset(transaction_manager &tm)
|
||||
: impl_(new bitset_impl(tm))
|
||||
{
|
||||
}
|
||||
|
||||
persistent_data::bitset::bitset(tm_ptr tm, block_address root, unsigned nr_bits)
|
||||
persistent_data::bitset::bitset(transaction_manager &tm, block_address root, unsigned nr_bits)
|
||||
: impl_(new bitset_impl(tm, root, nr_bits))
|
||||
{
|
||||
}
|
||||
@ -214,6 +221,12 @@ persistent_data::bitset::get_root() const
|
||||
return impl_->get_root();
|
||||
}
|
||||
|
||||
unsigned
|
||||
persistent_data::bitset::get_nr_bits() const
|
||||
{
|
||||
return impl_->get_nr_bits();
|
||||
}
|
||||
|
||||
void
|
||||
persistent_data::bitset::grow(unsigned new_nr_bits, bool default_value)
|
||||
{
|
||||
|
@ -16,8 +16,8 @@
|
||||
// with thin-provisioning-tools. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef BITSET_H
|
||||
#define BITSET_H
|
||||
#ifndef PERSISTENT_DATA_DATA_STRUCTURES_BITSET_H
|
||||
#define PERSISTENT_DATA_DATA_STRUCTURES_BITSET_H
|
||||
|
||||
#include "persistent-data/run.h"
|
||||
|
||||
@ -49,11 +49,12 @@ namespace persistent_data {
|
||||
class bitset {
|
||||
public:
|
||||
typedef boost::shared_ptr<bitset> ptr;
|
||||
typedef persistent_data::transaction_manager::ptr tm_ptr;
|
||||
|
||||
bitset(tm_ptr tm);
|
||||
bitset(tm_ptr tm, block_address root, unsigned nr_bits);
|
||||
bitset(transaction_manager &tm);
|
||||
bitset(transaction_manager &tm,
|
||||
block_address root, unsigned nr_bits);
|
||||
block_address get_root() const;
|
||||
unsigned get_nr_bits() const;
|
||||
void grow(unsigned new_nr_bits, bool default_value);
|
||||
void destroy();
|
||||
|
||||
|
146
persistent-data/data-structures/bloom_filter.cc
Normal file
146
persistent-data/data-structures/bloom_filter.cc
Normal file
@ -0,0 +1,146 @@
|
||||
#include "persistent-data/data-structures/bloom_filter.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace persistent_data;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
static const uint64_t m1 = 0x9e37fffffffc0001ULL;
|
||||
static const unsigned bits = 18;
|
||||
|
||||
static uint32_t hash1(block_address const &b) {
|
||||
return (b * m1) >> bits;
|
||||
}
|
||||
|
||||
static uint32_t hash2(block_address const &b) {
|
||||
uint32_t n = b;
|
||||
|
||||
n = n ^ (n >> 16);
|
||||
n = n * 0x85ebca6bu;
|
||||
n = n ^ (n >> 13);
|
||||
n = n * 0xc2b2ae35u;
|
||||
n = n ^ (n >> 16);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void check_power_of_two(unsigned nr_bits) {
|
||||
if (nr_bits & (nr_bits - 1))
|
||||
throw std::runtime_error("bloom filter needs a power of two nr_bits");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
bloom_filter::bloom_filter(transaction_manager &tm,
|
||||
unsigned nr_bits, unsigned nr_probes)
|
||||
: tm_(tm),
|
||||
bits_(tm),
|
||||
nr_probes_(nr_probes),
|
||||
mask_(nr_bits - 1)
|
||||
{
|
||||
check_power_of_two(nr_bits);
|
||||
bits_.grow(nr_bits, false);
|
||||
}
|
||||
|
||||
bloom_filter::bloom_filter(transaction_manager &tm, block_address root,
|
||||
unsigned nr_bits, unsigned nr_probes)
|
||||
: tm_(tm),
|
||||
bits_(tm, root, nr_bits),
|
||||
nr_probes_(nr_probes),
|
||||
mask_(nr_bits - 1)
|
||||
{
|
||||
check_power_of_two(nr_bits);
|
||||
}
|
||||
|
||||
block_address
|
||||
bloom_filter::get_root() const
|
||||
{
|
||||
return bits_.get_root();
|
||||
}
|
||||
|
||||
bool
|
||||
bloom_filter::test(uint64_t b)
|
||||
{
|
||||
vector<unsigned> probes(nr_probes_);
|
||||
fill_probes(b, probes);
|
||||
|
||||
for (unsigned p = 0; p < nr_probes_; p++)
|
||||
if (!bits_.get(probes[p]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bloom_filter::set(uint64_t b)
|
||||
{
|
||||
vector<unsigned> probes(nr_probes_);
|
||||
fill_probes(b, probes);
|
||||
|
||||
for (unsigned p = 0; p < nr_probes_; p++)
|
||||
bits_.set(probes[p], true);
|
||||
}
|
||||
|
||||
void
|
||||
bloom_filter::flush()
|
||||
{
|
||||
bits_.flush();
|
||||
}
|
||||
|
||||
void
|
||||
bloom_filter::fill_probes(block_address b, vector<unsigned> &probes) const
|
||||
{
|
||||
uint32_t h1 = hash1(b) & mask_;
|
||||
uint32_t h2 = hash2(b) & mask_;
|
||||
|
||||
probes[0] = h1;
|
||||
for (unsigned p = 1; p < nr_probes_; p++) {
|
||||
h1 = (h1 + h2) & mask_;
|
||||
h2 = (h2 + p) & mask_;
|
||||
probes[p] = h1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bloom_filter::print_debug(ostream &out)
|
||||
{
|
||||
print_residency(out);
|
||||
|
||||
map<unsigned, unsigned> runs;
|
||||
|
||||
for (unsigned i = 0; i < bits_.get_nr_bits();) {
|
||||
bool v = bits_.get(i);
|
||||
unsigned run_length = 1;
|
||||
|
||||
while (++i < bits_.get_nr_bits() && bits_.get(i) == v)
|
||||
run_length++;
|
||||
|
||||
map<unsigned, unsigned>::iterator it = runs.find(run_length);
|
||||
if (it != runs.end())
|
||||
it->second++;
|
||||
else
|
||||
runs.insert(make_pair(run_length, 1));
|
||||
}
|
||||
|
||||
{
|
||||
map<unsigned, unsigned>::const_iterator it;
|
||||
for (it = runs.begin(); it != runs.end(); ++it)
|
||||
out << it->first << ": " << it->second << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bloom_filter::print_residency(ostream &out)
|
||||
{
|
||||
unsigned count = 0;
|
||||
for (unsigned i = 0; i < bits_.get_nr_bits(); i++)
|
||||
if (bits_.get(i))
|
||||
count++;
|
||||
|
||||
out << "residency: " << count << "/" << bits_.get_nr_bits() << endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
45
persistent-data/data-structures/bloom_filter.h
Normal file
45
persistent-data/data-structures/bloom_filter.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef PERSISTENT_DATA_DATA_STRUCTURES_BLOOM_FILTER_H
|
||||
#define PERSISTENT_DATA_DATA_STRUCTURES_BLOOM_FILTER_H
|
||||
|
||||
#include "persistent-data/transaction_manager.h"
|
||||
#include "persistent-data/data-structures/bitset.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace persistent_data {
|
||||
class bloom_filter {
|
||||
public:
|
||||
typedef boost::shared_ptr<bloom_filter> ptr;
|
||||
|
||||
// nr_bits must be a power of two
|
||||
bloom_filter(transaction_manager &tm,
|
||||
unsigned nr_bits, unsigned nr_probes);
|
||||
|
||||
bloom_filter(transaction_manager &tm, block_address root,
|
||||
unsigned nr_bits_power, unsigned nr_probes);
|
||||
|
||||
block_address get_root() const;
|
||||
|
||||
bool test(uint64_t b); // not const due to caching effects in bitset
|
||||
void set(uint64_t b);
|
||||
void flush();
|
||||
|
||||
void print_debug(ostream &out);
|
||||
|
||||
private:
|
||||
void print_residency(ostream &out);
|
||||
|
||||
void fill_probes(block_address b, vector<unsigned> &probes) const;
|
||||
|
||||
transaction_manager &tm_;
|
||||
persistent_data::bitset bits_;
|
||||
unsigned nr_probes_;
|
||||
uint64_t mask_;
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@
|
||||
#ifndef BTREE_H
|
||||
#define BTREE_H
|
||||
|
||||
#include "persistent-data/endian_utils.h"
|
||||
#include "base/endian_utils.h"
|
||||
#include "persistent-data/transaction_manager.h"
|
||||
#include "persistent-data/data-structures/ref_counter.h"
|
||||
|
||||
@ -43,22 +43,6 @@ namespace persistent_data {
|
||||
space_map::ptr sm_;
|
||||
};
|
||||
|
||||
// FIXME: move to sep file. I don't think it's directly used by
|
||||
// the btree code.
|
||||
struct uint64_traits {
|
||||
typedef base::le64 disk_type;
|
||||
typedef uint64_t value_type;
|
||||
typedef no_op_ref_counter<uint64_t> ref_counter;
|
||||
|
||||
static void unpack(disk_type const &disk, value_type &value) {
|
||||
value = base::to_cpu<uint64_t>(disk);
|
||||
}
|
||||
|
||||
static void pack(value_type const &value, disk_type &disk) {
|
||||
disk = base::to_disk<base::le64>(value);
|
||||
}
|
||||
};
|
||||
|
||||
struct block_traits {
|
||||
typedef base::le64 disk_type;
|
||||
typedef block_address value_type;
|
||||
@ -179,12 +163,15 @@ namespace persistent_data {
|
||||
|
||||
private:
|
||||
static unsigned calc_max_entries(void);
|
||||
void check_fits_within_block() const;
|
||||
|
||||
void *key_ptr(unsigned i) const;
|
||||
void *value_ptr(unsigned i) const;
|
||||
|
||||
block_address location_;
|
||||
disk_node *raw_;
|
||||
|
||||
mutable bool checked_; // flag indicating we've checked the data fits in the block
|
||||
};
|
||||
|
||||
//------------------------------------------------
|
||||
@ -197,7 +184,7 @@ namespace persistent_data {
|
||||
return node_ref<ValueTraits>(
|
||||
b.get_location(),
|
||||
reinterpret_cast<disk_node *>(
|
||||
const_cast<unsigned char *>(b.data().raw())));
|
||||
const_cast<void *>(b.data())));
|
||||
}
|
||||
|
||||
template <typename ValueTraits>
|
||||
@ -206,14 +193,13 @@ namespace persistent_data {
|
||||
{
|
||||
return node_ref<ValueTraits>(
|
||||
b.get_location(),
|
||||
reinterpret_cast<disk_node *>(
|
||||
const_cast<unsigned char *>(b.data().raw())));
|
||||
reinterpret_cast<disk_node *>(b.data()));
|
||||
}
|
||||
|
||||
class ro_spine : private boost::noncopyable {
|
||||
public:
|
||||
ro_spine(transaction_manager::ptr tm,
|
||||
block_manager<>::validator::ptr v)
|
||||
ro_spine(transaction_manager &tm,
|
||||
bcache::validator::ptr v)
|
||||
: tm_(tm),
|
||||
validator_(v) {
|
||||
}
|
||||
@ -226,8 +212,8 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
private:
|
||||
transaction_manager::ptr tm_;
|
||||
block_manager<>::validator::ptr validator_;
|
||||
transaction_manager &tm_;
|
||||
bcache::validator::ptr validator_;
|
||||
std::list<block_manager<>::read_ref> spine_;
|
||||
};
|
||||
|
||||
@ -237,8 +223,8 @@ namespace persistent_data {
|
||||
typedef transaction_manager::write_ref write_ref;
|
||||
typedef boost::optional<block_address> maybe_block;
|
||||
|
||||
shadow_spine(transaction_manager::ptr tm,
|
||||
block_manager<>::validator::ptr v)
|
||||
shadow_spine(transaction_manager &tm,
|
||||
bcache::validator::ptr v)
|
||||
|
||||
: tm_(tm),
|
||||
validator_(v) {
|
||||
@ -290,8 +276,8 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
private:
|
||||
transaction_manager::ptr tm_;
|
||||
block_manager<>::validator::ptr validator_;
|
||||
transaction_manager &tm_;
|
||||
bcache::validator::ptr validator_;
|
||||
std::list<block_manager<>::write_ref> spine_;
|
||||
maybe_block root_;
|
||||
};
|
||||
@ -349,10 +335,10 @@ namespace persistent_data {
|
||||
typedef typename btree_detail::node_ref<ValueTraits> leaf_node;
|
||||
typedef typename btree_detail::node_ref<block_traits> internal_node;
|
||||
|
||||
btree(typename persistent_data::transaction_manager::ptr tm,
|
||||
btree(transaction_manager &tm,
|
||||
typename ValueTraits::ref_counter rc);
|
||||
|
||||
btree(typename transaction_manager::ptr tm,
|
||||
btree(transaction_manager &tm,
|
||||
block_address root,
|
||||
typename ValueTraits::ref_counter rc);
|
||||
|
||||
@ -448,12 +434,12 @@ namespace persistent_data {
|
||||
void inc_children(btree_detail::shadow_spine &spine,
|
||||
RefCounter &leaf_rc);
|
||||
|
||||
typename persistent_data::transaction_manager::ptr tm_;
|
||||
transaction_manager &tm_;
|
||||
bool destroy_;
|
||||
block_address root_;
|
||||
block_ref_counter internal_rc_;
|
||||
typename ValueTraits::ref_counter rc_;
|
||||
typename block_manager<>::validator::ptr validator_;
|
||||
typename bcache::validator::ptr validator_;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -32,9 +32,9 @@ namespace {
|
||||
using namespace btree_detail;
|
||||
using namespace std;
|
||||
|
||||
struct btree_node_validator : public block_manager<>::validator {
|
||||
virtual void check(buffer<> const &b, block_address location) const {
|
||||
disk_node const *data = reinterpret_cast<disk_node const *>(&b);
|
||||
struct btree_node_validator : public bcache::validator {
|
||||
virtual void check(void const *raw, block_address location) const {
|
||||
disk_node const *data = reinterpret_cast<disk_node const *>(raw);
|
||||
node_header const *n = &data->header;
|
||||
crc32c sum(BTREE_CSUM_XOR);
|
||||
sum.append(&n->flags, MD_BLOCK_SIZE - sizeof(uint32_t));
|
||||
@ -45,8 +45,8 @@ namespace {
|
||||
throw checksum_error("bad block nr in btree node");
|
||||
}
|
||||
|
||||
virtual void prepare(buffer<> &b, block_address location) const {
|
||||
disk_node *data = reinterpret_cast<disk_node *>(&b);
|
||||
virtual void prepare(void *raw, block_address location) const {
|
||||
disk_node *data = reinterpret_cast<disk_node *>(raw);
|
||||
node_header *n = &data->header;
|
||||
n->blocknr = to_disk<base::le64, uint64_t>(location);
|
||||
|
||||
@ -64,7 +64,7 @@ namespace persistent_data {
|
||||
inline void
|
||||
ro_spine::step(block_address b)
|
||||
{
|
||||
spine_.push_back(tm_->read_lock(b, validator_));
|
||||
spine_.push_back(tm_.read_lock(b, validator_));
|
||||
if (spine_.size() > 2)
|
||||
spine_.pop_front();
|
||||
}
|
||||
@ -72,11 +72,11 @@ namespace persistent_data {
|
||||
inline bool
|
||||
shadow_spine::step(block_address b)
|
||||
{
|
||||
pair<write_ref, bool> p = tm_->shadow(b, validator_);
|
||||
pair<write_ref, bool> p = tm_.shadow(b, validator_);
|
||||
try {
|
||||
step(p.first);
|
||||
} catch (...) {
|
||||
tm_->get_sm()->dec(p.first.get_location());
|
||||
tm_.get_sm()->dec(p.first.get_location());
|
||||
throw;
|
||||
}
|
||||
return p.second;
|
||||
@ -87,7 +87,8 @@ namespace persistent_data {
|
||||
template <typename ValueTraits>
|
||||
node_ref<ValueTraits>::node_ref(block_address location, disk_node *raw)
|
||||
: location_(location),
|
||||
raw_(raw)
|
||||
raw_(raw),
|
||||
checked_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -330,6 +331,8 @@ namespace persistent_data {
|
||||
void *
|
||||
node_ref<ValueTraits>::key_ptr(unsigned i) const
|
||||
{
|
||||
check_fits_within_block();
|
||||
|
||||
return raw_->keys + i;
|
||||
}
|
||||
|
||||
@ -337,6 +340,8 @@ namespace persistent_data {
|
||||
void *
|
||||
node_ref<ValueTraits>::value_ptr(unsigned i) const
|
||||
{
|
||||
check_fits_within_block();
|
||||
|
||||
void *value_base = &raw_->keys[to_cpu<uint32_t>(raw_->header.max_entries)];
|
||||
return static_cast<unsigned char *>(value_base) +
|
||||
sizeof(typename ValueTraits::disk_type) * i;
|
||||
@ -357,40 +362,75 @@ namespace persistent_data {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueTraits>
|
||||
void
|
||||
node_ref<ValueTraits>::check_fits_within_block() const {
|
||||
if (checked_)
|
||||
return;
|
||||
|
||||
if (sizeof(typename ValueTraits::disk_type) != get_value_size()) {
|
||||
std::ostringstream out;
|
||||
out << "value size mismatch: expected " << sizeof(typename ValueTraits::disk_type)
|
||||
<< ", but got " << get_value_size()
|
||||
<< ". This is not the btree you are looking for." << std::endl;
|
||||
throw std::runtime_error(out.str());
|
||||
}
|
||||
|
||||
unsigned max = calc_max_entries();
|
||||
|
||||
if (max < get_nr_entries()) {
|
||||
std::ostringstream out;
|
||||
out << "Bad nr of elements: max per block = "
|
||||
<< max << ", actual = " << get_nr_entries() << std::endl;
|
||||
throw std::runtime_error(out.str());
|
||||
}
|
||||
|
||||
checked_ = true;
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
template <unsigned Levels, typename ValueTraits>
|
||||
btree<Levels, ValueTraits>::
|
||||
btree(typename transaction_manager::ptr tm,
|
||||
btree(transaction_manager &tm,
|
||||
typename ValueTraits::ref_counter rc)
|
||||
: tm_(tm),
|
||||
destroy_(false),
|
||||
internal_rc_(tm->get_sm()),
|
||||
internal_rc_(tm.get_sm()),
|
||||
rc_(rc),
|
||||
validator_(new btree_node_validator)
|
||||
{
|
||||
using namespace btree_detail;
|
||||
|
||||
write_ref root = tm_->new_block(validator_);
|
||||
write_ref root = tm_.new_block(validator_);
|
||||
|
||||
leaf_node n = to_node<ValueTraits>(root);
|
||||
n.set_type(btree_detail::LEAF);
|
||||
n.set_nr_entries(0);
|
||||
n.set_max_entries();
|
||||
n.set_value_size(sizeof(typename ValueTraits::disk_type));
|
||||
if (Levels > 1) {
|
||||
internal_node n = to_node<block_traits>(root);
|
||||
n.set_type(btree_detail::LEAF);
|
||||
n.set_nr_entries(0);
|
||||
n.set_max_entries();
|
||||
n.set_value_size(sizeof(typename block_traits::disk_type));
|
||||
|
||||
} else {
|
||||
leaf_node n = to_node<ValueTraits>(root);
|
||||
n.set_type(btree_detail::LEAF);
|
||||
n.set_nr_entries(0);
|
||||
n.set_max_entries();
|
||||
n.set_value_size(sizeof(typename ValueTraits::disk_type));
|
||||
}
|
||||
|
||||
root_ = root.get_location();
|
||||
}
|
||||
|
||||
template <unsigned Levels, typename ValueTraits>
|
||||
btree<Levels, ValueTraits>::
|
||||
btree(typename transaction_manager::ptr tm,
|
||||
btree(transaction_manager &tm,
|
||||
block_address root,
|
||||
typename ValueTraits::ref_counter rc)
|
||||
: tm_(tm),
|
||||
destroy_(false),
|
||||
root_(root),
|
||||
internal_rc_(tm->get_sm()),
|
||||
internal_rc_(tm.get_sm()),
|
||||
rc_(rc),
|
||||
validator_(new btree_node_validator)
|
||||
{
|
||||
@ -519,7 +559,7 @@ namespace persistent_data {
|
||||
typename btree<Levels, ValueTraits>::ptr
|
||||
btree<Levels, ValueTraits>::clone() const
|
||||
{
|
||||
tm_->get_sm()->inc(root_);
|
||||
tm_.get_sm()->inc(root_);
|
||||
return ptr(new btree<Levels, ValueTraits>(tm_, root_, rc_));
|
||||
}
|
||||
|
||||
@ -595,13 +635,13 @@ namespace persistent_data {
|
||||
node_type type;
|
||||
unsigned nr_left, nr_right;
|
||||
|
||||
write_ref left = tm_->new_block(validator_);
|
||||
write_ref left = tm_.new_block(validator_);
|
||||
node_ref<ValueTraits> l = to_node<ValueTraits>(left);
|
||||
l.set_nr_entries(0);
|
||||
l.set_max_entries();
|
||||
l.set_value_size(sizeof(typename ValueTraits::disk_type));
|
||||
|
||||
write_ref right = tm_->new_block(validator_);
|
||||
write_ref right = tm_.new_block(validator_);
|
||||
node_ref<ValueTraits> r = to_node<ValueTraits>(right);
|
||||
r.set_nr_entries(0);
|
||||
r.set_max_entries();
|
||||
@ -655,7 +695,7 @@ namespace persistent_data {
|
||||
node_ref<ValueTraits> l = spine.template get_node<ValueTraits>();
|
||||
block_address left = spine.get_block();
|
||||
|
||||
write_ref right = tm_->new_block(validator_);
|
||||
write_ref right = tm_.new_block(validator_);
|
||||
node_ref<ValueTraits> r = to_node<ValueTraits>(right);
|
||||
|
||||
unsigned nr_left = l.get_nr_entries() / 2;
|
||||
@ -782,12 +822,15 @@ namespace persistent_data {
|
||||
{
|
||||
using namespace btree_detail;
|
||||
|
||||
read_ref blk = tm_->read_lock(b, validator_);
|
||||
read_ref blk = tm_.read_lock(b, validator_);
|
||||
internal_node o = to_node<block_traits>(blk);
|
||||
|
||||
// FIXME: use a switch statement
|
||||
if (o.get_type() == INTERNAL) {
|
||||
if (v.visit_internal(loc, o))
|
||||
if (v.visit_internal(loc, o)) {
|
||||
for (unsigned i = 0; i < o.get_nr_entries(); i++)
|
||||
tm_.prefetch(o.value_at(i));
|
||||
|
||||
for (unsigned i = 0; i < o.get_nr_entries(); i++) {
|
||||
node_location loc2(loc);
|
||||
|
||||
@ -796,6 +839,7 @@ namespace persistent_data {
|
||||
|
||||
walk_tree(v, loc2, o.value_at(i));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (loc.path.size() < Levels - 1) {
|
||||
if (v.visit_internal_leaf(loc, o))
|
||||
|
@ -85,23 +85,31 @@ namespace persistent_data {
|
||||
// different sub tree (by looking at the btree_path).
|
||||
class path_tracker {
|
||||
public:
|
||||
path_tracker() {
|
||||
// We push an empty path, to ensure there
|
||||
// is always a current_path.
|
||||
paths_.push_back(btree_path());
|
||||
}
|
||||
|
||||
// returns the old path if the tree has changed.
|
||||
boost::optional<btree_path> next_path(btree_path const &p) {
|
||||
if (p != path_) {
|
||||
btree_path tmp(path_);
|
||||
path_ = p;
|
||||
return boost::optional<btree_path>(tmp);
|
||||
btree_path const *next_path(btree_path const &p) {
|
||||
if (p != current_path()) {
|
||||
if (paths_.size() == 2)
|
||||
paths_.pop_front();
|
||||
paths_.push_back(p);
|
||||
|
||||
return &paths_.front();
|
||||
}
|
||||
|
||||
return boost::optional<btree_path>();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
btree_path const ¤t_path() const {
|
||||
return path_;
|
||||
return paths_.back();
|
||||
}
|
||||
|
||||
private:
|
||||
btree_path path_;
|
||||
std::list<btree_path> paths_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------
|
||||
@ -189,11 +197,12 @@ namespace persistent_data {
|
||||
private:
|
||||
void visit_values(btree_path const &path,
|
||||
node_ref<ValueTraits> const &n) {
|
||||
btree_path p2(path);
|
||||
unsigned nr = n.get_nr_entries();
|
||||
for (unsigned i = 0; i < nr; i++) {
|
||||
btree_path p2(path);
|
||||
p2.push_back(n.key_at(i));
|
||||
value_visitor_.visit(p2, n.value_at(i));
|
||||
p2.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,7 +436,7 @@ namespace persistent_data {
|
||||
}
|
||||
|
||||
void update_path(btree_path const &path) {
|
||||
boost::optional<btree_path> old_path = path_tracker_.next_path(path);
|
||||
btree_path const *old_path = path_tracker_.next_path(path);
|
||||
if (old_path)
|
||||
// we need to emit any errors that
|
||||
// were accrued against the old
|
||||
|
38
persistent-data/data-structures/simple_traits.h
Normal file
38
persistent-data/data-structures/simple_traits.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef PERSISTENT_DATA_DATA_STRUCTURES_SIMPLE_TRAITS_H
|
||||
#define PERSISTENT_DATA_DATA_STRUCTURES_SIMPLE_TRAITS_H
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace persistent_data {
|
||||
struct uint64_traits {
|
||||
typedef base::le64 disk_type;
|
||||
typedef uint64_t value_type;
|
||||
typedef no_op_ref_counter<uint64_t> ref_counter;
|
||||
|
||||
static void unpack(disk_type const &disk, value_type &value) {
|
||||
value = base::to_cpu<uint64_t>(disk);
|
||||
}
|
||||
|
||||
static void pack(value_type const &value, disk_type &disk) {
|
||||
disk = base::to_disk<base::le64>(value);
|
||||
}
|
||||
};
|
||||
|
||||
struct uint32_traits {
|
||||
typedef base::le32 disk_type;
|
||||
typedef uint32_t value_type;
|
||||
typedef no_op_ref_counter<uint32_t> ref_counter;
|
||||
|
||||
static void unpack(disk_type const &disk, value_type &value) {
|
||||
value = base::to_cpu<uint32_t>(disk);
|
||||
}
|
||||
|
||||
static void pack(value_type const &value, disk_type &disk) {
|
||||
disk = base::to_disk<base::le32>(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user