// 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)); } //----------------------------------------------------------------