diff --git a/era/era_invalidate.cc b/era/era_invalidate.cc index c96b286..9e63578 100644 --- a/era/era_invalidate.cc +++ b/era/era_invalidate.cc @@ -4,12 +4,16 @@ #include #include "version.h" +#include "base/indented_stream.h" #include "era/era_array.h" #include "era/writeset_tree.h" #include "era/metadata.h" #include "era/xml_format.h" #include "persistent-data/file_utils.h" +#include + +using namespace boost; using namespace era; using namespace std; @@ -17,14 +21,97 @@ using namespace std; namespace { struct flags { - flags() { + flags() + : metadata_snapshot_(false) { } + + bool metadata_snapshot_; + optional era_threshold_; }; //-------------------------------- - void emit_blocks() { - + void walk_array(era_array const &array, uint32_t nr_blocks, + uint32_t threshold, set &blocks) { + for (uint32_t b = 0; b < nr_blocks; b++) { + uint32_t era = array.get(b); + if (era >= threshold) + blocks.insert(b); + } + } + + class writesets_marked_since : public writeset_tree_detail::writeset_visitor { + public: + writesets_marked_since(uint32_t threshold, set &blocks) + : current_era_(0), + threshold_(threshold), + blocks_(blocks) { + } + + void writeset_begin(uint32_t era, uint32_t nr_bits) { + current_era_ = era; + } + + void bit(uint32_t index, bool value) { + if (value && current_era_ >= threshold_) + blocks_.insert(index); + } + + void writeset_end() { + } + + private: + uint32_t current_era_; + uint32_t threshold_; + set &blocks_; + }; + + void raise_metadata_damage() { + throw std::runtime_error("metadata contains errors (run era_check for details)."); + } + + struct fatal_writeset_tree_damage : public writeset_tree_detail::damage_visitor { + void visit(writeset_tree_detail::missing_eras const &d) { + raise_metadata_damage(); + } + + void visit(writeset_tree_detail::damaged_writeset const &d) { + raise_metadata_damage(); + } + }; + + void walk_writesets(metadata const &md, uint32_t threshold, set &result) { + writesets_marked_since v(threshold, result); + fatal_writeset_tree_damage dv; + + walk_writeset_tree(md.tm_, *md.writeset_tree_, v, dv); + } + + void mark_blocks_since(metadata const &md, uint32_t threshold, set &result) { + walk_array(*md.era_array_, md.sb_.nr_blocks, threshold, result); + walk_writesets(md, threshold, result); + } + + //-------------------------------- + + void emit_blocks(ostream &out, set const &blocks) { + indented_stream o(out); + + o.indent(); + o << "" << endl; + + o.inc(); + { + set::const_iterator it; + for (it = blocks.begin(); it != blocks.end(); ++it) { + o.indent(); + o << "" << endl; + } + } + o.dec(); + + o.indent(); + o << "" << endl; } //-------------------------------- @@ -37,16 +124,28 @@ namespace { int invalidate(string const &dev, string const &output, flags const &fs) { try { + set blocks; block_manager<>::ptr bm = open_bm(dev, block_io<>::READ_ONLY); - metadata::ptr md(new metadata(bm, metadata::OPEN)); - if (want_stdout(output)) { - emitter::ptr e = create_xml_emitter(cout); - //emit_blocks(md, e, fs); + if (fs.metadata_snapshot_) { + superblock sb = read_superblock(bm); + if (!sb.metadata_snap) + throw runtime_error("no metadata snapshot taken."); + + metadata::ptr md(new metadata(bm, *sb.metadata_snap)); + mark_blocks_since(*md, *fs.era_threshold_, blocks); + } else { + metadata::ptr md(new metadata(bm, metadata::OPEN)); + mark_blocks_since(*md, *fs.era_threshold_, blocks); + } + + if (want_stdout(output)) + emit_blocks(cout, blocks); + + else { ofstream out(output.c_str()); - emitter::ptr e = create_xml_emitter(out); - //emit_blocks(md, e, fs); + emit_blocks(out, blocks); } } catch (std::exception &e) { @@ -58,7 +157,7 @@ namespace { } void usage(ostream &out, string const &cmd) { - out << "Usage: " << cmd << " [options] {device|file}" << endl + out << "Usage: " << cmd << " [options] --written-since {device|file}" << endl << "Options:" << endl << " {-h|--help}" << endl << " {-o }" << endl @@ -79,11 +178,21 @@ int main(int argc, char **argv) { "help", no_argument, NULL, 'h' }, { "output", required_argument, NULL, 'o' }, { "version", no_argument, NULL, 'V' }, + { "metadata-snapshot", no_argument, NULL, 1}, + { "written-since", required_argument, NULL, 2}, { NULL, no_argument, NULL, 0 } }; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { + case 1: + fs.metadata_snapshot_ = true; + break; + + case 2: + fs.era_threshold_ = lexical_cast(optarg); + break; + case 'h': usage(cout, basename(argv[0])); return 0; @@ -108,6 +217,12 @@ int main(int argc, char **argv) return 1; } + if (!fs.era_threshold_) { + cerr << "Please specify --written-since" << endl; + usage(cerr, basename(argv[0])); + return 1; + } + return invalidate(argv[optind], output, fs); } diff --git a/era/metadata.cc b/era/metadata.cc index ab2eb7b..baae96a 100644 --- a/era/metadata.cc +++ b/era/metadata.cc @@ -41,11 +41,16 @@ metadata::metadata(block_manager<>::ptr bm, open_type ot) } } +metadata::metadata(block_manager<>::ptr bm, block_address metadata_snap) +{ + open_metadata(bm); +} + void -metadata::open_metadata(block_manager<>::ptr bm) +metadata::open_metadata(block_manager<>::ptr bm, block_address loc) { tm_ = open_tm(bm); - sb_ = read_superblock(tm_->get_bm()); + sb_ = read_superblock(tm_->get_bm(), loc); writeset_tree_ = writeset_tree::ptr(new writeset_tree(tm_, sb_.writeset_tree_root, diff --git a/era/metadata.h b/era/metadata.h index ca31a50..ea3a132 100644 --- a/era/metadata.h +++ b/era/metadata.h @@ -28,6 +28,7 @@ namespace era { typedef boost::shared_ptr ptr; metadata(block_manager<>::ptr bm, open_type ot); + metadata(block_manager<>::ptr bm, block_address metadata_snap); void commit(bool clean_shutdown = true); typedef persistent_data::transaction_manager tm; @@ -38,7 +39,8 @@ namespace era { era_array::ptr era_array_; private: - void open_metadata(block_manager<>::ptr bm); + void open_metadata(block_manager<>::ptr bm, + block_address loc = SUPERBLOCK_LOCATION); }; }; diff --git a/era/superblock.cc b/era/superblock.cc index 0572314..1bd1a4f 100644 --- a/era/superblock.cc +++ b/era/superblock.cc @@ -4,6 +4,7 @@ #include "persistent-data/errors.h" using namespace base; +using namespace boost; using namespace era; using namespace superblock_damage; using namespace persistent_data; @@ -37,6 +38,8 @@ namespace { le64 writeset_tree_root; le64 era_array_root; + le64 metadata_snap; + } __attribute__ ((packed)); struct superblock_traits { @@ -143,6 +146,11 @@ superblock_traits::unpack(disk_type const &disk, value_type &value) era_detail_traits::unpack(disk.current_detail, value.current_detail); value.writeset_tree_root = to_cpu(disk.writeset_tree_root); value.era_array_root = to_cpu(disk.era_array_root); + + block_address ms = to_cpu(disk.metadata_snap); + value.metadata_snap = (ms == SUPERBLOCK_LOCATION) ? + optional() : + optional(ms); } void @@ -163,6 +171,10 @@ superblock_traits::pack(value_type const &value, disk_type &disk) era_detail_traits::pack(value.current_detail, disk.current_detail); disk.writeset_tree_root = to_disk(value.writeset_tree_root); disk.era_array_root = to_disk(value.era_array_root); + + disk.metadata_snap = value.metadata_snap ? + to_disk(*value.metadata_snap) : + to_disk(SUPERBLOCK_LOCATION); } //-------------------------------- diff --git a/era/superblock.h b/era/superblock.h index 346582e..bea7af1 100644 --- a/era/superblock.h +++ b/era/superblock.h @@ -3,6 +3,7 @@ #include "persistent-data/block.h" #include "era/era_detail.h" +#include #include @@ -63,6 +64,8 @@ namespace era { // Big array holding the digested era/block info. uint64_t era_array_root; + + boost::optional metadata_snap; }; //--------------------------------