mirror of
https://github.com/google/leveldb.git
synced 2025-01-01 04:20:11 +08:00
Rework once initialization in env_posix.cc.
C++11 guarantees thread-safe initialization of static variables inside functions. This is a more restricted form of std::call_once or pthread_once_t (e.g., single call site), so the compiler might be able to generate better code [1]. Equally important, having less platform-dependent code in env_posix.cc makes it easier to port to other platforms. Due to the change above, this CL introduced a new approach for storing the singleton PosixEnv instance returned by Env::Default(). The new approach avoids a dynamic memory allocation, which eliminates the false positive from LeakSanitizer reported in https://github.com/google/leveldb/issues/539 and https://github.com/google/leveldb/issues/113 [1] https://stackoverflow.com/a/27206650/ ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=214293129
This commit is contained in:
parent
c43565dd39
commit
a7dc502e9f
@ -17,18 +17,21 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "leveldb/env.h"
|
#include "leveldb/env.h"
|
||||||
#include "leveldb/slice.h"
|
#include "leveldb/slice.h"
|
||||||
|
#include "leveldb/status.h"
|
||||||
#include "port/port.h"
|
#include "port/port.h"
|
||||||
#include "port/thread_annotations.h"
|
#include "port/thread_annotations.h"
|
||||||
#include "util/logging.h"
|
|
||||||
#include "util/mutexlock.h"
|
|
||||||
#include "util/posix_logger.h"
|
#include "util/posix_logger.h"
|
||||||
#include "util/env_posix_test_helper.h"
|
#include "util/env_posix_test_helper.h"
|
||||||
|
|
||||||
@ -401,12 +404,15 @@ class PosixLockTable {
|
|||||||
std::set<std::string> locked_files_ GUARDED_BY(mu_);
|
std::set<std::string> locked_files_ GUARDED_BY(mu_);
|
||||||
public:
|
public:
|
||||||
bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
|
bool Insert(const std::string& fname) LOCKS_EXCLUDED(mu_) {
|
||||||
MutexLock l(&mu_);
|
mu_.Lock();
|
||||||
return locked_files_.insert(fname).second;
|
bool succeeded = locked_files_.insert(fname).second;
|
||||||
|
mu_.Unlock();
|
||||||
|
return succeeded;
|
||||||
}
|
}
|
||||||
void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
|
void Remove(const std::string& fname) LOCKS_EXCLUDED(mu_) {
|
||||||
MutexLock l(&mu_);
|
mu_.Lock();
|
||||||
locked_files_.erase(fname);
|
locked_files_.erase(fname);
|
||||||
|
mu_.Unlock();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -693,7 +699,7 @@ PosixEnv::PosixEnv()
|
|||||||
void PosixEnv::Schedule(
|
void PosixEnv::Schedule(
|
||||||
void (*background_work_function)(void* background_work_arg),
|
void (*background_work_function)(void* background_work_arg),
|
||||||
void* background_work_arg) {
|
void* background_work_arg) {
|
||||||
MutexLock lock(&background_work_mutex_);
|
background_work_mutex_.Lock();
|
||||||
|
|
||||||
// Start the background thread, if we haven't done so already.
|
// Start the background thread, if we haven't done so already.
|
||||||
if (!started_background_thread_) {
|
if (!started_background_thread_) {
|
||||||
@ -708,6 +714,7 @@ void PosixEnv::Schedule(
|
|||||||
}
|
}
|
||||||
|
|
||||||
background_work_queue_.emplace(background_work_function, background_work_arg);
|
background_work_queue_.emplace(background_work_function, background_work_arg);
|
||||||
|
background_work_mutex_.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PosixEnv::BackgroundThreadMain() {
|
void PosixEnv::BackgroundThreadMain() {
|
||||||
@ -730,6 +737,59 @@ void PosixEnv::BackgroundThreadMain() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wraps an Env instance whose destructor is never created.
|
||||||
|
//
|
||||||
|
// Intended usage:
|
||||||
|
// using PlatformSingletonEnv = SingletonEnv<PlatformEnv>;
|
||||||
|
// void ConfigurePosixEnv(int param) {
|
||||||
|
// PlatformSingletonEnv::AssertEnvNotInitialized();
|
||||||
|
// // set global configuration flags.
|
||||||
|
// }
|
||||||
|
// Env* Env::Default() {
|
||||||
|
// static PlatformSingletonEnv default_env;
|
||||||
|
// return default_env.env();
|
||||||
|
// }
|
||||||
|
template<typename EnvType>
|
||||||
|
class SingletonEnv {
|
||||||
|
public:
|
||||||
|
SingletonEnv() {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
env_initialized_.store(true, std::memory_order::memory_order_relaxed);
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
|
static_assert(sizeof(env_storage_) >= sizeof(EnvType),
|
||||||
|
"env_storage_ will not fit the Env");
|
||||||
|
static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),
|
||||||
|
"env_storage_ does not meet the Env's alignment needs");
|
||||||
|
new (&env_storage_) EnvType();
|
||||||
|
}
|
||||||
|
~SingletonEnv() = default;
|
||||||
|
|
||||||
|
SingletonEnv(const SingletonEnv&) = delete;
|
||||||
|
SingletonEnv& operator=(const SingletonEnv&) = delete;
|
||||||
|
|
||||||
|
Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
|
||||||
|
|
||||||
|
static void AssertEnvNotInitialized() {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
assert(!env_initialized_.load(std::memory_order::memory_order_relaxed));
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type
|
||||||
|
env_storage_;
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
static std::atomic<bool> env_initialized_;
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
template<typename EnvType>
|
||||||
|
std::atomic<bool> SingletonEnv<EnvType>::env_initialized_;
|
||||||
|
#endif // !defined(NDEBUG)
|
||||||
|
|
||||||
|
using PosixDefaultEnv = SingletonEnv<PosixEnv>;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
|
void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
|
||||||
@ -738,23 +798,19 @@ void PosixEnv::StartThread(void (*thread_main)(void* thread_main_arg),
|
|||||||
new_thread.detach();
|
new_thread.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
|
||||||
static Env* default_env;
|
|
||||||
static void InitDefaultEnv() { default_env = new PosixEnv; }
|
|
||||||
|
|
||||||
void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
|
void EnvPosixTestHelper::SetReadOnlyFDLimit(int limit) {
|
||||||
assert(default_env == nullptr);
|
PosixDefaultEnv::AssertEnvNotInitialized();
|
||||||
open_read_only_file_limit = limit;
|
open_read_only_file_limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
|
void EnvPosixTestHelper::SetReadOnlyMMapLimit(int limit) {
|
||||||
assert(default_env == nullptr);
|
PosixDefaultEnv::AssertEnvNotInitialized();
|
||||||
mmap_limit = limit;
|
mmap_limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
Env* Env::Default() {
|
Env* Env::Default() {
|
||||||
pthread_once(&once, InitDefaultEnv);
|
static PosixDefaultEnv env_container;
|
||||||
return default_env;
|
return env_container.env();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace leveldb
|
} // namespace leveldb
|
||||||
|
Loading…
Reference in New Issue
Block a user