summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/monitoring/thread_status_updater.h
blob: 762c73ae2bb3f39118a784be7a0fc443ffbd444a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
//
// The implementation of ThreadStatus.
//
// Note that we make get and set access to ThreadStatusData lockless.
// As a result, ThreadStatusData as a whole is not atomic.  However,
// we guarantee consistent ThreadStatusData all the time whenever
// user call GetThreadList().  This consistency guarantee is done
// by having the following constraint in the internal implementation
// of set and get order:
//
// 1. When reset any information in ThreadStatusData, always start from
//    clearing up the lower-level information first.
// 2. When setting any information in ThreadStatusData, always start from
//    setting the higher-level information.
// 3. When returning ThreadStatusData to the user, fields are fetched from
//    higher-level to lower-level.  In addition, where there's a nullptr
//    in one field, then all fields that has lower-level than that field
//    should be ignored.
//
// The high to low level information would be:
// thread_id > thread_type > db > cf > operation > state
//
// This means user might not always get full information, but whenever
// returned by the GetThreadList() is guaranteed to be consistent.
#pragma once
#include <atomic>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "port/port.h"
#include "rocksdb/status.h"
#include "rocksdb/thread_status.h"
#include "util/thread_operation.h"

namespace ROCKSDB_NAMESPACE {

class ColumnFamilyHandle;

// The structure that keeps constant information about a column family.
struct ConstantColumnFamilyInfo {
#ifdef ROCKSDB_USING_THREAD_STATUS
 public:
  ConstantColumnFamilyInfo(const void* _db_key, const std::string& _db_name,
                           const std::string& _cf_name)
      : db_key(_db_key), db_name(_db_name), cf_name(_cf_name) {}
  const void* db_key;
  const std::string db_name;
  const std::string cf_name;
#endif  // ROCKSDB_USING_THREAD_STATUS
};

// the internal data-structure that is used to reflect the current
// status of a thread using a set of atomic pointers.
struct ThreadStatusData {
#ifdef ROCKSDB_USING_THREAD_STATUS
  explicit ThreadStatusData() : enable_tracking(false) {
    thread_id.store(0);
    thread_type.store(ThreadStatus::USER);
    cf_key.store(nullptr);
    operation_type.store(ThreadStatus::OP_UNKNOWN);
    op_start_time.store(0);
    state_type.store(ThreadStatus::STATE_UNKNOWN);
  }

  // A flag to indicate whether the thread tracking is enabled
  // in the current thread.  This value will be updated based on whether
  // the associated Options::enable_thread_tracking is set to true
  // in ThreadStatusUtil::SetColumnFamily().
  //
  // If set to false, then SetThreadOperation and SetThreadState
  // will be no-op.
  bool enable_tracking;

  std::atomic<uint64_t> thread_id;
  std::atomic<ThreadStatus::ThreadType> thread_type;
  std::atomic<void*> cf_key;
  std::atomic<ThreadStatus::OperationType> operation_type;
  std::atomic<uint64_t> op_start_time;
  std::atomic<ThreadStatus::OperationStage> operation_stage;
  std::atomic<uint64_t> op_properties[ThreadStatus::kNumOperationProperties];
  std::atomic<ThreadStatus::StateType> state_type;
#endif  // ROCKSDB_USING_THREAD_STATUS
};

// The class that stores and updates the status of the current thread
// using a thread-local ThreadStatusData.
//
// In most of the case, you should use ThreadStatusUtil to update
// the status of the current thread instead of using ThreadSatusUpdater
// directly.
//
// @see ThreadStatusUtil
class ThreadStatusUpdater {
 public:
  ThreadStatusUpdater() {}

  // Releases all ThreadStatusData of all active threads.
  virtual ~ThreadStatusUpdater() {}

  // Unregister the current thread.
  void UnregisterThread();

  // Reset the status of the current thread.  This includes resetting
  // ColumnFamilyInfoKey, ThreadOperation, and ThreadState.
  void ResetThreadStatus();

  // Set the id of the current thread.
  void SetThreadID(uint64_t thread_id);

