1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 2 // This source code is licensed under both the GPLv2 (found in the 3 // COPYING file in the root directory) and Apache 2.0 License 4 // (found in the LICENSE.Apache file in the root directory). 5 // 6 // The implementation of ThreadStatus. 7 // 8 // Note that we make get and set access to ThreadStatusData lockless. 9 // As a result, ThreadStatusData as a whole is not atomic. However, 10 // we guarantee consistent ThreadStatusData all the time whenever 11 // user call GetThreadList(). This consistency guarantee is done 12 // by having the following constraint in the internal implementation 13 // of set and get order: 14 // 15 // 1. When reset any information in ThreadStatusData, always start from 16 // clearing up the lower-level information first. 17 // 2. When setting any information in ThreadStatusData, always start from 18 // setting the higher-level information. 19 // 3. When returning ThreadStatusData to the user, fields are fetched from 20 // higher-level to lower-level. In addition, where there's a nullptr 21 // in one field, then all fields that has lower-level than that field 22 // should be ignored. 23 // 24 // The high to low level information would be: 25 // thread_id > thread_type > db > cf > operation > state 26 // 27 // This means user might not always get full information, but whenever 28 // returned by the GetThreadList() is guaranteed to be consistent. 29 #pragma once 30 #include <atomic> 31 #include <list> 32 #include <memory> 33 #include <mutex> 34 #include <string> 35 #include <unordered_map> 36 #include <unordered_set> 37 #include <vector> 38 39 #include "rocksdb/status.h" 40 #include "rocksdb/thread_status.h" 41 #include "port/port.h" 42 #include "util/thread_operation.h" 43 44 namespace ROCKSDB_NAMESPACE { 45 46 class ColumnFamilyHandle; 47 48 // The structure that keeps constant information about a column family. 49 struct ConstantColumnFamilyInfo { 50 #ifdef ROCKSDB_USING_THREAD_STATUS 51 public: ConstantColumnFamilyInfoConstantColumnFamilyInfo52 ConstantColumnFamilyInfo( 53 const void* _db_key, 54 const std::string& _db_name, 55 const std::string& _cf_name) : 56 db_key(_db_key), db_name(_db_name), cf_name(_cf_name) {} 57 const void* db_key; 58 const std::string db_name; 59 const std::string cf_name; 60 #endif // ROCKSDB_USING_THREAD_STATUS 61 }; 62 63 // the internal data-structure that is used to reflect the current 64 // status of a thread using a set of atomic pointers. 65 struct ThreadStatusData { 66 #ifdef ROCKSDB_USING_THREAD_STATUS ThreadStatusDataThreadStatusData67 explicit ThreadStatusData() : enable_tracking(false) { 68 thread_id.store(0); 69 thread_type.store(ThreadStatus::USER); 70 cf_key.store(nullptr); 71 operation_type.store(ThreadStatus::OP_UNKNOWN); 72 op_start_time.store(0); 73 state_type.store(ThreadStatus::STATE_UNKNOWN); 74 } 75 76 // A flag to indicate whether the thread tracking is enabled 77 // in the current thread. This value will be updated based on whether 78 // the associated Options::enable_thread_tracking is set to true 79 // in ThreadStatusUtil::SetColumnFamily(). 80 // 81 // If set to false, then SetThreadOperation and SetThreadState 82 // will be no-op. 83 bool enable_tracking; 84 85 std::atomic<uint64_t> thread_id; 86 std::atomic<ThreadStatus::ThreadType> thread_type; 87 std::atomic<void*> cf_key; 88 std::atomic<ThreadStatus::OperationType> operation_type; 89 std::atomic<uint64_t> op_start_time; 90 std::atomic<ThreadStatus::OperationStage> operation_stage; 91 std::atomic<uint64_t> op_properties[ThreadStatus::kNumOperationProperties]; 92 std::atomic<ThreadStatus::StateType> state_type; 93 #endif // ROCKSDB_USING_THREAD_STATUS 94 }; 95 96 // The class that stores and updates the status of the current thread 97 // using a thread-local ThreadStatusData. 98 // 99 // In most of the case, you should use ThreadStatusUtil to update 100 // the status of the current thread instead of using ThreadSatusUpdater 101 // directly. 102 // 103 // @see ThreadStatusUtil 104 class ThreadStatusUpdater { 105 public: ThreadStatusUpdater()106 ThreadStatusUpdater() {} 107 108 // Releases all ThreadStatusData of all active threads. ~ThreadStatusUpdater()109 virtual ~ThreadStatusUpdater() {} 110 111 // Unregister the current thread. 112 void UnregisterThread(); 113 114 // Reset the status of the current thread. This includes resetting 115 // ColumnFamilyInfoKey, ThreadOperation, and ThreadState. 116 void ResetThreadStatus(); 117 118 // Set the id of the current thread. 119 void SetThreadID(uint64_t thread_id); 120 121 // Register the current thread for tracking. 122 void RegisterThread(ThreadStatus::ThreadType ttype, uint64_t thread_id); 123 124 // Update the column-family info of the current thread by setting 125 // its thread-local pointer of ThreadStateInfo to the correct entry. 126 void SetColumnFamilyInfoKey(const void* cf_key); 127 128 // returns the column family info key. 129 const void* GetColumnFamilyInfoKey(); 130 131 // Update the thread operation of the current thread. 132 void SetThreadOperation(const ThreadStatus::OperationType type); 133 134 // The start time of the current thread operation. It is in the format 135 // of micro-seconds since some fixed point in time. 136 void SetOperationStartTime(const uint64_t start_time); 137 138 // Set the "i"th property of the current operation. 139 // 140 // NOTE: Our practice here is to set all the thread operation properties 141 // and stage before we set thread operation, and thread operation 142 // will be set in std::memory_order_release. This is to ensure 143 // whenever a thread operation is not OP_UNKNOWN, we will always 144 // have a consistent information on its properties. 145 void SetThreadOperationProperty( 146 int i, uint64_t value); 147 148 // Increase the "i"th property of the current operation with 149 // the specified delta. 150 void IncreaseThreadOperationProperty( 151 int i, uint64_t delta); 152 153 // Update the thread operation stage of the current thread. 154 ThreadStatus::OperationStage SetThreadOperationStage( 155 const ThreadStatus::OperationStage stage); 156 157 // Clear thread operation of the current thread. 158 void ClearThreadOperation(); 159 160 // Reset all thread-operation-properties to 0. 161 void ClearThreadOperationProperties(); 162 163 // Update the thread state of the current thread. 164 void SetThreadState(const ThreadStatus::StateType type); 165 166 // Clear the thread state of the current thread. 167 void ClearThreadState(); 168 169 // Obtain the status of all active registered threads. 170 Status GetThreadList( 171 std::vector<ThreadStatus>* thread_list); 172 173 // Create an entry in the global ColumnFamilyInfo table for the 174 // specified column family. This function should be called only 175 // when the current thread does not hold db_mutex. 176 void NewColumnFamilyInfo( 177 const void* db_key, const std::string& db_name, 178 const void* cf_key, const std::string& cf_name); 179 180 // Erase all ConstantColumnFamilyInfo that is associated with the 181 // specified db instance. This function should be called only when 182 // the current thread does not hold db_mutex. 183 void EraseDatabaseInfo(const void* db_key); 184 185 // Erase the ConstantColumnFamilyInfo that is associated with the 186 // specified ColumnFamilyData. This function should be called only 187 // when the current thread does not hold db_mutex. 188 void EraseColumnFamilyInfo(const void* cf_key); 189 190 // Verifies whether the input ColumnFamilyHandles matches 191 // the information stored in the current cf_info_map. 192 void TEST_VerifyColumnFamilyInfoMap( 193 const std::vector<ColumnFamilyHandle*>& handles, 194 bool check_exist); 195 196 protected: 197 #ifdef ROCKSDB_USING_THREAD_STATUS 198 // The thread-local variable for storing thread status. 199 static __thread ThreadStatusData* thread_status_data_; 200 201 // Returns the pointer to the thread status data only when the 202 // thread status data is non-null and has enable_tracking == true. 203 ThreadStatusData* GetLocalThreadStatus(); 204 205 // Directly returns the pointer to thread_status_data_ without 206 // checking whether enabling_tracking is true of not. Get()207 ThreadStatusData* Get() { 208 return thread_status_data_; 209 } 210 211 // The mutex that protects cf_info_map and db_key_map. 212 std::mutex thread_list_mutex_; 213 214 // The current status data of all active threads. 215 std::unordered_set<ThreadStatusData*> thread_data_set_; 216 217 // A global map that keeps the column family information. It is stored 218 // globally instead of inside DB is to avoid the situation where DB is 219 // closing while GetThreadList function already get the pointer to its 220 // CopnstantColumnFamilyInfo. 221 std::unordered_map<const void*, ConstantColumnFamilyInfo> cf_info_map_; 222 223 // A db_key to cf_key map that allows erasing elements in cf_info_map 224 // associated to the same db_key faster. 225 std::unordered_map< 226 const void*, std::unordered_set<const void*>> db_key_map_; 227 228 #else 229 static ThreadStatusData* thread_status_data_; 230 #endif // ROCKSDB_USING_THREAD_STATUS 231 }; 232 233 } // namespace ROCKSDB_NAMESPACE 234