45bab305f9
Summary: GetThreadList() feature depends on the thread creation and destruction, which is currently handled under Env. This patch moves GetThreadList() feature under Env to better manage the dependency of GetThreadList() feature on thread creation and destruction. Renamed ThreadStatusImpl to ThreadStatusUpdater. Add ThreadStatusUtil, which is a static class contains utility functions for ThreadStatusUpdater. Test Plan: run db_test, thread_list_test and db_bench and verify the life cycle of Env and ThreadStatusUpdater is properly managed. Reviewers: igor, sdong Reviewed By: sdong Subscribers: ljin, dhruba, leveldb Differential Revision: https://reviews.facebook.net/D30057
180 lines
5.5 KiB
C++
180 lines
5.5 KiB
C++
// Copyright (c) 2014, 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.
|
|
|
|
#include "port/likely.h"
|
|
#include "util/mutexlock.h"
|
|
#include "util/thread_status_updater.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
#if ROCKSDB_USING_THREAD_STATUS
|
|
|
|
__thread ThreadStatusData* ThreadStatusUpdater::thread_status_data_ = nullptr;
|
|
|
|
void ThreadStatusUpdater::UnregisterThread() {
|
|
if (thread_status_data_ != nullptr) {
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
thread_data_set_.erase(thread_status_data_);
|
|
delete thread_status_data_;
|
|
thread_status_data_ = nullptr;
|
|
}
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetThreadType(
|
|
ThreadStatus::ThreadType ttype) {
|
|
auto* data = InitAndGet();
|
|
data->thread_type.store(ttype, std::memory_order_relaxed);
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetColumnFamilyInfoKey(
|
|
const void* cf_key) {
|
|
auto* data = InitAndGet();
|
|
data->cf_key.store(cf_key, std::memory_order_relaxed);
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetEventInfoPtr(
|
|
const ThreadEventInfo* event_info) {
|
|
auto* data = InitAndGet();
|
|
data->event_info.store(event_info, std::memory_order_relaxed);
|
|
}
|
|
|
|
Status ThreadStatusUpdater::GetThreadList(
|
|
std::vector<ThreadStatus>* thread_list) {
|
|
thread_list->clear();
|
|
std::vector<std::shared_ptr<ThreadStatusData>> valid_list;
|
|
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
for (auto* thread_data : thread_data_set_) {
|
|
assert(thread_data);
|
|
auto thread_type = thread_data->thread_type.load(
|
|
std::memory_order_relaxed);
|
|
auto cf_key = thread_data->cf_key.load(
|
|
std::memory_order_relaxed);
|
|
auto iter = cf_info_map_.find(cf_key);
|
|
assert(cf_key == 0 || iter != cf_info_map_.end());
|
|
auto* cf_info = iter != cf_info_map_.end() ?
|
|
iter->second.get() : nullptr;
|
|
auto* event_info = thread_data->event_info.load(
|
|
std::memory_order_relaxed);
|
|
const std::string* db_name = nullptr;
|
|
const std::string* cf_name = nullptr;
|
|
const std::string* event_name = nullptr;
|
|
if (cf_info != nullptr) {
|
|
db_name = &cf_info->db_name;
|
|
cf_name = &cf_info->cf_name;
|
|
// display lower-level info only when higher-level info is available.
|
|
if (event_info != nullptr) {
|
|
event_name = &event_info->event_name;
|
|
}
|
|
}
|
|
thread_list->emplace_back(
|
|
thread_data->thread_id, thread_type,
|
|
db_name ? *db_name : "",
|
|
cf_name ? *cf_name : "",
|
|
event_name ? *event_name : "");
|
|
}
|
|
|
|
return Status::OK();
|
|
}
|
|
|
|
ThreadStatusData* ThreadStatusUpdater::InitAndGet() {
|
|
if (UNLIKELY(thread_status_data_ == nullptr)) {
|
|
thread_status_data_ = new ThreadStatusData();
|
|
thread_status_data_->thread_id = reinterpret_cast<uint64_t>(
|
|
thread_status_data_);
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
thread_data_set_.insert(thread_status_data_);
|
|
}
|
|
return thread_status_data_;
|
|
}
|
|
|
|
void ThreadStatusUpdater::NewColumnFamilyInfo(
|
|
const void* db_key, const std::string& db_name,
|
|
const void* cf_key, const std::string& cf_name) {
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
|
|
cf_info_map_[cf_key].reset(
|
|
new ConstantColumnFamilyInfo(db_key, db_name, cf_name));
|
|
db_key_map_[db_key].insert(cf_key);
|
|
}
|
|
|
|
void ThreadStatusUpdater::EraseColumnFamilyInfo(const void* cf_key) {
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
auto cf_pair = cf_info_map_.find(cf_key);
|
|
assert(cf_pair != cf_info_map_.end());
|
|
|
|
auto* cf_info = cf_pair->second.get();
|
|
assert(cf_info);
|
|
|
|
// Remove its entry from db_key_map_ by the following steps:
|
|
// 1. Obtain the entry in db_key_map_ whose set contains cf_key
|
|
// 2. Remove it from the set.
|
|
auto db_pair = db_key_map_.find(cf_info->db_key);
|
|
assert(db_pair != db_key_map_.end());
|
|
size_t result __attribute__((unused)) = db_pair->second.erase(cf_key);
|
|
assert(result);
|
|
|
|
cf_pair->second.reset();
|
|
result = cf_info_map_.erase(cf_key);
|
|
assert(result);
|
|
}
|
|
|
|
void ThreadStatusUpdater::EraseDatabaseInfo(const void* db_key) {
|
|
std::lock_guard<std::mutex> lck(thread_list_mutex_);
|
|
auto db_pair = db_key_map_.find(db_key);
|
|
if (UNLIKELY(db_pair == db_key_map_.end())) {
|
|
// In some occasional cases such as DB::Open fails, we won't
|
|
// register ColumnFamilyInfo for a db.
|
|
return;
|
|
}
|
|
|
|
size_t result __attribute__((unused)) = 0;
|
|
for (auto cf_key : db_pair->second) {
|
|
auto cf_pair = cf_info_map_.find(cf_key);
|
|
assert(cf_pair != cf_info_map_.end());
|
|
cf_pair->second.reset();
|
|
result = cf_info_map_.erase(cf_key);
|
|
assert(result);
|
|
}
|
|
db_key_map_.erase(db_key);
|
|
}
|
|
|
|
#else
|
|
|
|
void ThreadStatusUpdater::UnregisterThread() {
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetThreadType(
|
|
ThreadStatus::ThreadType ttype) {
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetColumnFamilyInfoKey(
|
|
const void* cf_key) {
|
|
}
|
|
|
|
void ThreadStatusUpdater::SetEventInfoPtr(
|
|
const ThreadEventInfo* event_info) {
|
|
}
|
|
|
|
Status ThreadStatusUpdater::GetThreadList(
|
|
std::vector<ThreadStatus>* thread_list) {
|
|
return Status::NotSupported(
|
|
"GetThreadList is not supported in the current running environment.");
|
|
}
|
|
|
|
void ThreadStatusUpdater::NewColumnFamilyInfo(
|
|
const void* db_key, const std::string& db_name,
|
|
const void* cf_key, const std::string& cf_name) {
|
|
}
|
|
|
|
void ThreadStatusUpdater::EraseColumnFamilyInfo(const void* cf_key) {
|
|
}
|
|
|
|
void ThreadStatusUpdater::EraseDatabaseInfo(const void* db_key) {
|
|
}
|
|
|
|
#endif // ROCKSDB_USING_THREAD_STATUS
|
|
} // namespace rocksdb
|