From d362fdc867004d780ec86cd4516f5cfe8600e22c Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Thu, 10 Jan 2013 23:00:50 +0000 Subject: [PATCH] array data structure wip --- persistent-data/array.h | 154 ++++++++++++++++++++ persistent-data/array.tcc | 290 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 persistent-data/array.h create mode 100644 persistent-data/array.tcc diff --git a/persistent-data/array.h b/persistent-data/array.h new file mode 100644 index 0000000..3792df8 --- /dev/null +++ b/persistent-data/array.h @@ -0,0 +1,154 @@ +// Copyright (C) 2012 Red Hat, Inc. All rights reserved. +// +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +#ifndef ARRAY_H +#define ARRAY_H + +#include "btree.h" + +//---------------------------------------------------------------- + +namespace persistent_data { + struct array_block_disk { + __le32 csum; + __le32 max_entries; + __le32 nr_entries; + __le32 value_size; + __le64 blocknr; + } __attribute__((packed)); + + template + class ro_array_block { + public: + typedef typename ValueTraits::value_type value_type; + typedef block_manager<>::read_ref read_ref; + + ro_array_block(read_ref rr); + + unsigned nr_entries() const; + value_type get(unsigned index) const; + + private: + const void *element_at(unsigned int index) const; + + read_ref rr_; + }; + + template + class array_block : public ro_array_block { + public: + typedef typename ValueTraits::value_type value_type; + typedef block_manager<>::write_ref write_ref; + + array_block(write_ref wr); + + // No virtual methods, so no need for a virtual destructor. + // Not really sure inheritance is the right relationship + // though. + + void set(unsigned index, value_type const &v); + void inc_all_entries(typename ValueTraits::ref_counter &rc); + void dec_all_entries(typename ValueTraits::ref_counter &rc); + + block_address address() const; + + // FIXME: why isn't this visible? + //using ro_array_block::nr_entries(); + + private: + void *element_at(unsigned int index); + + write_ref wr_; + }; + + class BlockRefCounter { + public: + void inc(uint64_t const &v) {} + void dec(uint64_t const &v) {} + }; + + template + struct array_block_traits { + typedef base::__le64 disk_type; + typedef array_block value_type; + typedef NoOpRefCounter ref_counter; + + static void unpack(disk_type const &disk, value_type &value) { + value = base::to_cpu(disk); + } + + static void pack(value_type const &value, disk_type &disk) { + disk = base::to_disk(value); + } + }; + + template + class array { + public: + typedef typename persistent_data::transaction_manager::ptr tm_ptr; + + typedef boost::shared_ptr > ptr; + typedef typename ValueTraits::value_type value_type; + + array(tm_ptr tm, + typename ValueTraits::ref_counter rc, + unsigned nr_entries, + value_type const &default_value); + + array(tm_ptr tm, + typename ValueTraits::ref_counter rc, + block_address root); + + void set_root(block_address root); + block_address get_root() const; + + void destroy(); + + void grow(unsigned old_size, unsigned new_size, value_type const &v); + void shrink(unsigned old_size, unsigned new_size); + + value_type const &get(unsigned index) const; + void set(unsigned index, value_type const &value); + + + private: + array_block new_ablock(); + ro_array_block get_ablock(unsigned block_index) const; + array_block shadow_ablock(unsigned block_index); + + void fill_tail_block(array_block &ab, + value_type v, + unsigned nr_entries); + void insert_full_blocks(unsigned begin_index, unsigned end_index, + value_type v); + void insert_tail_block(unsigned index, unsigned nr_entries, value_type v); + + + tm_ptr tm_; + bool destroy_; + unsigned entries_per_block_; // FIXME: initialise + btree<1, array_block_traits > block_tree_; + typename ValueTraits::ref_counter rc_; + }; +} + +#include "array.tcc" + +//---------------------------------------------------------------- + +#endif diff --git a/persistent-data/array.tcc b/persistent-data/array.tcc new file mode 100644 index 0000000..88faec3 --- /dev/null +++ b/persistent-data/array.tcc @@ -0,0 +1,290 @@ +// Copyright (C) 2012 Red Hat, Inc. All rights reserved. +// +// This file is part of the thin-provisioning-tools source. +// +// thin-provisioning-tools is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// thin-provisioning-tools is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with thin-provisioning-tools. If not, see +// . + +using namespace base; +using namespace persistent_data; + +//---------------------------------------------------------------- + +namespace { + 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(&b); + crc32c sum(ARRAY_CSUM_XOR); + sum.append(&data->max_entries, MD_BLOCK_SIZE - sizeof(uint32_t)); + if (sum.get_sum() != to_cpu(data->csum)) + throw checksum_error("bad checksum in array block node"); + + if (to_cpu(data->blocknr) != location) + throw checksum_error("bad block nr in array block"); + } + + virtual void prepare(buffer<> &b, block_address location) const { + array_block_disk *data = reinterpret_cast(&b); + data->blocknr = to_disk(location); + + crc32c sum(ARRAY_CSUM_XOR); + sum.append(&data->max_entries, MD_BLOCK_SIZE - sizeof(uint32_t)); + data->csum = to_disk(sum.get_sum()); + } + }; + + struct array_dim { + array_dim(unsigned nr_entries, unsigned entries_per_block) + : nr_full_blocks(nr_entries / entries_per_block), + nr_entries_in_last_block(nr_entries % entries_per_block) { + } + + unsigned nr_full_blocks; + unsigned nr_entries_in_last_block; + }; + + unsigned calc_max_entries(size_t value_size, size_t block_size) + { + return (block_size - sizeof(struct array_block_disk)) / value_size; + } +} + +//---------------------------------------------------------------- + +template +array::array(typename persistent_data::transaction_manager::ptr tm, + typename ValueTraits::ref_counter rc, + unsigned nr_entries, + value_type const &default_value) + : tm_(tm), + destroy_(false), + block_tree_(tm, array_block_traits()), + entries_per_block_(calc_max_entries(sizeof(value_type), MD_BLOCK_SIZE)), + rc_(rc) +{ +} + +template +array::array(typename persistent_data::transaction_manager::ptr tm, + typename ValueTraits::ref_counter rc, + block_address root) + : tm_(tm), + destroy_(false), + block_tree_(tm, root, array_block_traits()), + entries_per_block_(calc_max_entries(sizeof(value_type), MD_BLOCK_SIZE)), + rc_(rc) +{ +} + +template +void +array::set_root(block_address root) +{ + block_tree_.set_root(root); +} + +template +block_address +array::get_root() const +{ + return block_tree_.get_root(); +} + +template +void +array::destroy() +{ + block_tree_.destroy(); +} + +template +void +array::grow(unsigned old_size, unsigned new_size, + typename ValueTraits::value_type const &v) +{ + array_dim old_dim(old_size, entries_per_block_); + array_dim new_dim(new_size, entries_per_block_); + + if (new_dim.nr_full_blocks > old_dim.nr_full_blocks) { + if (old_dim.nr_entries_in_last_block > 0) { + array_block ab = shadow_ablock(old_dim.nr_full_blocks); + fill_tail_block(ab, v, entries_per_block_); + } + + insert_full_blocks(old_dim.nr_full_blocks, new_dim.nr_full_blocks + 1, v); + insert_tail_block(new_dim.nr_full_blocks, new_dim.nr_entries_in_last_block, v); + } else { + array_block ab = get_ablock(new_dim.nr_full_blocks - 1u); + fill_tail_block(ab, v, new_dim.nr_entries_in_last_block); + } +} + +template +void +array::shrink(unsigned old_size, unsigned new_size) +{ + +} + +template +typename array::value_type const & +array::get(unsigned index) const +{ + array_block ab = get_ablock(index / entries_per_block_); + return ab.get(index % entries_per_block_); +} + +template +void +array::set(unsigned index, value_type const &value) +{ + array_block ab = shadow_ablock(index / entries_per_block_); + ab.set(index % entries_per_block_, value); +} + +template +ro_array_block +array::get_ablock(unsigned block_index) const +{ + return ro_array_block(tm_->read_lock(block_index)); +} + +template +array_block +array::shadow_ablock(unsigned block_index) +{ + typedef typename block_manager<>::write_ref write_ref; + + transaction_manager::validator v(new array_block_validator); + std::pair p = tm_->shadow(block_index, v); + array_block ab(p.first); + + if (p.second) + ab.inc_all_entries(); + + uint64_t key[1]; + key[0] = block_index; + block_tree_.insert(key, ab.get_location()); + + return ab; +} + +template +void +array::fill_tail_block(array_block &ab, + value_type v, + unsigned nr_entries) +{ + for (unsigned i = ab.nr_entries(); i < nr_entries; i++) + ab.set(i, v); +} + +template +void +array::insert_full_blocks(unsigned begin_index, + unsigned end_index, + value_type v) +{ + array_block ab = new_ablock(); + space_map::ptr sm = tm_->get_sm(); + + for (unsigned i = 0; i < entries_per_block_; i++) + ab.set(i, v); + + for (uint64_t b = begin_index; b < end_index; b++) { + block_tree_.insert(b, ab); + sm->inc(ab.address()); + } + + sm->dec(ab.adress()); +} + +template +void +array::insert_tail_block(unsigned index, + unsigned nr_entries, + value_type v) +{ + array_block ab = new_ablock(); + + for (unsigned i = 0; i < nr_entries; i++) + ab.set(i, v); + + block_tree_.insert(index, ab); +} + +//---------------------------------------------------------------- + +template +ro_array_block::ro_array_block(read_ref rr) + : rr_(rr) +{ +} + +template +unsigned +ro_array_block::nr_entries() const +{ + array_block_disk const *data = + reinterpret_cast(&rr_.data()); + + return to_cpu(data->nr_entries); +} + +template +typename ValueTraits::value_type +ro_array_block::get(unsigned index) const +{ + value_type v; + ValueTraits::unpack(element_at(index), v); + return v; +} + +template +array_block::array_block(write_ref wr) + : wr_(wr) +{ +} + +template +void +array_block::set(unsigned index, value_type const &v) +{ + void *elt = element_at(index); + ValueTraits::pack(v, element_at(index)); +} + +template +void +array_block::inc_all_entries(typename ValueTraits::ref_counter &rc) +{ + unsigned nr = ro_array_block::nr_entries(); + + for (unsigned i = 0; i < nr; i++) + rc.inc(ro_array_block::get(i)); +} + +template +void +array_block::dec_all_entries(typename ValueTraits::ref_counter &rc) +{ + unsigned nr = ro_array_block::nr_entries(); + + for (unsigned i = 0; i < nr; i++) + rc.dec(ro_array_block::get(i)); +} + +//----------------------------------------------------------------