[thin_restore] Add a progress monitor
This commit is contained 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 \ | ||||
|   | ||||
							
								
								
									
										75
									
								
								base/progress_monitor.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								base/progress_monitor.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| #include "base/progress_monitor.h" | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| 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<unsigned>(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()); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
							
								
								
									
										25
									
								
								base/progress_monitor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								base/progress_monitor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #ifndef BASE_PROGRESS_MONITOR_H | ||||
| #define BASE_PROGRESS_MONITOR_H | ||||
|  | ||||
| #include <boost/shared_ptr.hpp> | ||||
| #include <string> | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|  | ||||
| namespace base { | ||||
| 	class progress_monitor { | ||||
| 	public: | ||||
| 		typedef boost::shared_ptr<progress_monitor> 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 | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| #define XML_FORMAT_H | ||||
|  | ||||
| #include "emitter.h" | ||||
| #include "base/progress_monitor.h" | ||||
|  | ||||
| #include <iosfwd> | ||||
|  | ||||
| @@ -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); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user