// Copyright (c) 2013, Facebook, Inc. All rights reserved. // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. An additional grant // of patent rights can be found in the PATENTS file in the same directory. // // The implementation of ThreadStatus. It is implemented via combination // of macros and thread-local variables. // // 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 > event > event_count > event_details // // This means user might not always get full information, but whenever // returned by the GetThreadList() is guaranteed to be consistent. #pragma once #include #include #include #include #include #include #include #include "rocksdb/status.h" #include "rocksdb/thread_status.h" #include "port/port_posix.h" namespace rocksdb { class ColumnFamilyHandle; // The mutable version of ThreadStatus. It has a static set maintaining // the set of current registered threades. // // Note that it is suggested to call the above macros. struct ConstantColumnFamilyInfo { #if 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 }; struct ThreadEventInfo { #if ROCKSDB_USING_THREAD_STATUS public: const std::string event_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 { #if ROCKSDB_USING_THREAD_STATUS explicit ThreadStatusData() : thread_id(0) { thread_type.store(ThreadStatus::ThreadType::USER_THREAD); cf_key.store(0); event_info.store(nullptr); } uint64_t thread_id; std::atomic thread_type; std::atomic cf_key; std::atomic event_info; #endif // ROCKSDB_USING_THREAD_STATUS }; class ThreadStatusImpl { public: ThreadStatusImpl() {} // Releases all ThreadStatusData of all active threads. ~ThreadStatusImpl(); void UnregisterThread(); // Set the thread type of the current thread. void SetThreadType(ThreadStatus::ThreadType ttype); // Update the column-family info of the current thread by setting // its thread-local pointer of ThreadEventInfo to the correct entry. void SetColumnFamilyInfoKey(const void* cf_key); // Update the event info of the current thread by setting // its thread-local pointer of ThreadEventInfo to the correct entry. void SetEventInfoPtr(const ThreadEventInfo* event_info); Status GetThreadList( std::vector* thread_list) const; // 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. static 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. static 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. static void EraseColumnFamilyInfo(const void* cf_key); // Verifies whether the input ColumnFamilyHandles matches // the information stored in the current cf_info_map. static void TEST_VerifyColumnFamilyInfoMap( const std::vector& handles, bool check_exist); protected: #if ROCKSDB_USING_THREAD_STATUS // The thread-local variable for storing thread status. static __thread ThreadStatusData* thread_status_data_; // Obtain the pointer to the thread status data. It also performs // initialization when necessary. ThreadStatusData* InitAndGet(); // The mutex that protects cf_info_map and db_key_map. static std::mutex thread_list_mutex_; // The current status data of all active threads. static std::unordered_set 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. static 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. static std::unordered_map< const void*, std::unordered_set> db_key_map_; #else static ThreadStatusData* thread_status_data_; #endif // ROCKSDB_USING_THREAD_STATUS }; extern ThreadStatusImpl thread_local_status; } // namespace rocksdb