  // Register the current thread for tracking.
  void RegisterThread(ThreadStatus::ThreadType ttype, uint64_t thread_id);

  // Update the column-family info of the current thread by setting
  // its thread-local pointer of ThreadStateInfo to the correct entry.
  void SetColumnFamilyInfoKey(const void* cf_key);

  // returns the column family info key.
  const void* GetColumnFamilyInfoKey();

  // Update the thread operation of the current thread.
  void SetThreadOperation(const ThreadStatus::OperationType type);

  // The start time of the current thread operation.  It is in the format
  // of micro-seconds since some fixed point in time.
  void SetOperationStartTime(const uint64_t start_time);

  // Set the "i"th property of the current operation.
  //
  // NOTE: Our practice here is to set all the thread operation properties
  //       and stage before we set thread operation, and thread operation
  //       will be set in std::memory_order_release.  This is to ensure
  //       whenever a thread operation is not OP_UNKNOWN, we will always
  //       have a consistent information on its properties.
  void SetThreadOperationProperty(int i, uint64_t value);

  // Increase the "i"th property of the current operation with
  // the specified delta.
  void IncreaseThreadOperationProperty(int i, uint64_t delta);

  // Update the thread operation stage of the current thread.
  ThreadStatus::OperationStage SetThreadOperationStage(
      const ThreadStatus::OperationStage stage);

  // Clear thread operation of the current thread.
  void ClearThreadOperation();

  // Reset all thread-operation-properties to 0.
  void ClearThreadOperationProperties();

  // Update the thread state of the current thread.
  void SetThreadState(const ThreadStatus::StateType type);

  // Clear the thread state of the current thread.
  void ClearThreadState();

  // Obtain the status of all active registered threads.
  Status GetThreadList(std::vector<ThreadStatus>* thread_list);

  // Create an entry in the global ColumnFamilyInfo table for the
  // specified column family.  This function should be called only
  // when the current thread does not hold db_mutex.
  void NewColumnFamilyInfo(const void* db_key, const std::string& db_name,
                           const void* cf_key, const std::string& cf_name);

  // Erase all ConstantColumnFamilyInfo that is associated with the
  // specified db instance.  This function should be called only when
  // the current thread does not hold db_mutex.
  void EraseDatabaseInfo(const void* db_key);

  // Erase the ConstantColumnFamilyInfo that is associated with the
  // specified ColumnFamilyData.  This function should be called only
  // when the current thread does not hold db_mutex.
  void EraseColumnFamilyInfo(const void* cf_key);

  // Verifies whether the input ColumnFamilyHandles matches
  // the information stored in the current cf_info_map.
  void TEST_VerifyColumnFamilyInfoMap(
      const std::vector<ColumnFamilyHandle*>& handles, bool check_exist);

 protected:
#ifdef ROCKSDB_USING_THREAD_STATUS
  // The thread-local variable for storing thread status.
  static thread_local ThreadStatusData* thread_status_data_;

  // Returns the pointer to the thread status data only when the
  // thread status data is non-null and has enable_tracking == true.
  ThreadStatusData* GetLocalThreadStatus();

  // Directly returns the pointer to thread_status_data_ without
  // checking whether enabling_tracking is true of not.
  ThreadStatusData* Get() { return thread_status_data_; }

  // The mutex that protects cf_info_map and db_key_map.
  std::mutex thread_list_mutex_;

  // The current status data of all active threads.
  std::unordered_set<ThreadStatusData*> thread_data_set_;

  // A global map that keeps the column family information.  It is stored
  // globally instead of inside DB is to avoid the situation where DB is
  // closing while GetThreadList function already get the pointer to its
  // CopnstantColumnFamilyInfo.
  std::unordered_map<const void*, ConstantColumnFamilyInfo> cf_info_map_;

  // A db_key to cf_key map that allows erasing elements in cf_info_map
  // associated to the same db_key faster.
  std::unordered_map<const void*, std::unordered_set<const void*>> db_key_map_;

#else
  static ThreadStatusData* thread_status_data_;
#endif  // ROCKSDB_USING_THREAD_STATUS
};

}  // namespace ROCKSDB_NAMESPACE