/Users/deen/code/yugabyte-db/src/yb/tablet/maintenance_manager.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | #ifndef YB_TABLET_MAINTENANCE_MANAGER_H |
33 | | #define YB_TABLET_MAINTENANCE_MANAGER_H |
34 | | |
35 | | #include <stdint.h> |
36 | | |
37 | | #include <condition_variable> |
38 | | #include <map> |
39 | | #include <memory> |
40 | | #include <set> |
41 | | #include <string> |
42 | | #include <vector> |
43 | | |
44 | | #include "yb/gutil/macros.h" |
45 | | #include "yb/gutil/thread_annotations.h" |
46 | | |
47 | | #include "yb/tablet/tablet.pb.h" |
48 | | |
49 | | #include "yb/util/condition_variable.h" |
50 | | #include "yb/util/monotime.h" |
51 | | #include "yb/util/mutex.h" |
52 | | #include "yb/util/threadpool.h" |
53 | | |
54 | | namespace yb { |
55 | | |
56 | | template<class T> |
57 | | class AtomicGauge; |
58 | | class Histogram; |
59 | | class MaintenanceManager; |
60 | | class MemTracker; |
61 | | |
62 | | class MaintenanceOpStats { |
63 | | public: |
64 | | MaintenanceOpStats(); |
65 | | |
66 | | // Zero all stats. They are invalid until the first setter is called. |
67 | | void Clear(); |
68 | | |
69 | 50.4M | bool runnable() const { |
70 | 50.4M | DCHECK(valid_); |
71 | 50.4M | return runnable_; |
72 | 50.4M | } |
73 | | |
74 | 50.4M | void set_runnable(bool runnable) { |
75 | 50.4M | UpdateLastModified(); |
76 | 50.4M | runnable_ = runnable; |
77 | 50.4M | } |
78 | | |
79 | 50.4M | uint64_t ram_anchored() const { |
80 | 50.4M | DCHECK(valid_); |
81 | 50.4M | return ram_anchored_; |
82 | 50.4M | } |
83 | | |
84 | | void set_ram_anchored(uint64_t ram_anchored) { |
85 | | UpdateLastModified(); |
86 | | ram_anchored_ = ram_anchored; |
87 | | } |
88 | | |
89 | 100M | int64_t logs_retained_bytes() const { |
90 | 100M | DCHECK(valid_); |
91 | 100M | return logs_retained_bytes_; |
92 | 100M | } |
93 | | |
94 | 50.4M | void set_logs_retained_bytes(int64_t logs_retained_bytes) { |
95 | 50.4M | UpdateLastModified(); |
96 | 50.4M | logs_retained_bytes_ = logs_retained_bytes; |
97 | 50.4M | } |
98 | | |
99 | 50.4M | double perf_improvement() const { |
100 | 50.4M | DCHECK(valid_); |
101 | 50.4M | return perf_improvement_; |
102 | 50.4M | } |
103 | | |
104 | | void set_perf_improvement(double perf_improvement) { |
105 | | UpdateLastModified(); |
106 | | perf_improvement_ = perf_improvement; |
107 | | } |
108 | | |
109 | 0 | const MonoTime& last_modified() const { |
110 | 0 | DCHECK(valid_); |
111 | 0 | return last_modified_; |
112 | 0 | } |
113 | | |
114 | 50.4M | bool valid() const { |
115 | 50.4M | return valid_; |
116 | 50.4M | } |
117 | | |
118 | | private: |
119 | 100M | void UpdateLastModified() { |
120 | 100M | valid_ = true; |
121 | 100M | last_modified_ = MonoTime::Now(); |
122 | 100M | } |
123 | | |
124 | | // True if these stats are valid. |
125 | | bool valid_; |
126 | | |
127 | | // True if this op can be run now. |
128 | | bool runnable_; |
129 | | |
130 | | // The approximate amount of memory that not doing this operation keeps |
131 | | // around. This number is used to decide when to start freeing memory, so it |
132 | | // should be fairly accurate. May be 0. |
133 | | uint64_t ram_anchored_; |
134 | | |
135 | | // The approximate amount of disk space that not doing this operation keeps us from GCing from |
136 | | // the logs. May be 0. |
137 | | int64_t logs_retained_bytes_; |
138 | | |
139 | | // The estimated performance improvement-- how good it is to do this on some |
140 | | // absolute scale (yet TBD). |
141 | | double perf_improvement_; |
142 | | |
143 | | // The last time that the stats were modified. |
144 | | MonoTime last_modified_; |
145 | | }; |
146 | | |
147 | | class ScopedMaintenanceOpRun; |
148 | | |
149 | | // MaintenanceOp objects represent background operations that the |
150 | | // MaintenanceManager can schedule. Once a MaintenanceOp is registered, the |
151 | | // manager will periodically poll it for statistics. The registrant is |
152 | | // responsible for managing the memory associated with the MaintenanceOp object. |
153 | | // Op objects should be unregistered before being de-allocated. |
154 | | class MaintenanceOp { |
155 | | public: |
156 | | friend class MaintenanceManager; |
157 | | |
158 | | // General indicator of how much IO the Op will use. |
159 | | enum IOUsage { |
160 | | LOW_IO_USAGE, // Low impact operations like removing a file, updating metadata. |
161 | | HIGH_IO_USAGE // Everything else. |
162 | | }; |
163 | | |
164 | | explicit MaintenanceOp(std::string name, IOUsage io_usage); |
165 | | virtual ~MaintenanceOp(); |
166 | | |
167 | | // Unregister this op, if it is currently registered. |
168 | | void Unregister(); |
169 | | |
170 | | // Update the op statistics. This will be called every scheduling period |
171 | | // (about a few times a second), so it should not be too expensive. It's |
172 | | // possible for the returned statistics to be invalid; the caller should |
173 | | // call MaintenanceOpStats::valid() before using them. This will be run |
174 | | // under the MaintenanceManager lock. |
175 | | virtual void UpdateStats(MaintenanceOpStats* stats) = 0; |
176 | | |
177 | | // Prepare to perform the operation. This will be run without holding the |
178 | | // maintenance manager lock. It should be short, since it is run from the |
179 | | // context of the maintenance op scheduler thread rather than a worker thread. |
180 | | // If this returns false, we will abort the operation. |
181 | | virtual bool Prepare() = 0; |
182 | | |
183 | | // Perform the operation. This will be run without holding the maintenance |
184 | | // manager lock, and may take a long time. |
185 | | virtual void Perform() = 0; |
186 | | |
187 | | // Returns the histogram for this op that tracks duration. Cannot be NULL. |
188 | | virtual scoped_refptr<Histogram> DurationHistogram() const = 0; |
189 | | |
190 | | // Returns the gauge for this op that tracks when this op is running. Cannot be NULL. |
191 | | virtual scoped_refptr<AtomicGauge<uint32_t> > RunningGauge() const = 0; |
192 | | |
193 | 0 | uint32_t running() { return running_; } |
194 | | |
195 | 2.66M | std::string name() const { return name_; } |
196 | | |
197 | 0 | IOUsage io_usage() const { return io_usage_; } |
198 | | |
199 | | private: |
200 | | friend class ScopedMaintenanceOpRun; |
201 | | |
202 | | // The name of the operation. Op names must be unique. |
203 | | const std::string name_; |
204 | | |
205 | | // The number of times that this op is currently running. |
206 | | uint32_t running_ = 0; |
207 | | |
208 | | // Condition variable which the UnregisterOp function can wait on. |
209 | | // |
210 | | // Note: 'cond_' is used with the MaintenanceManager's mutex. As such, |
211 | | // it only exists when the op is registered. |
212 | | std::condition_variable cond_; |
213 | | |
214 | | // The MaintenanceManager with which this op is registered, or null |
215 | | // if it is not registered. |
216 | | std::shared_ptr<MaintenanceManager> manager_; |
217 | | |
218 | | IOUsage io_usage_; |
219 | | |
220 | | DISALLOW_COPY_AND_ASSIGN(MaintenanceOp); |
221 | | }; |
222 | | |
223 | | struct MaintenanceOpComparator { |
224 | | bool operator() (const MaintenanceOp* lhs, |
225 | 1.29M | const MaintenanceOp* rhs) const { |
226 | 1.29M | return lhs->name().compare(rhs->name()) < 0; |
227 | 1.29M | } |
228 | | }; |
229 | | |
230 | | // Holds the information regarding a recently completed operation. |
231 | | struct CompletedOp { |
232 | | std::string name; |
233 | | MonoDelta duration; |
234 | | MonoTime start_mono_time; |
235 | | }; |
236 | | |
237 | | // The MaintenanceManager manages the scheduling of background operations such |
238 | | // as flushes or compactions. It runs these operations in the background, in a |
239 | | // thread pool. It uses information provided in MaintenanceOpStats objects to |
240 | | // decide which operations, if any, to run. |
241 | | class MaintenanceManager : public std::enable_shared_from_this<MaintenanceManager> { |
242 | | public: |
243 | | struct Options { |
244 | | int32_t num_threads; |
245 | | int32_t polling_interval_ms; |
246 | | uint32_t history_size; |
247 | | std::shared_ptr<MemTracker> parent_mem_tracker; |
248 | | }; |
249 | | |
250 | | explicit MaintenanceManager(const Options& options); |
251 | | ~MaintenanceManager(); |
252 | | |
253 | | CHECKED_STATUS Init(); |
254 | | void Shutdown(); |
255 | | |
256 | | // Register an op with the manager. |
257 | | void RegisterOp(MaintenanceOp* op); |
258 | | |
259 | | // Unregister an op with the manager. |
260 | | // If the Op is currently running, it will not be interrupted. However, this |
261 | | // function will block until the Op is finished. |
262 | | void UnregisterOp(MaintenanceOp* op); |
263 | | |
264 | | void GetMaintenanceManagerStatusDump(tablet::MaintenanceManagerStatusPB* out_pb); |
265 | | |
266 | | static const Options DEFAULT_OPTIONS; |
267 | | |
268 | | private: |
269 | | friend class ScopedMaintenanceOpRun; |
270 | | |
271 | | FRIEND_TEST(MaintenanceManagerTest, TestLogRetentionPrioritization); |
272 | | typedef std::map<MaintenanceOp*, MaintenanceOpStats, MaintenanceOpComparator> OpMapTy; |
273 | | |
274 | | void RunSchedulerThread(); |
275 | | |
276 | | // find the best op, or null if there is nothing we want to run |
277 | | MaintenanceOp* FindBestOp() REQUIRES(mutex_); |
278 | | |
279 | | void LaunchOp(const ScopedMaintenanceOpRun& op); |
280 | | |
281 | | std::mutex mutex_; |
282 | | const int32_t num_threads_; |
283 | | const int32_t polling_interval_ms_; |
284 | | const std::shared_ptr<MemTracker> parent_mem_tracker_; |
285 | | |
286 | | OpMapTy ops_ GUARDED_BY(mutex_); // registered operations |
287 | | scoped_refptr<yb::Thread> monitor_thread_; |
288 | | std::unique_ptr<ThreadPool> thread_pool_; |
289 | | std::condition_variable cond_; |
290 | | bool shutdown_ GUARDED_BY(mutex_) = false; |
291 | | uint64_t running_ops_ = 0; |
292 | | // Vector used as a circular buffer for recently completed ops. Elements need to be added at |
293 | | // the completed_ops_count_ % the vector's size and then the count needs to be incremented. |
294 | | std::vector<CompletedOp> completed_ops_ GUARDED_BY(mutex_); |
295 | | int64_t completed_ops_count_ GUARDED_BY(mutex_) = 0; |
296 | | |
297 | | DISALLOW_COPY_AND_ASSIGN(MaintenanceManager); |
298 | | }; |
299 | | |
300 | | class ScopedMaintenanceOpRun { |
301 | | public: |
302 | | explicit ScopedMaintenanceOpRun(MaintenanceOp* op); |
303 | | |
304 | | ScopedMaintenanceOpRun(const ScopedMaintenanceOpRun& rhs); |
305 | | void operator=(const ScopedMaintenanceOpRun& rhs); |
306 | | |
307 | | ScopedMaintenanceOpRun(ScopedMaintenanceOpRun&& rhs); |
308 | | void operator=(ScopedMaintenanceOpRun&& rhs); |
309 | | |
310 | | ~ScopedMaintenanceOpRun(); |
311 | | |
312 | | void Reset(); |
313 | | |
314 | | MaintenanceOp* get() const; |
315 | | |
316 | | private: |
317 | | void Assign(MaintenanceOp* op); |
318 | | |
319 | | MaintenanceOp* op_; |
320 | | }; |
321 | | |
322 | | } // namespace yb |
323 | | |
324 | | #endif // YB_TABLET_MAINTENANCE_MANAGER_H |