1 // progress_meter.h
2 
3 
4 /**
5  *    Copyright (C) 2018-present MongoDB, Inc.
6  *
7  *    This program is free software: you can redistribute it and/or modify
8  *    it under the terms of the Server Side Public License, version 1,
9  *    as published by MongoDB, Inc.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    Server Side Public License for more details.
15  *
16  *    You should have received a copy of the Server Side Public License
17  *    along with this program. If not, see
18  *    <http://www.mongodb.com/licensing/server-side-public-license>.
19  *
20  *    As a special exception, the copyright holders give permission to link the
21  *    code of portions of this program with the OpenSSL library under certain
22  *    conditions as described in each individual source file and distribute
23  *    linked combinations including the program with the OpenSSL library. You
24  *    must comply with the Server Side Public License in all respects for
25  *    all of the code used other than as permitted herein. If you modify file(s)
26  *    with this exception, you may extend this exception to your version of the
27  *    file(s), but you are not obligated to do so. If you do not wish to do so,
28  *    delete this exception statement from your version. If you delete this
29  *    exception statement from all source files in the program, then also delete
30  *    it in the license file.
31  */
32 
33 #pragma once
34 
35 #include "mongo/util/thread_safe_string.h"
36 
37 #include <string>
38 
39 namespace mongo {
40 
41 class ProgressMeter {
42     MONGO_DISALLOW_COPYING(ProgressMeter);
43 
44 public:
45     ProgressMeter(unsigned long long total,
46                   int secondsBetween = 3,
47                   int checkInterval = 100,
48                   std::string units = "",
49                   std::string name = "Progress")
_showTotal(true)50         : _showTotal(true), _units(units) {
51         _name = name.c_str();
52         reset(total, secondsBetween, checkInterval);
53     }
54 
ProgressMeter()55     ProgressMeter() {
56         _name = "Progress";
57     }
58 
59     // typically you do ProgressMeterHolder
60     void reset(unsigned long long total, int secondsBetween = 3, int checkInterval = 100);
61 
finished()62     void finished() {
63         _active = false;
64     }
isActive()65     bool isActive() const {
66         return _active;
67     }
68 
69     /**
70      * @param n how far along we are relative to the total # we set in CurOp::setMessage
71      * @return if row was printed
72      */
73     bool hit(int n = 1);
74 
setUnits(const std::string & units)75     void setUnits(const std::string& units) {
76         _units = units;
77     }
getUnit()78     std::string getUnit() const {
79         return _units;
80     }
81 
setName(std::string name)82     void setName(std::string name) {
83         _name = name.c_str();
84     }
getName()85     std::string getName() const {
86         return _name.toString();
87     }
88 
setTotalWhileRunning(unsigned long long total)89     void setTotalWhileRunning(unsigned long long total) {
90         _total = total;
91     }
92 
done()93     unsigned long long done() const {
94         return _done;
95     }
96 
hits()97     unsigned long long hits() const {
98         return _hits;
99     }
100 
total()101     unsigned long long total() const {
102         return _total;
103     }
104 
showTotal(bool doShow)105     void showTotal(bool doShow) {
106         _showTotal = doShow;
107     }
108 
109     std::string toString() const;
110 
111     bool operator==(const ProgressMeter& other) const {
112         return this == &other;
113     }
114 
115 private:
116     bool _active{false};
117 
118     unsigned long long _total;
119     bool _showTotal{true};
120     int _secondsBetween{3};
121     int _checkInterval{100};
122 
123     unsigned long long _done;
124     unsigned long long _hits;
125     int _lastTime;
126 
127     std::string _units;
128     ThreadSafeString _name;
129 };
130 
131 // e.g.:
132 // CurOp * op = CurOp::get(opCtx);
133 // ProgressMeterHolder pm(op->setMessage("index: (1/3) external sort",
134 // "Index: External Sort Progress", d->stats.nrecords, 10)); loop { pm.hit(); }
135 class ProgressMeterHolder {
136     MONGO_DISALLOW_COPYING(ProgressMeterHolder);
137 
138 public:
ProgressMeterHolder(ProgressMeter & pm)139     ProgressMeterHolder(ProgressMeter& pm) : _pm(pm) {}
140 
~ProgressMeterHolder()141     ~ProgressMeterHolder() {
142         _pm.finished();
143     }
144 
145     ProgressMeter* operator->() {
146         return &_pm;
147     }
148 
get()149     ProgressMeter* get() {
150         return &_pm;
151     }
152 
153     bool hit(int n = 1) {
154         return _pm.hit(n);
155     }
156 
finished()157     void finished() {
158         _pm.finished();
159     }
160 
161     bool operator==(const ProgressMeter& other) {
162         return _pm == other;
163     }
164 
165 private:
166     ProgressMeter& _pm;
167 };
168 }
169