YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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