era_invalidate

This commit is contained in:
Joe Thornber 2014-01-31 16:31:27 +00:00
parent 344f4b1e08
commit d3afa57082
5 changed files with 150 additions and 13 deletions

View File

@ -4,12 +4,16 @@
#include <iostream>
#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 <boost/lexical_cast.hpp>
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<uint32_t> era_threshold_;
};
//--------------------------------
void emit_blocks() {
void walk_array(era_array const &array, uint32_t nr_blocks,
uint32_t threshold, set<uint32_t> &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<uint32_t> &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<uint32_t> &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<uint32_t> &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<uint32_t> &result) {
walk_array(*md.era_array_, md.sb_.nr_blocks, threshold, result);
walk_writesets(md, threshold, result);
}
//--------------------------------
void emit_blocks(ostream &out, set<uint32_t> const &blocks) {
indented_stream o(out);
o.indent();
o << "<blocks>" << endl;
o.inc();
{
set<uint32_t>::const_iterator it;
for (it = blocks.begin(); it != blocks.end(); ++it) {
o.indent();
o << "<block block=\"" << *it << "\"/>" << endl;
}
}
o.dec();
o.indent();
o << "</blocks>" << endl;
}
//--------------------------------
@ -37,16 +124,28 @@ namespace {
int invalidate(string const &dev, string const &output, flags const &fs) {
try {
set<uint32_t> 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 <era> {device|file}" << endl
<< "Options:" << endl
<< " {-h|--help}" << endl
<< " {-o <xml file>}" << 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<uint32_t>(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);
}

View File

@ -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,

View File

@ -28,6 +28,7 @@ namespace era {
typedef boost::shared_ptr<metadata> 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);
};
};

View File

@ -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<uint64_t>(disk.writeset_tree_root);
value.era_array_root = to_cpu<uint64_t>(disk.era_array_root);
block_address ms = to_cpu<uint64_t>(disk.metadata_snap);
value.metadata_snap = (ms == SUPERBLOCK_LOCATION) ?
optional<block_address>() :
optional<block_address>(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<le64>(value.writeset_tree_root);
disk.era_array_root = to_disk<le64>(value.era_array_root);
disk.metadata_snap = value.metadata_snap ?
to_disk<le64>(*value.metadata_snap) :
to_disk<le64>(SUPERBLOCK_LOCATION);
}
//--------------------------------

View File

@ -3,6 +3,7 @@
#include "persistent-data/block.h"
#include "era/era_detail.h"
#include <boost/optional.hpp>
#include <set>
@ -63,6 +64,8 @@ namespace era {
// Big array holding the digested era/block info.
uint64_t era_array_root;
boost::optional<persistent_data::block_address> metadata_snap;
};
//--------------------------------