diff --git a/Makefile.in b/Makefile.in index ab9837c..8d0d53a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -63,6 +63,7 @@ SOURCE=\ era/writeset_tree.cc \ era/metadata.cc \ era/metadata_dump.cc \ + era/restore_emitter.cc \ era/xml_format.cc \ \ persistent-data/checksum.cc \ @@ -443,7 +444,42 @@ ERA_INVALIDATE_SOURCE=\ ERA_INVALIDATE_OBJECTS=$(subst .cc,.o,$(ERA_INVALIDATE_SOURCE)) -era_invalidate: $(ERA_INVALIDATE_OBJECTS) era/era_invalidate.o +era_invalidate: $(ERA_INVALIDATE_OBJECTS) era/era_invalidate.o + @echo " [LD] $@" + $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) + +ERA_RESTORE_SOURCE=\ + block-cache/block_cache.cc \ + \ + base/base64.cc \ + base/error_state.cc \ + base/endian_utils.cc \ + base/xml_utils.cc \ + \ + era/writeset_tree.cc \ + era/era_detail.cc \ + era/era_array.cc \ + era/metadata.cc \ + era/metadata_dump.cc \ + era/restore_emitter.cc \ + era/superblock.cc \ + era/xml_format.cc \ + \ + persistent-data/checksum.cc \ + persistent-data/error_set.cc \ + persistent-data/file_utils.cc \ + persistent-data/hex_dump.cc \ + persistent-data/data-structures/btree.cc \ + persistent-data/data-structures/bitset.cc \ + persistent-data/space_map.cc \ + persistent-data/space-maps/disk.cc \ + persistent-data/space-maps/recursive.cc \ + persistent-data/space-maps/careful_alloc.cc \ + persistent-data/transaction_manager.cc \ + +ERA_RESTORE_OBJECTS=$(subst .cc,.o,$(ERA_RESTORE_SOURCE)) + +era_restore: $(ERA_RESTORE_OBJECTS) era/era_restore.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(LIBEXPAT) diff --git a/era/era_detail.h b/era/era_detail.h index 4269afd..80961d5 100644 --- a/era/era_detail.h +++ b/era/era_detail.h @@ -22,16 +22,22 @@ namespace era { uint64_t writeset_root; }; - // FIXME: implement struct era_detail_ref_counter { - era_detail_ref_counter(persistent_data::transaction_manager::ptr tm) { + era_detail_ref_counter(persistent_data::transaction_manager::ptr tm) + : tm_(tm) { } - void inc(persistent_data::block_address b) { + void inc(era_detail const &d) { + tm_->get_sm()->inc(d.writeset_root); } void dec(persistent_data::block_address b) { + // I don't think we ever do this in the tools + throw std::runtime_error("not implemented"); } + + private: + persistent_data::transaction_manager::ptr tm_; }; struct era_detail_traits { diff --git a/era/era_restore.cc b/era/era_restore.cc new file mode 100644 index 0000000..56618ac --- /dev/null +++ b/era/era_restore.cc @@ -0,0 +1,115 @@ +#include "version.h" + +#include "era/metadata.h" +#include "era/restore_emitter.h" +#include "era/xml_format.h" +#include "persistent-data/file_utils.h" + +#include +#include +#include +#include +#include +#include + +using namespace boost; +using namespace caching; +using namespace persistent_data; +using namespace std; + +//---------------------------------------------------------------- + +namespace { + struct flags { + optional input; + optional output; + }; + + int restore(flags const &fs) { + try { + block_manager<>::ptr bm = open_bm(*fs.output, block_manager<>::READ_WRITE); + metadata::ptr md(new metadata(bm, metadata::CREATE)); + emitter::ptr restorer = create_restore_emitter(md); + + check_file_exists(*fs.input); + ifstream in(fs.input->c_str(), ifstream::in); + parse_xml(in, restorer); + + } catch (std::exception &e) { + cerr << e.what() << endl; + return 1; + } + + return 0; + } + + void usage(ostream &out, string const &cmd) { + out << "Usage: " << cmd << " [options]" << endl + << "Options:" << endl + << " {-h|--help}" << endl + << " {-i|--input} " << endl + << " {-o|--output} " << endl + << " {-V|--version}" << endl + << endl; + } +} + +int main(int argc, char **argv) +{ + int c; + flags fs; + char const *prog_name = basename(argv[0]); + char const *short_opts = "hi:o:V"; + option const long_opts[] = { + { "help", no_argument, NULL, 'h'}, + { "input", required_argument, NULL, 'i' }, + { "output", required_argument, NULL, 'o'}, + { "version", no_argument, NULL, 'V'}, + { NULL, no_argument, NULL, 0 } + }; + + while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { + switch(c) { + case 'h': + usage(cout, prog_name); + return 0; + + case 'i': + fs.input = optional(string(optarg)); + break; + + case 'o': + fs.output = optional(string(optarg)); + break; + + case 'V': + cout << THIN_PROVISIONING_TOOLS_VERSION << endl; + return 0; + + default: + usage(cerr, prog_name); + return 1; + } + } + + if (argc != optind) { + usage(cerr, prog_name); + return 1; + } + + if (!fs.input) { + cerr << "No input file provided." << endl << endl; + usage(cerr, prog_name); + return 1; + } + + if (!fs.output) { + cerr << "No output file provided." << endl << endl; + usage(cerr, prog_name); + return 1; + } + + return restore(fs); +} + +//---------------------------------------------------------------- diff --git a/era/metadata.cc b/era/metadata.cc index d344b6c..d3535d8 100644 --- a/era/metadata.cc +++ b/era/metadata.cc @@ -53,4 +53,38 @@ metadata::open_metadata(block_manager<>::ptr bm, block_address loc) sb_.nr_blocks)); } +void +metadata::commit() +{ + commit_space_map(); + commit_writesets(); + commit_era_array(); + commit_superblock(); +} + +void +metadata::commit_space_map() +{ + metadata_sm_->commit(); + metadata_sm_->copy_root(&sb_.metadata_space_map_root, sizeof(sb_.metadata_space_map_root)); +} + +void +metadata::commit_writesets() +{ + sb_.writeset_tree_root = writeset_tree_->get_root(); +} + +void +metadata::commit_era_array() +{ + sb_.era_array_root = era_array_->get_root(); +} + +void +metadata::commit_superblock() +{ + write_superblock(tm_->get_bm(), sb_); +} + //---------------------------------------------------------------- diff --git a/era/metadata.h b/era/metadata.h index ea3a132..a88a1e9 100644 --- a/era/metadata.h +++ b/era/metadata.h @@ -29,7 +29,7 @@ namespace era { metadata(block_manager<>::ptr bm, open_type ot); metadata(block_manager<>::ptr bm, block_address metadata_snap); - void commit(bool clean_shutdown = true); + void commit(); typedef persistent_data::transaction_manager tm; tm::ptr tm_; @@ -41,6 +41,11 @@ namespace era { private: void open_metadata(block_manager<>::ptr bm, block_address loc = SUPERBLOCK_LOCATION); + + void commit_space_map(); + void commit_writesets(); + void commit_era_array(); + void commit_superblock(); }; }; diff --git a/era/restore_emitter.cc b/era/restore_emitter.cc new file mode 100644 index 0000000..aba16c0 --- /dev/null +++ b/era/restore_emitter.cc @@ -0,0 +1,107 @@ +#include "era/restore_emitter.h" + +#include "era/superblock.h" + +using namespace era; +using namespace persistent_data; + +//---------------------------------------------------------------- + +namespace { + class restorer : public emitter { + public: + restorer(metadata &md) + : md_(md), + in_superblock_(false), + in_writeset_(false), + in_era_array_(false) { + } + + virtual void begin_superblock(std::string const &uuid, + uint32_t data_block_size, + pd::block_address nr_blocks, + uint32_t current_era) { + superblock &sb = md_.sb_; + memcpy(sb.uuid, reinterpret_cast<__u8 const *>(uuid.c_str()), + min(sizeof(sb.uuid), uuid.length())); + sb.data_block_size = data_block_size; + sb.nr_blocks = nr_blocks; + sb.current_era = current_era; + + nr_blocks = nr_blocks; + } + + virtual void end_superblock() { + if (!in_superblock_) + throw runtime_error("missing superblock"); + + md_.commit(); + } + + virtual void begin_writeset(uint32_t era, uint32_t nr_bits) { + if (!in_superblock_) + throw runtime_error("missing superblock"); + + in_writeset_ = true; + era_ = era; + + bits_.reset(new bitset(md_.tm_)); + bits_->grow(nr_bits, false); + } + + virtual void writeset_bit(uint32_t bit, bool value) { + bits_->set(bit, value); + } + + virtual void end_writeset() { + in_writeset_ = false; + + era_detail e; + e.nr_bits = bits_->get_nr_bits(); + e.writeset_root = bits_->get_root(); + + uint64_t key[1] = {era_}; + md_.writeset_tree_->insert(key, e); + } + + virtual void begin_era_array() { + if (!in_superblock_) + throw runtime_error("missing superblock"); + + in_era_array_ = true; + } + + virtual void era(pd::block_address block, uint32_t era) { + if (!in_era_array_) + throw runtime_error("missing era array"); + + md_.era_array_->set(block, era); + } + + virtual void end_era_array() { + in_era_array_ = false; + } + + private: + metadata &md_; + + bool in_superblock_; + + bool in_writeset_; + uint32_t era_; + pd::bitset::ptr bits_; + + bool in_era_array_; + uint32_t nr_blocks_; + }; +} + +//---------------------------------------------------------------- + +emitter::ptr +era::create_restore_emitter(metadata &md) +{ + return emitter::ptr(new restorer(md)); +} + +//---------------------------------------------------------------- diff --git a/era/restore_emitter.h b/era/restore_emitter.h new file mode 100644 index 0000000..3c907bc --- /dev/null +++ b/era/restore_emitter.h @@ -0,0 +1,15 @@ +#ifndef ERA_RESTORE_EMITTER_H +#define ERA_RESTORE_EMITTER_H + +#include "era/emitter.h" +#include "era/metadata.h" + +//---------------------------------------------------------------- + +namespace era { + emitter::ptr create_restore_emitter(metadata &md); +} + +//---------------------------------------------------------------- + +#endif diff --git a/era/superblock.h b/era/superblock.h index bea7af1..408039d 100644 --- a/era/superblock.h +++ b/era/superblock.h @@ -1,5 +1,5 @@ #ifndef ERA_SUPERBLOCK_H -#define ERA_SUPERBLOCK_h +#define ERA_SUPERBLOCK_H #include "persistent-data/block.h" #include "era/era_detail.h"