diff --git a/era/era_dump.cc b/era/era_dump.cc index a2c82aa..c9e14ad 100644 --- a/era/era_dump.cc +++ b/era/era_dump.cc @@ -19,10 +19,12 @@ using namespace std; namespace { struct flags { flags() - : repair_(false) { + : repair_(false), + logical_(false) { } bool repair_; + bool logical_; }; //-------------------------------- @@ -40,11 +42,11 @@ namespace { if (want_stdout(output)) { emitter::ptr e = create_xml_emitter(cout); - metadata_dump(md, e, fs.repair_); + metadata_dump(md, e, fs.repair_, fs.logical_); } else { ofstream out(output.c_str()); emitter::ptr e = create_xml_emitter(out); - metadata_dump(md, e, fs.repair_); + metadata_dump(md, e, fs.repair_, fs.logical_); } } catch (std::exception &e) { @@ -61,7 +63,8 @@ namespace { << " {-h|--help}" << endl << " {-o }" << endl << " {-V|--version}" << endl - << " {--repair}" << endl; + << " {--repair}" << endl + << " {--logical}" << endl; } } @@ -79,6 +82,7 @@ int main(int argc, char **argv) { "output", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'V' }, { "repair", no_argument, NULL, 1 }, + { "logical", no_argument, NULL, 2 }, { NULL, no_argument, NULL, 0 } }; @@ -88,6 +92,10 @@ int main(int argc, char **argv) fs.repair_ = true; break; + case 2: + fs.logical_ = true; + break; + case 'h': usage(cout, basename(argv[0])); return 0; diff --git a/era/metadata_dump.cc b/era/metadata_dump.cc index e7eac5f..0d48ebf 100644 --- a/era/metadata_dump.cc +++ b/era/metadata_dump.cc @@ -39,6 +39,34 @@ namespace { emitter::ptr e_; }; + class writeset_tree_collator : public writeset_tree_detail::writeset_visitor { + public: + writeset_tree_collator(map &exceptions) + : exceptions_(exceptions), + current_era_(0) { + } + + virtual void writeset_begin(uint32_t era, uint32_t nr_bits) { + current_era_ = era; + } + + virtual void bit(uint32_t bit, bool value) { + if (value) { + map::const_iterator it = exceptions_.find(bit); + if (it == exceptions_.end() || it->second < current_era_) + exceptions_.insert(make_pair(bit, current_era_)); + } + } + + virtual void writeset_end() { + } + + private: + map &exceptions_; + uint32_t current_era_; + }; + + struct ignore_writeset_tree_damage : public writeset_tree_detail::damage_visitor { void visit(writeset_tree_detail::missing_eras const &d) { } @@ -61,16 +89,22 @@ namespace { class era_array_emitter : public era_array_visitor { public: - era_array_emitter(emitter::ptr e) - : e_(e) { + era_array_emitter(emitter::ptr e, map const &exceptions) + : e_(e), + exceptions_(exceptions) { } virtual void visit(uint32_t index, uint32_t era) { - e_->era(index, era); + map::const_iterator it = exceptions_.find(index); + if (it != exceptions_.end() && it->second > era) + e_->era(index, it->second); + else + e_->era(index, era); } private: emitter::ptr e_; + map exceptions_; }; struct ignore_era_array_damage : public era_array_detail::damage_visitor { @@ -90,18 +124,9 @@ namespace { raise_metadata_damage(); } }; -} -//---------------------------------------------------------------- - -void -era::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair) -{ - superblock const &sb = md->sb_; - - e->begin_superblock(to_string(sb.uuid), sb.data_block_size, - sb.nr_blocks, - sb.current_era); + void + dump(metadata::ptr md, emitter::ptr e, bool repair) { { writeset_tree_emitter visitor(e); @@ -117,7 +142,8 @@ era::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair) e->begin_era_array(); { - era_array_emitter visitor(e); + map exceptions; + era_array_emitter visitor(e, exceptions); ignore_era_array_damage ignore; fatal_era_array_damage fatal; @@ -129,6 +155,57 @@ era::metadata_dump(metadata::ptr md, emitter::ptr e, bool repair) } e->end_era_array(); } + + void dump_logical(metadata::ptr md, emitter::ptr e, bool repair) + { + // This will potentially use a lot of memory, but I don't + // see a way around it. + map exceptions; + + { + writeset_tree_collator visitor(exceptions); + + ignore_writeset_tree_damage ignore; + fatal_writeset_tree_damage fatal; + writeset_tree_detail::damage_visitor &dv = repair ? + static_cast(ignore) : + static_cast(fatal); + + walk_writeset_tree(md->tm_, *md->writeset_tree_, visitor, dv); + } + + e->begin_era_array(); + { + era_array_emitter visitor(e, exceptions); + + ignore_era_array_damage ignore; + fatal_era_array_damage fatal; + era_array_detail::damage_visitor &dv = repair ? + static_cast(ignore) : + static_cast(fatal); + + walk_era_array(*md->era_array_, visitor, dv); + } + e->end_era_array(); + } +} + +//---------------------------------------------------------------- + +void +era::metadata_dump(metadata::ptr md, emitter::ptr e, + bool repair, bool logical) +{ + superblock const &sb = md->sb_; + e->begin_superblock(to_string(sb.uuid), sb.data_block_size, + sb.nr_blocks, + sb.current_era); + { + if (logical) + dump_logical(md, e, repair); + else + dump(md, e, repair); + } e->end_superblock(); } diff --git a/era/metadata_dump.h b/era/metadata_dump.h index 59d9d67..43cf81f 100644 --- a/era/metadata_dump.h +++ b/era/metadata_dump.h @@ -7,7 +7,8 @@ //---------------------------------------------------------------- namespace era { - void metadata_dump(metadata::ptr md, emitter::ptr out, bool repair); + void metadata_dump(metadata::ptr md, emitter::ptr out, + bool repair, bool logical); } //----------------------------------------------------------------