#include "caching/hint_array.h" using namespace boost; using namespace caching; using namespace caching::hint_array_damage; using namespace persistent_data; //---------------------------------------------------------------- namespace { template struct hint_traits { typedef unsigned char byte; typedef byte disk_type[WIDTH]; typedef vector value_type; typedef no_op_ref_counter ref_counter; // FIXME: slow copying for now static void unpack(disk_type const &disk, value_type &value) { value.resize(WIDTH); for (unsigned byte = 0; byte < WIDTH; byte++) value.at(byte) = disk[byte]; } static void pack(value_type const &value, disk_type &disk) { for (unsigned byte = 0; byte < WIDTH; byte++) disk[byte] = value.at(byte); } }; // We've got into a bit of a mess here. Templates are compile // time, and we don't know the hint width until run time. We're // going to have to provide specialisation for all legal widths and // use the appropriate one. #define all_widths \ xx(4); template std::shared_ptr mk_array(transaction_manager &tm) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr r = typename ha::ptr(new ha(tm, typename traits::ref_counter())); return r; } std::shared_ptr mk_array(transaction_manager &tm, uint32_t width) { switch (width) { #define xx(n) case n: return mk_array(tm) all_widths #undef xx default: throw runtime_error("invalid hint width"); } } //-------------------------------- template std::shared_ptr downcast_array(std::shared_ptr base) { std::shared_ptr a = dynamic_pointer_cast(base); if (!a) throw runtime_error("internal error: couldn't cast hint array"); return a; } //-------------------------------- template std::shared_ptr mk_array(transaction_manager &tm, block_address root, unsigned nr_entries) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr r = typename ha::ptr(new ha(tm, typename traits::ref_counter(), root, nr_entries)); return r; } std::shared_ptr mk_array(transaction_manager &tm, uint32_t width, block_address root, unsigned nr_entries) { switch (width) { #define xx(n) case n: return mk_array(tm, root, nr_entries) all_widths #undef xx default: throw runtime_error("invalid hint width"); } } //-------------------------------- template void get_hint(std::shared_ptr base, unsigned index, vector &data) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr a = downcast_array(base); data = a->get(index); } void get_hint_(uint32_t width, std::shared_ptr base, unsigned index, vector &data) { switch (width) { #define xx(n) case n: return get_hint(base, index, data) all_widths #undef xx } } //-------------------------------- template void set_hint(std::shared_ptr base, unsigned index, vector const &data) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr a = downcast_array(base); a->set(index, data); } void set_hint_(uint32_t width, std::shared_ptr base, unsigned index, vector const &data) { switch (width) { #define xx(n) case n: return set_hint(base, index, data) all_widths #undef xx } } //-------------------------------- template void grow(std::shared_ptr base, unsigned new_nr_entries, vector const &value) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr a = downcast_array(base); a->grow(new_nr_entries, value); } void grow_(uint32_t width, std::shared_ptr base, unsigned new_nr_entries, vector const &value) { switch (width) { #define xx(n) case n: return grow(base, new_nr_entries, value) all_widths #undef xx } } //-------------------------------- class value_adapter { public: value_adapter(hint_visitor &v) : v_(v) { } virtual void visit(uint32_t index, std::vector const &v) { v_.visit(static_cast(index), v); } private: hint_visitor &v_; }; struct no_op_visitor : public hint_visitor { virtual void visit(block_address cblock, std::vector const &v) { } }; class ll_damage_visitor { public: ll_damage_visitor(damage_visitor &v) : v_(v) { } virtual void visit(array_detail::damage const &d) { v_.visit(missing_hints(d.desc_, d.lost_keys_)); } private: damage_visitor &v_; }; template void walk_hints(std::shared_ptr base, hint_visitor &hv, damage_visitor &dv) { typedef hint_traits traits; typedef persistent_data::array ha; std::shared_ptr a = downcast_array(base); value_adapter vv(hv); ll_damage_visitor ll(dv); a->visit_values(vv, ll); } void walk_hints_(uint32_t width, std::shared_ptr base, hint_visitor &hv, damage_visitor &dv) { switch (width) { #define xx(n) case n: walk_hints(base, hv, dv); break all_widths #undef xx } } } //---------------------------------------------------------------- missing_hints::missing_hints(std::string const desc, run const &keys) : damage(desc), keys_(keys) { } void missing_hints::visit(damage_visitor &v) const { v.visit(*this); } //---------------------------------------------------------------- hint_array::hint_array(transaction_manager &tm, unsigned width) : width_(check_width(width)), impl_(mk_array(tm, width)) { } hint_array::hint_array(transaction_manager &tm, unsigned width, block_address root, unsigned nr_entries) : width_(check_width(width)), impl_(mk_array(tm, width, root, nr_entries)) { } block_address hint_array::get_root() const { return impl_->get_root(); } void hint_array::get_hint(unsigned index, vector &data) const { get_hint_(width_, impl_, index, data); } void hint_array::set_hint(unsigned index, vector const &data) { set_hint_(width_, impl_, index, data); } void hint_array::grow(unsigned new_nr_entries, vector const &value) { grow_(width_, impl_, new_nr_entries, value); } void hint_array::walk(hint_visitor &hv, hint_array_damage::damage_visitor &dv) { walk_hints_(width_, impl_, hv, dv); } void hint_array::check(hint_array_damage::damage_visitor &visitor) { no_op_visitor vv; walk(vv, visitor); } uint32_t hint_array::check_width(uint32_t width) { if (width % 4 || width == 0 || width > 128) { ostringstream msg; msg << "invalid hint width: " << width; throw runtime_error(msg.str()); } return width; } //----------------------------------------------------------------