WIP on cache tools
This commit is contained in:
@@ -1,18 +1,41 @@
|
||||
#include <fstream>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "version.h"
|
||||
#include "caching/xml_format.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace caching;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
string const STDOUT_PATH("-");
|
||||
|
||||
bool want_stdout(string const &output) {
|
||||
return output == STDOUT_PATH;
|
||||
}
|
||||
|
||||
int dump_(string const &dev, ostream &out) {
|
||||
emitter::ptr e = create_xml_emitter(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dump(string const &dev, string const &output) {
|
||||
if (want_stdout(output)) {
|
||||
ofstream out(output.c_str());
|
||||
return dump_(dev, out);
|
||||
} else
|
||||
return dump_(dev, cout);
|
||||
}
|
||||
|
||||
void usage(ostream &out, string const &cmd) {
|
||||
out << "Usage: " << cmd << " [options] {device|file}" << endl
|
||||
<< "Options:" << endl
|
||||
<< " {-h|--help}" << endl
|
||||
<< " {-o <xml file>}" << endl
|
||||
<< " {-V|--version}" << endl;
|
||||
}
|
||||
}
|
||||
@@ -22,10 +45,12 @@ namespace {
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
char const shortopts[] = "hV";
|
||||
string output("-");
|
||||
char const shortopts[] = "ho:V";
|
||||
|
||||
option const longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "output", required_argument, NULL, 'o'},
|
||||
{ "version", no_argument, NULL, 'V'},
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
@@ -36,6 +61,10 @@ int main(int argc, char **argv)
|
||||
usage(cout, basename(argv[0]));
|
||||
return 0;
|
||||
|
||||
case 'o':
|
||||
output = optarg;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
|
||||
return 0;
|
||||
@@ -46,15 +75,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (argc == optind) {
|
||||
cerr << "No input file provided." << endl;
|
||||
usage(cerr, basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return dump(argv[optind], output);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
@@ -1,15 +1,50 @@
|
||||
#include "version.h"
|
||||
|
||||
#include "caching/metadata.h"
|
||||
#include "caching/xml_format.h"
|
||||
#include "persistent-data/file_utils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <libgen.h>
|
||||
#include <string>
|
||||
|
||||
using namespace caching;
|
||||
using namespace persistent_data;
|
||||
using namespace std;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
void check_file_exists(string const &file) {
|
||||
struct stat info;
|
||||
int r = ::stat(file.c_str(), &info);
|
||||
if (r)
|
||||
throw runtime_error("Couldn't stat file");
|
||||
|
||||
if (!S_ISREG(info.st_mode))
|
||||
throw runtime_error("Not a regular file");
|
||||
}
|
||||
|
||||
int restore(string const &xml_file, string const &dev) {
|
||||
try {
|
||||
block_manager<>::ptr bm = open_bm(dev, block_io<>::READ_ONLY);
|
||||
metadata::ptr md(new metadata(bm, metadata::CREATE));
|
||||
emitter::ptr restorer = create_restore_emitter(md);
|
||||
|
||||
check_file_exists(xml_file);
|
||||
ifstream in(xml_file.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
|
||||
@@ -75,7 +110,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return restore(input, output);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
44
caching/emitter.h
Normal file
44
caching/emitter.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef CACHE_EMITTER_H
|
||||
#define CACHE_EMITTER_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "persistent-data/block.h"
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace caching {
|
||||
namespace pd = persistent_data;
|
||||
|
||||
class emitter {
|
||||
public:
|
||||
typedef boost::shared_ptr<emitter> ptr;
|
||||
|
||||
virtual ~emitter() {}
|
||||
|
||||
virtual void begin_superblock(std::string const &uuid,
|
||||
pd::block_address block_size,
|
||||
pd::block_address nr_cache_blocks,
|
||||
std::string const &policy) = 0;
|
||||
|
||||
virtual void end_superblock() = 0;
|
||||
|
||||
virtual void begin_mappings() = 0;
|
||||
virtual void end_mappings() = 0;
|
||||
|
||||
virtual void mapping(pd::block_address cblock,
|
||||
pd::block_address oblock,
|
||||
bool dirty) = 0;
|
||||
|
||||
virtual void begin_hints() = 0;
|
||||
virtual void end_hints() = 0;
|
||||
|
||||
virtual void hint(pd::block_address cblock,
|
||||
std::string const &data) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
17
caching/metadata.cc
Normal file
17
caching/metadata.cc
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "caching/metadata.h"
|
||||
|
||||
using namespace caching;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
metadata::metadata(block_manager<>::ptr bm, open_type ot)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
metadata::metadata(block_manager<>::ptr bm, block_address metadata_snap)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
33
caching/metadata.h
Normal file
33
caching/metadata.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef CACHE_METADATA_H
|
||||
#define CACHE_METADATA_H
|
||||
|
||||
#include "persistent-data/block.h"
|
||||
#include "persistent-data/data-structures/array.h"
|
||||
#include "persistent-data/endian_utils.h"
|
||||
#include "persistent-data/space-maps/disk.h"
|
||||
#include "persistent-data/transaction_manager.h"
|
||||
|
||||
#include "caching/superblock.h"
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace caching {
|
||||
class metadata {
|
||||
public:
|
||||
enum open_type {
|
||||
CREATE,
|
||||
OPEN
|
||||
};
|
||||
|
||||
typedef block_manager<>::read_ref read_ref;
|
||||
typedef block_manager<>::write_ref write_ref;
|
||||
typedef boost::shared_ptr<metadata> ptr;
|
||||
|
||||
metadata(block_manager<>::ptr bm, open_type ot);
|
||||
metadata(block_manager<>::ptr bm, block_address metadata_snap);
|
||||
};
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
279
caching/xml_format.cc
Normal file
279
caching/xml_format.cc
Normal file
@@ -0,0 +1,279 @@
|
||||
#include "caching/xml_format.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <expat.h>
|
||||
|
||||
using namespace boost;
|
||||
using namespace caching;
|
||||
using namespace persistent_data;
|
||||
using namespace std;
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
// base64 encoding?
|
||||
string encode(string const &data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
string decode(string const &data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// Emitter
|
||||
//--------------------------------
|
||||
class xml_emitter : public emitter {
|
||||
public:
|
||||
xml_emitter(ostream &out)
|
||||
: out_(out),
|
||||
indent_(0) {
|
||||
}
|
||||
|
||||
void begin_superblock(std::string const &uuid,
|
||||
block_address block_size,
|
||||
block_address nr_cache_blocks,
|
||||
std::string const &policy) {
|
||||
indent();
|
||||
out_ << "<superblock uuid=\"" << uuid << "\""
|
||||
<< " block_size=\"" << block_size << "\""
|
||||
<< " nr_cache_blocks=\"" << nr_cache_blocks << "\""
|
||||
<< " policy=\"" << policy << "\">" << endl;
|
||||
inc();
|
||||
}
|
||||
|
||||
virtual void end_superblock() {
|
||||
dec();
|
||||
indent();
|
||||
out_ << "</superblock>" << endl;
|
||||
}
|
||||
|
||||
virtual void begin_mappings() {
|
||||
indent();
|
||||
out_ << "<mappings>" << endl;
|
||||
inc();
|
||||
}
|
||||
|
||||
virtual void end_mappings() {
|
||||
dec();
|
||||
indent();
|
||||
out_ << "</mappings>" << endl;
|
||||
}
|
||||
|
||||
virtual void mapping(block_address cblock,
|
||||
block_address oblock,
|
||||
bool dirty) {
|
||||
indent();
|
||||
out_ << "<mapping"
|
||||
<< " cache_block=\"" << cblock << "\""
|
||||
<< " origin_block=\"" << oblock << "\""
|
||||
<< " dirty=\"" << as_truth(dirty) << "\""
|
||||
<< "/>" << endl;
|
||||
}
|
||||
|
||||
virtual void begin_hints() {
|
||||
indent();
|
||||
out_ << "<hints>" << endl;
|
||||
inc();
|
||||
}
|
||||
|
||||
virtual void end_hints() {
|
||||
dec();
|
||||
indent();
|
||||
out_ << "</hints>" << endl;
|
||||
}
|
||||
|
||||
virtual void hint(block_address cblock,
|
||||
std::string const &data) {
|
||||
out_ << "<hint"
|
||||
<< " cache_block=\"" << cblock << "\""
|
||||
<< " data=\"" << encode(data) << "\""
|
||||
<< ">" << endl;
|
||||
}
|
||||
|
||||
private:
|
||||
string as_truth(bool v) const {
|
||||
return v ? "true" : "false";
|
||||
}
|
||||
|
||||
// FIXME: factor out a common class with the thin_provisioning emitter
|
||||
void indent() {
|
||||
for (unsigned i = 0; i < indent_ * 2; i++)
|
||||
out_ << ' ';
|
||||
}
|
||||
|
||||
void inc() {
|
||||
indent_++;
|
||||
}
|
||||
|
||||
void dec() {
|
||||
indent_--;
|
||||
}
|
||||
|
||||
ostream &out_;
|
||||
unsigned indent_;
|
||||
};
|
||||
|
||||
//--------------------------------
|
||||
// Parser
|
||||
//--------------------------------
|
||||
|
||||
// FIXME: factor out common code with thinp one
|
||||
typedef std::map<string, string> attributes;
|
||||
|
||||
void build_attributes(attributes &a, char const **attr) {
|
||||
while (*attr) {
|
||||
char const *key = *attr;
|
||||
|
||||
attr++;
|
||||
if (!*attr) {
|
||||
ostringstream out;
|
||||
out << "No value given for xml attribute: " << key;
|
||||
throw runtime_error(out.str());
|
||||
}
|
||||
|
||||
char const *value = *attr;
|
||||
a.insert(make_pair(string(key), string(value)));
|
||||
attr++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get_attr(attributes const &attr, string const &key) {
|
||||
attributes::const_iterator it = attr.find(key);
|
||||
if (it == attr.end()) {
|
||||
ostringstream out;
|
||||
out << "could not find attribute: " << key;
|
||||
throw runtime_error(out.str());
|
||||
}
|
||||
|
||||
return boost::lexical_cast<T>(it->second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::optional<T> get_opt_attr(attributes const &attr, string const &key) {
|
||||
typedef boost::optional<T> rtype;
|
||||
attributes::const_iterator it = attr.find(key);
|
||||
if (it == attr.end())
|
||||
return rtype();
|
||||
|
||||
return rtype(boost::lexical_cast<T>(it->second));
|
||||
}
|
||||
|
||||
void parse_superblock(emitter *e, attributes const &attr) {
|
||||
e->begin_superblock(get_attr<string>(attr, "uuid"),
|
||||
get_attr<uint64_t>(attr, "block_size"),
|
||||
get_attr<uint64_t>(attr, "nr_cache_blocks"),
|
||||
get_attr<string>(attr, "policy"));
|
||||
}
|
||||
|
||||
bool to_bool(string const &str) {
|
||||
if (str == "true")
|
||||
return true;
|
||||
|
||||
else if (str == "false")
|
||||
return false;
|
||||
|
||||
throw runtime_error("bad boolean value");
|
||||
}
|
||||
|
||||
void parse_mapping(emitter *e, attributes const &attr) {
|
||||
e->mapping(get_attr<uint64_t>(attr, "cache_block"),
|
||||
get_attr<uint64_t>(attr, "origin_block"),
|
||||
to_bool(get_attr<string>(attr, "dirty")));
|
||||
}
|
||||
|
||||
void parse_hint(emitter *e, attributes const &attr) {
|
||||
e->hint(get_attr<uint64_t>(attr, "cache_block"),
|
||||
decode(get_attr<string>(attr, "data")));
|
||||
}
|
||||
|
||||
void start_tag(void *data, char const *el, char const **attr) {
|
||||
emitter *e = static_cast<emitter *>(data);
|
||||
attributes a;
|
||||
|
||||
build_attributes(a, attr);
|
||||
|
||||
if (!strcmp(el, "superblock"))
|
||||
parse_superblock(e, a);
|
||||
|
||||
else if (!strcmp(el, "mappings"))
|
||||
e->begin_mappings();
|
||||
|
||||
else if (!strcmp(el, "mapping"))
|
||||
parse_mapping(e, a);
|
||||
|
||||
else if (!strcmp(el, "hints"))
|
||||
e->begin_hints();
|
||||
|
||||
else if (!strcmp(el, "hint"))
|
||||
parse_hint(e, a);
|
||||
|
||||
else
|
||||
throw runtime_error("unknown tag type");
|
||||
}
|
||||
|
||||
void end_tag(void *data, const char *el) {
|
||||
emitter *e = static_cast<emitter *>(data);
|
||||
|
||||
if (!strcmp(el, "superblock"))
|
||||
e->end_superblock();
|
||||
|
||||
else if (!strcmp(el, "mappings"))
|
||||
e->end_mappings();
|
||||
|
||||
else if (!strcmp(el, "mapping"))
|
||||
// do nothing
|
||||
;
|
||||
|
||||
else if (!strcmp(el, "hints"))
|
||||
e->end_hints();
|
||||
|
||||
else if (!strcmp(el, "hint"))
|
||||
// do nothing
|
||||
;
|
||||
|
||||
else
|
||||
throw runtime_error("unknown tag close");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
caching::emitter::ptr
|
||||
caching::create_xml_emitter(ostream &out)
|
||||
{
|
||||
return emitter::ptr(new xml_emitter(out));
|
||||
}
|
||||
|
||||
void
|
||||
caching::parse_xml(istream &in, emitter::ptr e)
|
||||
{
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
if (!parser)
|
||||
throw runtime_error("couldn't create xml parser");
|
||||
|
||||
XML_SetUserData(parser, e.get());
|
||||
XML_SetElementHandler(parser, start_tag, end_tag);
|
||||
|
||||
while (!in.eof()) {
|
||||
char buffer[4096];
|
||||
in.read(buffer, sizeof(buffer));
|
||||
size_t len = in.gcount();
|
||||
int done = in.eof();
|
||||
|
||||
if (!XML_Parse(parser, buffer, len, done)) {
|
||||
ostringstream out;
|
||||
out << "Parse error at line "
|
||||
<< XML_GetCurrentLineNumber(parser)
|
||||
<< ":\n"
|
||||
<< XML_ErrorString(XML_GetErrorCode(parser))
|
||||
<< endl;
|
||||
throw runtime_error(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
17
caching/xml_format.h
Normal file
17
caching/xml_format.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CACHE_XML_FORMAT_H
|
||||
#define CACHE_XML_FORMAT_H
|
||||
|
||||
#include "emitter.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace caching {
|
||||
emitter::ptr create_xml_emitter(std::ostream &out);
|
||||
void parse_xml(std::istream &in, emitter::ptr e);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user