1 // Author:  Bruce Allen
2 // Created: 2/25/2013
3 //
4 // The software provided here is released by the Naval Postgraduate
5 // School, an agency of the U.S. Department of Navy.  The software
6 // bears no warranty, either expressed or implied. NPS does not assume
7 // legal liability nor responsibility for a User's use of the software
8 // or the results of such use.
9 //
10 // Please note that within the United States, copyright protection,
11 // under Section 105 of the United States Code, Title 17, is not
12 // available for any work of the United States Government and/or for
13 // any works created by United States Government employees. User
14 // acknowledges that this software contains work which was created by
15 // NPS government employees and is therefore in the public domain and
16 // not subject to copyright.
17 //
18 // Released into the public domain on February 25, 2013 by Bruce Allen.
19 
20 /**
21  * \file
22  * Track progress to show that long iterative actions are not hung.
23  * Writes progress to cout and to <dir>/timestamp.json log.
24  * Use total=0 if total is not known.
25  */
26 
27 #ifndef PROGRESS_TRACKER_HPP
28 #define PROGRESS_TRACKER_HPP
29 
30 // Standard includes
31 #include <cstdlib>
32 #include <cstdio>
33 #include <cerrno>
34 #include <cstring>
35 #include <sstream>
36 #include <iostream>
37 #include <fstream>
38 #include "../src_libhashdb/hashdb.hpp" // for timestamp
39 
40 class progress_tracker_t {
41   private:
42   const std::string dir;
43   const uint64_t total;
44   uint64_t index;
45   std::ofstream os;
46   hashdb::timestamp_t timestamp;
47 
48   // do not allow copy or assignment
49   progress_tracker_t(const progress_tracker_t&);
50   progress_tracker_t& operator=(const progress_tracker_t&);
51 
show_progress()52   void show_progress() {
53     std::stringstream ss;
54     if (total > 0) {
55       // total is known
56       ss << "# Processing " << index << " of " << total;
57     } else {
58       // total is not known
59       ss << "# Processing " << index << " of ?";
60     }
61     std::cout << ss.str() << "..." << std::endl;
62     os << timestamp.stamp(ss.str()) << std::endl;
63   }
64 
65   public:
progress_tracker_t(const std::string & p_dir,const uint64_t p_total,const std::string & cmd)66   progress_tracker_t(const std::string& p_dir, const uint64_t p_total,
67                      const std::string& cmd) :
68                          dir(p_dir),
69                          total(p_total),
70                          index(0),
71                          os(),
72                          timestamp() {
73     std::string filename(dir+"/timestamp.json");
74 
75     // open, fatal if unable to open
76     os.open(filename.c_str());
77     if (!os.is_open()) {
78       std::cout << "Cannot open progress tracker file " << filename
79                 << ": " << strerror(errno) << "\n";
80       exit(1);
81     }
82 
83     // put header in log
84     os << "# command: '" << cmd << "'\n"
85        << "# hashdb-Version: " << PACKAGE_VERSION << "\n";
86   }
87 
track()88   void track() {
89     ++index;
90     if (index%100000 == 0) {
91       show_progress();
92     }
93   }
94 
track_count(const size_t count)95   void track_count(const size_t count) {
96     size_t old_index = index;
97     index += count;
98     if ((index > 0) && (index / 100000 > old_index / 100000)) {
99       show_progress();
100     }
101   }
102 
track_hash_data(const uint64_t count)103   void track_hash_data(const uint64_t count) {
104     // The amount of hash data traversed is calculated from count,
105     // which is 1 or size + 1, see hashdb_data store.
106     track_count(count == 1? 1 : count + 1);
107   }
108 
~progress_tracker_t()109   ~progress_tracker_t() {
110     std::stringstream ss;
111     if (total > 0) {
112       // total is known
113       ss << "# Processing " << index << " of " << total << " completed.";
114     } else {
115       // total is not known
116       ss << "# Processing " << index << " of " << index << " completed.";
117     }
118     std::cout << ss.str() << std::endl;
119     os << timestamp.stamp(ss.str()) << std::endl;
120 
121     os.close();
122   }
123 };
124 
125 #endif
126 
127