diff --git a/Makefile.in b/Makefile.in index e65667d..9f4167d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,6 +46,7 @@ SOURCE=\ base/base64.cc \ base/endian_utils.cc \ base/error_state.cc \ + base/progress_monitor.cc \ \ caching/hint_array.cc \ caching/superblock.cc \ @@ -377,6 +378,7 @@ ERA_DUMP_SOURCE=\ base/base64.cc \ base/error_state.cc \ base/endian_utils.cc \ + base/progress_monitor.cc \ \ era/writeset_tree.cc \ era/era_detail.cc \ diff --git a/base/progress_monitor.cc b/base/progress_monitor.cc new file mode 100644 index 0000000..4e6792d --- /dev/null +++ b/base/progress_monitor.cc @@ -0,0 +1,75 @@ +#include "base/progress_monitor.h" + +#include + +//---------------------------------------------------------------- + +namespace { + using namespace std; + + class progress_bar : public base::progress_monitor { + public: + progress_bar(string const &title) + : title_(title), + progress_width_(50), + spinner_(0) { + + update_percent(0); + } + + void update_percent(unsigned p) { + unsigned nr_equals = max(progress_width_ * p / 100, 1); + unsigned nr_spaces = progress_width_ - nr_equals; + + cout << title_ << ": ["; + + for (unsigned i = 0; i < nr_equals - 1; i++) + cout << '='; + + if (nr_equals < progress_width_) + cout << '>'; + + for (unsigned i = 0; i < nr_spaces; i++) + cout << ' '; + + cout << "] " << spinner_char() << " " << p << "%\r" << flush; + + spinner_++; + } + + private: + char spinner_char() const { + char cs[] = {'|', '/', '-', '\\'}; + + unsigned index = spinner_ % sizeof(cs); + return cs[index]; + } + + std::string title_; + unsigned progress_width_; + unsigned spinner_; + }; + + class quiet_progress : public base::progress_monitor { + public: + void update_percent(unsigned p) { + } + }; + +} + +//---------------------------------------------------------------- + +base::progress_monitor::ptr +base::create_progress_bar(std::string const &title) +{ + return progress_monitor::ptr(new progress_bar(title)); +} + +base::progress_monitor::ptr +base::create_quiet_progress_monitor() +{ + return progress_monitor::ptr(new quiet_progress()); +} + +//---------------------------------------------------------------- diff --git a/base/progress_monitor.h b/base/progress_monitor.h new file mode 100644 index 0000000..29b3d36 --- /dev/null +++ b/base/progress_monitor.h @@ -0,0 +1,25 @@ +#ifndef BASE_PROGRESS_MONITOR_H +#define BASE_PROGRESS_MONITOR_H + +#include +#include + +//---------------------------------------------------------------- + +namespace base { + class progress_monitor { + public: + typedef boost::shared_ptr ptr; + + virtual ~progress_monitor() {} + + virtual void update_percent(unsigned) = 0; + }; + + progress_monitor::ptr create_progress_bar(std::string const &title); + progress_monitor::ptr create_quiet_progress_monitor(); +} + +//---------------------------------------------------------------- + +#endif diff --git a/thin-provisioning/thin_restore.cc b/thin-provisioning/thin_restore.cc index 2aa9173..86c7801 100644 --- a/thin-provisioning/thin_restore.cc +++ b/thin-provisioning/thin_restore.cc @@ -41,6 +41,24 @@ using namespace thin_provisioning; //---------------------------------------------------------------- namespace { + size_t get_file_length(string const &file) { + struct stat info; + int r; + + r = ::stat(file.c_str(), &info); + if (r) + throw runtime_error("Couldn't stat backup path"); + + return info.st_size; + } + + progress_monitor::ptr create_monitor() { + if (isatty(fileno(stdout))) + return create_progress_bar("Restoring"); + else + return create_quiet_progress_monitor(); + } + int restore(string const &backup_file, string const &dev) { try { // The block size gets updated by the restorer. @@ -49,7 +67,9 @@ namespace { check_file_exists(backup_file); ifstream in(backup_file.c_str(), ifstream::in); - parse_xml(in, restorer); + + progress_monitor::ptr monitor = create_monitor(); + parse_xml(in, restorer, get_file_length(backup_file), monitor); } catch (std::exception &e) { cerr << e.what() << endl; diff --git a/thin-provisioning/xml_format.cc b/thin-provisioning/xml_format.cc index 2767b9a..f868e2c 100644 --- a/thin-provisioning/xml_format.cc +++ b/thin-provisioning/xml_format.cc @@ -256,7 +256,8 @@ tp::create_xml_emitter(ostream &out) } void -tp::parse_xml(std::istream &in, emitter::ptr e) +tp::parse_xml(std::istream &in, emitter::ptr e, + size_t input_length, base::progress_monitor::ptr monitor) { XML_Parser parser = XML_ParserCreate(NULL); if (!parser) @@ -265,8 +266,10 @@ tp::parse_xml(std::istream &in, emitter::ptr e) XML_SetUserData(parser, e.get()); XML_SetElementHandler(parser, start_tag, end_tag); + size_t total = 0; + while (!in.eof()) { - char buffer[4096]; + char buffer[1024 * 1024]; in.read(buffer, sizeof(buffer)); size_t len = in.gcount(); int done = in.eof(); @@ -280,6 +283,9 @@ tp::parse_xml(std::istream &in, emitter::ptr e) << endl; throw runtime_error(out.str()); } + + total += len; + monitor->update_percent(total * 100 / input_length); } } diff --git a/thin-provisioning/xml_format.h b/thin-provisioning/xml_format.h index cf520e2..7cd7d4e 100644 --- a/thin-provisioning/xml_format.h +++ b/thin-provisioning/xml_format.h @@ -20,6 +20,7 @@ #define XML_FORMAT_H #include "emitter.h" +#include "base/progress_monitor.h" #include @@ -27,7 +28,8 @@ namespace thin_provisioning { emitter::ptr create_xml_emitter(std::ostream &out); - void parse_xml(std::istream &in, emitter::ptr e); + void parse_xml(std::istream &in, emitter::ptr e, + size_t input_length, base::progress_monitor::ptr p); } //----------------------------------------------------------------