#include "caching/metadata_dump.h" #include <set> using namespace std; using namespace caching; //---------------------------------------------------------------- namespace { string to_string(unsigned char const *data) { // FIXME: we're assuming the data is zero terminated here return std::string(reinterpret_cast<char const *>(data)); } void raise_metadata_damage() { throw std::runtime_error("metadata contains errors (run cache_check for details).\n" "perhaps you wanted to run with --repair ?"); } //-------------------------------- class mapping_emitter : public mapping_visitor { public: mapping_emitter(emitter::ptr e, set<block_address> &valid_blocks) : e_(e), valid_blocks_(valid_blocks) { } void visit(block_address cblock, mapping const &m) { if (m.flags_ & M_VALID) { e_->mapping(cblock, m.oblock_, m.flags_ & M_DIRTY); mark_valid(cblock); } } private: void mark_valid(block_address cblock) { valid_blocks_.insert(cblock); } emitter::ptr e_; set<block_address> &valid_blocks_; }; struct ignore_mapping_damage : public mapping_array_damage::damage_visitor { virtual void visit(mapping_array_damage::missing_mappings const &d) {} virtual void visit(mapping_array_damage::invalid_mapping const &d) {} }; class fatal_mapping_damage : public mapping_array_damage::damage_visitor { public: virtual void visit(mapping_array_damage::missing_mappings const &d) { raise_metadata_damage(); } virtual void visit(mapping_array_damage::invalid_mapping const &d) { raise_metadata_damage(); } }; //-------------------------------- class hint_emitter : public hint_visitor { public: hint_emitter(emitter::ptr e, set<block_address> &valid_blocks) : e_(e), valid_blocks_(valid_blocks) { } virtual void visit(block_address cblock, std::vector<unsigned char> const &data) { if (valid(cblock)) e_->hint(cblock, data); } private: bool valid(block_address cblock) const { return valid_blocks_.find(cblock) != valid_blocks_.end(); } emitter::ptr e_; set<block_address> &valid_blocks_; }; struct ignore_hint_damage : public hint_array_damage::damage_visitor { virtual void visit(hint_array_damage::missing_hints const &d) {} }; class fatal_hint_damage : public hint_array_damage::damage_visitor { virtual void visit(hint_array_damage::missing_hints const &d) { raise_metadata_damage(); } }; } //---------------------------------------------------------------- void caching::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair) { set<block_address> valid_blocks; superblock const &sb = md->sb_; e->begin_superblock(to_string(sb.uuid), sb.data_block_size, sb.cache_blocks, to_string(sb.policy_name), sb.policy_hint_size); e->begin_mappings(); { namespace mad = mapping_array_damage; mapping_emitter me(e, valid_blocks); ignore_mapping_damage ignore; fatal_mapping_damage fatal; mad::damage_visitor &dv = repair ? static_cast<mad::damage_visitor &>(ignore) : static_cast<mad::damage_visitor &>(fatal); walk_mapping_array(*md->mappings_, me, dv); } e->end_mappings(); // walk hints e->begin_hints(); if (md->hints_) { using namespace hint_array_damage; hint_emitter he(e, valid_blocks); ignore_hint_damage ignore; fatal_hint_damage fatal; damage_visitor &dv = repair ? static_cast<damage_visitor &>(ignore) : static_cast<damage_visitor &>(fatal); md->hints_->walk(he, dv); } e->end_hints(); // FIXME: walk discards e->end_superblock(); } //----------------------------------------------------------------