From d177a0263cce4344d05188521ad53459c369b940 Mon Sep 17 00:00:00 2001 From: costan Date: Tue, 17 Apr 2018 13:23:10 -0700 Subject: [PATCH] Replace port_posix with port_stdcxx. The porting layer implements threading primitives: atomic pointers, condition variables, mutexes, thread-safe initialization. These are all specified in C++11, so the reference open source port implementation can become platform-independent. The porting layer will remain in place to allow the use of other implementations with more features, such as the built-in deadlock detection in abseil's Mutex. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=193245934 --- CMakeLists.txt | 64 ++++++------------------ port/README | 2 +- port/port.h | 2 +- port/port_posix.cc | 53 -------------------- port/port_posix.h | 130 ------------------------------------------------- port/port_stdcxx.h | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++ util/env_posix.cc | 6 +++ 7 files changed, 164 insertions(+), 233 deletions(-) delete mode 100644 port/port_posix.cc delete mode 100644 port/port_posix.h create mode 100644 port/port_stdcxx.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5588120..4bf3df3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,33 +79,10 @@ if(BUILD_SHARED_LIBS) add_compile_options(-fvisibility=hidden) endif(BUILD_SHARED_LIBS) -# POSIX code is specified separately so we can leave it out in the future. -add_library(leveldb_port_posix OBJECT "") -target_sources(leveldb_port_posix - PRIVATE - "${PROJECT_SOURCE_DIR}/port/port_posix.cc" - - PUBLIC - # The headers below are dependencies for leveldb, but aren't needed by users - # that link to the installed version of leveldb and rely on its public API. - $ - $ - $ - $ -) -if (NOT HAVE_CXX17_HAS_INCLUDE) - target_compile_definitions(leveldb_port_posix - PRIVATE - LEVELDB_HAS_PORT_CONFIG_H=1 - ) -endif(NOT HAVE_CXX17_HAS_INCLUDE) -if(BUILD_SHARED_LIBS) - set_property(TARGET leveldb_port_posix PROPERTY POSITION_INDEPENDENT_CODE ON) -endif(BUILD_SHARED_LIBS) - add_library(leveldb "") target_sources(leveldb PRIVATE + "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h" "${PROJECT_SOURCE_DIR}/db/builder.cc" "${PROJECT_SOURCE_DIR}/db/builder.h" "${PROJECT_SOURCE_DIR}/db/c.cc" @@ -136,6 +113,8 @@ target_sources(leveldb "${PROJECT_SOURCE_DIR}/db/version_set.h" "${PROJECT_SOURCE_DIR}/db/write_batch_internal.h" "${PROJECT_SOURCE_DIR}/db/write_batch.cc" + "${PROJECT_SOURCE_DIR}/port/atomic_pointer.h" + "${PROJECT_SOURCE_DIR}/port/port_stdcxx.h" "${PROJECT_SOURCE_DIR}/port/port.h" "${PROJECT_SOURCE_DIR}/port/thread_annotations.h" "${PROJECT_SOURCE_DIR}/table/block_builder.cc" @@ -163,7 +142,6 @@ target_sources(leveldb "${PROJECT_SOURCE_DIR}/util/comparator.cc" "${PROJECT_SOURCE_DIR}/util/crc32c.cc" "${PROJECT_SOURCE_DIR}/util/crc32c.h" - "${PROJECT_SOURCE_DIR}/util/env_posix.cc" "${PROJECT_SOURCE_DIR}/util/env.cc" "${PROJECT_SOURCE_DIR}/util/filter_policy.cc" "${PROJECT_SOURCE_DIR}/util/hash.cc" @@ -172,10 +150,8 @@ target_sources(leveldb "${PROJECT_SOURCE_DIR}/util/logging.h" "${PROJECT_SOURCE_DIR}/util/mutexlock.h" "${PROJECT_SOURCE_DIR}/util/options.cc" - "${PROJECT_SOURCE_DIR}/util/posix_logger.h" "${PROJECT_SOURCE_DIR}/util/random.h" "${PROJECT_SOURCE_DIR}/util/status.cc" - $ # Only CMake 3.3+ supports PUBLIC sources in targets exported by "install". $<$:PUBLIC> @@ -195,12 +171,21 @@ target_sources(leveldb "${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h" "${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h" ) + +# POSIX code is specified separately so we can leave it out in the future. +target_sources(leveldb + PRIVATE + "${PROJECT_SOURCE_DIR}/util/env_posix.cc" + "${PROJECT_SOURCE_DIR}/util/posix_logger.h" +) + # MemEnv is not part of the interface and could be pulled to a separate library. target_sources(leveldb PRIVATE "${PROJECT_SOURCE_DIR}/helpers/memenv/memenv.cc" "${PROJECT_SOURCE_DIR}/helpers/memenv/memenv.h" ) + target_include_directories(leveldb PUBLIC $ @@ -234,11 +219,6 @@ if(HAVE_CLANG_THREAD_SAFETY) -Werror -Wthread-safety) endif(HAVE_CLANG_THREAD_SAFETY) -# TODO(costan): This is only needed for port_posix. -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) -target_link_libraries(leveldb Threads::Threads) - if(HAVE_CRC32C) target_link_libraries(leveldb crc32c) endif(HAVE_CRC32C) @@ -249,6 +229,10 @@ if(HAVE_TCMALLOC) target_link_libraries(leveldb tcmalloc) endif(HAVE_TCMALLOC) +# Needed by port_stdcxx.h +find_package(Threads REQUIRED) +target_link_libraries(leveldb Threads::Threads) + add_executable(leveldbutil "${PROJECT_SOURCE_DIR}/db/leveldbutil.cc" ) @@ -271,14 +255,6 @@ if(LEVELDB_BUILD_TESTS) "${test_file}" ) - if(BUILD_SHARED_LIBS) - # Port functions aren't exposed in the shared library build. - target_sources("${test_target_name}" - PRIVATE - $ - ) - endif(BUILD_SHARED_LIBS) - target_link_libraries("${test_target_name}" leveldb) target_compile_definitions("${test_target_name}" PRIVATE @@ -351,14 +327,6 @@ if(LEVELDB_BUILD_BENCHMARKS) "${bench_file}" ) - if(BUILD_SHARED_LIBS) - # Port functions aren't exposed in the shared library build. - target_sources("${bench_target_name}" - PRIVATE - $ - ) - endif(BUILD_SHARED_LIBS) - target_link_libraries("${bench_target_name}" leveldb) target_compile_definitions("${bench_target_name}" PRIVATE diff --git a/port/README b/port/README index 422563e..8b17153 100644 --- a/port/README +++ b/port/README @@ -5,6 +5,6 @@ Code in the rest of the package includes "port.h" from this directory. "port.h" in turn includes a platform specific "port_.h" file that provides the platform specific implementation. -See port_posix.h for an example of what must be provided in a platform +See port_stdcxx.h for an example of what must be provided in a platform specific header file. diff --git a/port/port.h b/port/port.h index e667db4..0975fed 100644 --- a/port/port.h +++ b/port/port.h @@ -11,7 +11,7 @@ // porting to a new platform, see "port_example.h" for documentation // of what the new port_.h file must provide. #if defined(LEVELDB_PLATFORM_POSIX) -# include "port/port_posix.h" +# include "port/port_stdcxx.h" #elif defined(LEVELDB_PLATFORM_CHROMIUM) # include "port/port_chromium.h" #endif diff --git a/port/port_posix.cc b/port/port_posix.cc deleted file mode 100644 index 04095bb..0000000 --- a/port/port_posix.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. - -#include "port/port_posix.h" - -#include -#include -#include - -namespace leveldb { -namespace port { - -static void PthreadCall(const char* label, int result) { - if (result != 0) { - fprintf(stderr, "pthread %s: %s\n", label, strerror(result)); - abort(); - } -} - -Mutex::Mutex() { PthreadCall("init mutex", pthread_mutex_init(&mu_, nullptr)); } - -Mutex::~Mutex() { PthreadCall("destroy mutex", pthread_mutex_destroy(&mu_)); } - -void Mutex::Lock() { PthreadCall("lock", pthread_mutex_lock(&mu_)); } - -void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } - -CondVar::CondVar(Mutex* mu) - : mu_(mu) { - PthreadCall("init cv", pthread_cond_init(&cv_, nullptr)); -} - -CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } - -void CondVar::Wait() { - PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); -} - -void CondVar::Signal() { - PthreadCall("signal", pthread_cond_signal(&cv_)); -} - -void CondVar::SignalAll() { - PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); -} - -void InitOnce(OnceType* once, void (*initializer)()) { - PthreadCall("once", pthread_once(once, initializer)); -} - -} // namespace port -} // namespace leveldb diff --git a/port/port_posix.h b/port/port_posix.h deleted file mode 100644 index 54b07b6..0000000 --- a/port/port_posix.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2011 The LevelDB Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. See the AUTHORS file for names of contributors. -// -// See port_example.h for documentation for the following types/functions. - -#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_ -#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_ - -// port/port_config.h availability is automatically detected via __has_include -// in newer compilers. If LEVELDB_HAS_PORT_CONFIG_H is defined, it overrides the -// configuration detection. -#if defined(LEVELDB_HAS_PORT_CONFIG_H) - -#if LEVELDB_HAS_PORT_CONFIG_H -#include "port/port_config.h" -#endif // LEVELDB_HAS_PORT_CONFIG_H - -#elif defined(__has_include) - -#if __has_include("port/port_config.h") -#include "port/port_config.h" -#endif // __has_include("port/port_config.h") - -#endif // defined(LEVELDB_HAS_PORT_CONFIG_H) - -#include -#if HAVE_CRC32C -#include -#endif // HAVE_CRC32C -#if HAVE_SNAPPY -#include -#endif // HAVE_SNAPPY -#include -#include -#include "port/atomic_pointer.h" -#include "port/thread_annotations.h" - -#if !HAVE_FDATASYNC -#define fdatasync fsync -#endif // !HAVE_FDATASYNC - -namespace leveldb { -namespace port { - -static const bool kLittleEndian = !LEVELDB_IS_BIG_ENDIAN; - -class CondVar; - -class LOCKABLE Mutex { - public: - Mutex(); - ~Mutex(); - - void Lock() EXCLUSIVE_LOCK_FUNCTION(); - void Unlock() UNLOCK_FUNCTION(); - void AssertHeld() ASSERT_EXCLUSIVE_LOCK() { } - - private: - friend class CondVar; - pthread_mutex_t mu_; - - // No copying - Mutex(const Mutex&); - void operator=(const Mutex&); -}; - -class CondVar { - public: - explicit CondVar(Mutex* mu); - ~CondVar(); - void Wait(); - void Signal(); - void SignalAll(); - private: - pthread_cond_t cv_; - Mutex* mu_; -}; - -typedef pthread_once_t OnceType; -#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT -void InitOnce(OnceType* once, void (*initializer)()); - -inline bool Snappy_Compress(const char* input, size_t length, - ::std::string* output) { -#if HAVE_SNAPPY - output->resize(snappy::MaxCompressedLength(length)); - size_t outlen; - snappy::RawCompress(input, length, &(*output)[0], &outlen); - output->resize(outlen); - return true; -#endif // HAVE_SNAPPY - - return false; -} - -inline bool Snappy_GetUncompressedLength(const char* input, size_t length, - size_t* result) { -#if HAVE_SNAPPY - return snappy::GetUncompressedLength(input, length, result); -#else - return false; -#endif // HAVE_SNAPPY -} - -inline bool Snappy_Uncompress(const char* input, size_t length, - char* output) { -#if HAVE_SNAPPY - return snappy::RawUncompress(input, length, output); -#else - return false; -#endif // HAVE_SNAPPY -} - -inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { - return false; -} - -inline uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { -#if HAVE_CRC32C - return ::crc32c::Extend(crc, reinterpret_cast(buf), size); -#else - return 0; -#endif // HAVE_CRC32C -} - -} // namespace port -} // namespace leveldb - -#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_ diff --git a/port/port_stdcxx.h b/port/port_stdcxx.h new file mode 100644 index 0000000..4e58cba --- /dev/null +++ b/port/port_stdcxx.h @@ -0,0 +1,140 @@ +// Copyright (c) 2018 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + +#ifndef STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ +#define STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ + +// port/port_config.h availability is automatically detected via __has_include +// in newer compilers. If LEVELDB_HAS_PORT_CONFIG_H is defined, it overrides the +// configuration detection. +#if defined(LEVELDB_HAS_PORT_CONFIG_H) + +#if LEVELDB_HAS_PORT_CONFIG_H +#include "port/port_config.h" +#endif // LEVELDB_HAS_PORT_CONFIG_H + +#elif defined(__has_include) + +#if __has_include("port/port_config.h") +#include "port/port_config.h" +#endif // __has_include("port/port_config.h") + +#endif // defined(LEVELDB_HAS_PORT_CONFIG_H) + +#if HAVE_CRC32C +#include +#endif // HAVE_CRC32C +#if HAVE_SNAPPY +#include +#endif // HAVE_SNAPPY + +#include +#include +#include +#include // NOLINT +#include // NOLINT +#include +#include "port/atomic_pointer.h" +#include "port/thread_annotations.h" + +namespace leveldb { +namespace port { + +static const bool kLittleEndian = !LEVELDB_IS_BIG_ENDIAN; + +class CondVar; + +// Thinly wraps std::mutex. +class LOCKABLE Mutex { + public: + Mutex() = default; + ~Mutex() = default; + + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu_.lock(); } + void Unlock() UNLOCK_FUNCTION() { mu_.unlock(); } + void AssertHeld() ASSERT_EXCLUSIVE_LOCK() { } + + private: + friend class CondVar; + std::mutex mu_; +}; + +// Thinly wraps std::condition_variable. +class CondVar { + public: + explicit CondVar(Mutex* mu) : mu_(mu) { assert(mu != nullptr); } + ~CondVar() = default; + + CondVar(const CondVar&) = delete; + CondVar& operator=(const CondVar&) = delete; + + void Wait() { + std::unique_lock lock(mu_->mu_, std::adopt_lock); + cv_.wait(lock); + lock.release(); + } + void Signal() { cv_.notify_one(); } + void SignalAll() { cv_.notify_all(); } + private: + std::condition_variable cv_; + Mutex* const mu_; +}; + +using OnceType = std::once_flag; +#define LEVELDB_ONCE_INIT {} + +// Thinly wraps std::call_once. +inline void InitOnce(OnceType* once, void (*initializer)()) { + std::call_once(*once, *initializer); +} + +inline bool Snappy_Compress(const char* input, size_t length, + ::std::string* output) { +#if HAVE_SNAPPY + output->resize(snappy::MaxCompressedLength(length)); + size_t outlen; + snappy::RawCompress(input, length, &(*output)[0], &outlen); + output->resize(outlen); + return true; +#endif // HAVE_SNAPPY + + return false; +} + +inline bool Snappy_GetUncompressedLength(const char* input, size_t length, + size_t* result) { +#if HAVE_SNAPPY + return snappy::GetUncompressedLength(input, length, result); +#else + return false; +#endif // HAVE_SNAPPY +} + +inline bool Snappy_Uncompress(const char* input, size_t length, char* output) { +#if HAVE_SNAPPY + return snappy::RawUncompress(input, length, output); +#else + return false; +#endif // HAVE_SNAPPY +} + +inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { + return false; +} + +inline uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { +#if HAVE_CRC32C + return ::crc32c::Extend(crc, reinterpret_cast(buf), size); +#else + return 0; +#endif // HAVE_CRC32C +} + +} // namespace port +} // namespace leveldb + +#endif // STORAGE_LEVELDB_PORT_PORT_STDCXX_H_ diff --git a/util/env_posix.cc b/util/env_posix.cc index e758d5f..51844ad 100644 --- a/util/env_posix.cc +++ b/util/env_posix.cc @@ -28,6 +28,12 @@ #include "util/posix_logger.h" #include "util/env_posix_test_helper.h" +// HAVE_FDATASYNC is defined in the auto-generated port_config.h, which is +// included by port_stdcxx.h. +#if !HAVE_FDATASYNC +#define fdatasync fsync +#endif // !HAVE_FDATASYNC + namespace leveldb { namespace {