From b9b04dc872fadcf89eaee6211c698188bf8d30ba Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Thu, 21 Jan 2021 16:05:28 +0800 Subject: [PATCH] [thin_debug] Factor out reusable componments --- Makefile.in | 2 + base/command_interpreter.cc | 44 ++++++++ base/command_interpreter.h | 60 +++++++++++ base/output_formatter.cc | 53 ++++++++++ base/output_formatter.h | 59 +++++++++++ thin-provisioning/thin_debug.cc | 181 +++----------------------------- 6 files changed, 231 insertions(+), 168 deletions(-) create mode 100644 base/command_interpreter.cc create mode 100644 base/command_interpreter.h create mode 100644 base/output_formatter.cc create mode 100644 base/output_formatter.h diff --git a/Makefile.in b/Makefile.in index c70159d..ae7ebcd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -126,6 +126,8 @@ TOOLS_SOURCE=\ thin-provisioning/thin_trim.cc DEVTOOLS_SOURCE=\ + base/command_interpreter.cc \ + base/output_formatter.cc \ caching/devel_commands.cc \ era/devel_commands.cc \ thin-provisioning/damage_generator.cc \ diff --git a/base/command_interpreter.cc b/base/command_interpreter.cc new file mode 100644 index 0000000..e2e4e82 --- /dev/null +++ b/base/command_interpreter.cc @@ -0,0 +1,44 @@ +#include "base/command_interpreter.h" + +using namespace dbg; +using namespace std; + +//---------------------------------------------------------------- + +namespace { + strings read_input(std::istream &in) { + using namespace boost::algorithm; + + std::string input; + getline(in, input); + + strings toks; + split(toks, input, is_any_of(" \t"), token_compress_on); + + return toks; + } +} + +//---------------------------------------------------------------- + +void command_interpreter::do_once() { + if (in_.eof()) + throw runtime_error("input closed"); + + out_ << "> "; + strings args = read_input(in_); + + std::map::iterator it; + it = commands_.find(args[0]); + if (it == commands_.end()) + out_ << "Unrecognised command" << endl; + else { + try { + it->second->exec(args, out_); + } catch (std::exception &e) { + cerr << e.what() << endl; + } + } +} + +//---------------------------------------------------------------- diff --git a/base/command_interpreter.h b/base/command_interpreter.h new file mode 100644 index 0000000..0b4abca --- /dev/null +++ b/base/command_interpreter.h @@ -0,0 +1,60 @@ +#ifndef DBG_COMMAND_INTERPRETER +#define DBG_COMMAND_INTERPRETER + +#include +#include + +#include +#include +#include +#include + +//---------------------------------------------------------------- + +namespace dbg { + typedef std::vector strings; + + class command { + public: + typedef std::shared_ptr ptr; + + virtual ~command() {} + virtual void exec(strings const &args, std::ostream &out) = 0; + }; + + class command_interpreter { + public: + typedef std::shared_ptr ptr; + + command_interpreter(std::istream &in, std::ostream &out) + : in_(in), + out_(out), + exit_(false) { + } + + void register_command(std::string const &str, command::ptr cmd) { + commands_.insert(make_pair(str, cmd)); + } + + void enter_main_loop() { + while (!exit_) + do_once(); + } + + void exit_main_loop() { + exit_ = true; + } + + private: + void do_once(); + + std::istream &in_; + std::ostream &out_; + std::map commands_; + bool exit_; + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/base/output_formatter.cc b/base/output_formatter.cc new file mode 100644 index 0000000..54ef578 --- /dev/null +++ b/base/output_formatter.cc @@ -0,0 +1,53 @@ +#include + +#include "base/output_formatter.h" + +using namespace dbg; +using namespace std; + +//---------------------------------------------------------------- + +namespace { + void indent(int depth, std::ostream &out) { + for (int i = 0; i < depth * 2; i++) + out << ' '; + } +} + +//---------------------------------------------------------------- + +void xml_formatter::output(std::ostream &out, + int depth, + boost::optional name) { + indent(depth, out); + out << "::const_iterator it; + for (it = fields_.begin(); it != fields_.end(); ++it) { + if (string const *s = boost::get(&it->get<1>())) { + out << " " << it->get<0>() << "=\"" << *s << "\""; + } + } + + if (children_.size() == 0) { + out << " />" << endl; + return; + } + + /* output child fields */ + out << ">" << endl; + for (it = children_.begin(); it != children_.end(); ++it) { + if (!boost::get(&it->get<1>())) { + formatter::ptr f = boost::get(it->get<1>()); + f->output(out, depth + 1, it->get<0>()); + } + } + + indent(depth, out); + out << "" << endl; +} + +//---------------------------------------------------------------- diff --git a/base/output_formatter.h b/base/output_formatter.h new file mode 100644 index 0000000..2299f9d --- /dev/null +++ b/base/output_formatter.h @@ -0,0 +1,59 @@ +#ifndef DBG_OUTPUT_FORMATTER_H +#define DBG_OUTPUT_FORMATTER_H + +#include +#include +#include +#include + +#include +#include + +//---------------------------------------------------------------- + +namespace dbg { + class formatter { + public: + typedef std::shared_ptr ptr; + + virtual ~formatter() {} + + typedef boost::optional maybe_string; + + void field(std::string const &name, std::string const &value) { + fields_.push_back(field_type(name, value)); + } + + void child(std::string const &name, formatter::ptr t) { + children_.push_back(field_type(name, t)); + } + + virtual void output(std::ostream &out, int depth = 0, + boost::optional name = boost::none) = 0; + + protected: + typedef boost::variant value; + typedef boost::tuple field_type; + + std::vector fields_; + std::vector children_; + }; + + template + void + field(formatter &t, std::string const &name, T const &value) { + t.field(name, boost::lexical_cast(value)); + } + + //-------------------------------- + + class xml_formatter : public formatter { + public: + virtual void output(std::ostream &out, int depth = 0, + boost::optional name = boost::none); + }; +} + +//---------------------------------------------------------------- + +#endif diff --git a/thin-provisioning/thin_debug.cc b/thin-provisioning/thin_debug.cc index ea3541c..a48b79f 100644 --- a/thin-provisioning/thin_debug.cc +++ b/thin-provisioning/thin_debug.cc @@ -16,193 +16,36 @@ // with thin-provisioning-tools. If not, see // . -#include -#include #include -#include -#include #include #include -#include -#include #include -#include +#include "base/command_interpreter.h" #include "base/math_utils.h" +#include "base/output_formatter.h" #include "persistent-data/data-structures/btree.h" #include "persistent-data/data-structures/simple_traits.h" #include "persistent-data/file_utils.h" #include "persistent-data/space-maps/disk_structures.h" #include "thin-provisioning/commands.h" #include "thin-provisioning/metadata.h" -#include "thin-provisioning/metadata_checker.h" #include "thin-provisioning/superblock.h" #include "version.h" +using namespace dbg; using namespace persistent_data; using namespace std; using namespace thin_provisioning; namespace { - typedef vector strings; - - class formatter { - public: - typedef std::shared_ptr ptr; - - virtual ~formatter() {} - - typedef boost::optional maybe_string; - - void field(string const &name, string const &value) { - fields_.push_back(field_type(name, value)); - } - - void child(string const &name, formatter::ptr t) { - children_.push_back(field_type(name, t)); - } - - virtual void output(ostream &out, int depth = 0, boost::optional name = boost::none) = 0; - - protected: - typedef boost::variant value; - typedef boost::tuple field_type; - - vector fields_; - vector children_; - }; - - template - void - field(formatter &t, string const &name, T const &value) { - t.field(name, boost::lexical_cast(value)); - } - - //-------------------------------- - - class xml_formatter : public formatter { - public: - virtual void output(ostream &out, int depth, boost::optional name = boost::none) { - indent(depth, out); - out << "::const_iterator it; - for (it = fields_.begin(); it != fields_.end(); ++it) { - if (string const *s = boost::get(&it->get<1>())) { - out << " " << it->get<0>() << "=\"" << *s << "\""; - } - } - - if (children_.size() == 0) { - out << " />" << endl; - return; - } - - /* output child fields */ - out << ">" << endl; - for (it = children_.begin(); it != children_.end(); ++it) { - if (!boost::get(&it->get<1>())) { - formatter::ptr f = boost::get(it->get<1>()); - f->output(out, depth + 1, it->get<0>()); - } - } - - indent(depth, out); - out << "" << endl; - } - - - private: - void indent(int depth, ostream &out) const { - for (int i = 0; i < depth * 2; i++) - out << ' '; - } - }; - - //-------------------------------- - - class command { - public: - typedef std::shared_ptr ptr; - - virtual ~command() {} - virtual void exec(strings const &args, ostream &out) = 0; - }; - - class command_interpreter { - public: - typedef std::shared_ptr ptr; - - command_interpreter(istream &in, ostream &out) - : in_(in), - out_(out), - exit_(false) { - } - - void register_command(string const &str, command::ptr cmd) { - commands_.insert(make_pair(str, cmd)); - } - - void enter_main_loop() { - while (!exit_) - do_once(); - } - - void exit_main_loop() { - exit_ = true; - } - - private: - strings read_input() { - using namespace boost::algorithm; - - string input; - getline(in_, input); - - strings toks; - split(toks, input, is_any_of(" \t"), token_compress_on); - - return toks; - } - - void do_once() { - if (in_.eof()) - throw runtime_error("input closed"); - - out_ << "> "; - strings args = read_input(); - - map::iterator it; - it = commands_.find(args[0]); - if (it == commands_.end()) - out_ << "Unrecognised command" << endl; - else { - try { - it->second->exec(args, out_); - } catch (std::exception &e) { - cerr << e.what() << endl; - } - } - } - - istream &in_; - ostream &out_; - map commands_; - bool exit_; - }; - - //-------------------------------- - - class hello : public command { + class hello : public dbg::command { virtual void exec(strings const &args, ostream &out) { out << "Hello, world!" << endl; } }; - class help : public command { + class help : public dbg::command { virtual void exec(strings const &args, ostream &out) { out << "Commands:" << endl << " superblock" << endl @@ -215,7 +58,7 @@ namespace { } }; - class exit_handler : public command { + class exit_handler : public dbg::command { public: exit_handler(command_interpreter &interpreter) : interpreter_(interpreter) { @@ -240,7 +83,7 @@ namespace { } }; - class show_superblock : public command { + class show_superblock : public dbg::command { public: explicit show_superblock(metadata::ptr md) : md_(md) { @@ -340,7 +183,7 @@ namespace { }; template - class show_btree_node : public command { + class show_btree_node : public dbg::command { public: explicit show_btree_node(metadata::ptr md) : md_(md) { @@ -389,7 +232,7 @@ namespace { metadata::ptr md_; }; - class show_index_block : public command { + class show_index_block : public dbg::command { public: explicit show_index_block(metadata::ptr md) : md_(md) { @@ -437,7 +280,9 @@ namespace { //-------------------------------- - int debug(string const &path, bool ignore_metadata_sm) { + int debug_(string const &path, bool ignore_metadata_sm) { + using dbg::command; + try { block_manager::ptr bm = open_bm(path, block_manager::READ_ONLY, 1); metadata::ptr md(new metadata(bm, false)); @@ -510,5 +355,5 @@ thin_debug_cmd::run(int argc, char **argv) exit(1); } - return debug(argv[optind], ignore_metadata_sm); + return debug_(argv[optind], ignore_metadata_sm); }