diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/arena_test.cc | 6 | ||||
-rw-r--r-- | util/bloom_test.cc | 28 | ||||
-rw-r--r-- | util/cache.cc | 11 | ||||
-rw-r--r-- | util/cache_test.cc | 28 | ||||
-rw-r--r-- | util/coding.h | 50 | ||||
-rw-r--r-- | util/coding_test.cc | 9 | ||||
-rw-r--r-- | util/crc32c.cc | 4 | ||||
-rw-r--r-- | util/crc32c.h | 4 | ||||
-rw-r--r-- | util/crc32c_test.cc | 7 | ||||
-rw-r--r-- | util/env.cc | 20 | ||||
-rw-r--r-- | util/env_posix.cc | 55 | ||||
-rw-r--r-- | util/env_posix_test.cc | 93 | ||||
-rw-r--r-- | util/env_test.cc | 78 | ||||
-rw-r--r-- | util/env_windows.cc | 40 | ||||
-rw-r--r-- | util/env_windows_test.cc | 23 | ||||
-rw-r--r-- | util/hash.cc | 2 | ||||
-rw-r--r-- | util/hash.h | 4 | ||||
-rw-r--r-- | util/hash_test.cc | 7 | ||||
-rw-r--r-- | util/histogram.cc | 24 | ||||
-rw-r--r-- | util/logging.cc | 14 | ||||
-rw-r--r-- | util/logging.h | 5 | ||||
-rw-r--r-- | util/logging_test.cc | 9 | ||||
-rw-r--r-- | util/no_destructor_test.cc | 9 | ||||
-rw-r--r-- | util/posix_logger.h | 8 | ||||
-rw-r--r-- | util/random.h | 2 | ||||
-rw-r--r-- | util/status.cc | 18 | ||||
-rw-r--r-- | util/status_test.cc | 7 | ||||
-rw-r--r-- | util/testharness.cc | 81 | ||||
-rw-r--r-- | util/testharness.h | 141 | ||||
-rw-r--r-- | util/testutil.cc | 2 | ||||
-rw-r--r-- | util/testutil.h | 16 | ||||
-rw-r--r-- | util/windows_logger.h | 8 |
32 files changed, 304 insertions, 509 deletions
diff --git a/util/arena_test.cc b/util/arena_test.cc index e917228..3e2011e 100644 --- a/util/arena_test.cc +++ b/util/arena_test.cc @@ -4,13 +4,11 @@ #include "util/arena.h" +#include "gtest/gtest.h" #include "util/random.h" -#include "util/testharness.h" namespace leveldb { -class ArenaTest {}; - TEST(ArenaTest, Empty) { Arena arena; } TEST(ArenaTest, Simple) { @@ -61,5 +59,3 @@ TEST(ArenaTest, Simple) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/bloom_test.cc b/util/bloom_test.cc index 436daa9..9f11108 100644 --- a/util/bloom_test.cc +++ b/util/bloom_test.cc @@ -2,11 +2,10 @@ // 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 "gtest/gtest.h" #include "leveldb/filter_policy.h" - #include "util/coding.h" #include "util/logging.h" -#include "util/testharness.h" #include "util/testutil.h" namespace leveldb { @@ -18,7 +17,7 @@ static Slice Key(int i, char* buffer) { return Slice(buffer, sizeof(uint32_t)); } -class BloomTest { +class BloomTest : public testing::Test { public: BloomTest() : policy_(NewBloomFilterPolicy(10)) {} @@ -46,14 +45,14 @@ class BloomTest { size_t FilterSize() const { return filter_.size(); } void DumpFilter() { - fprintf(stderr, "F("); + std::fprintf(stderr, "F("); for (size_t i = 0; i + 1 < filter_.size(); i++) { const unsigned int c = static_cast<unsigned int>(filter_[i]); for (int j = 0; j < 8; j++) { - fprintf(stderr, "%c", (c & (1 << j)) ? '1' : '.'); + std::fprintf(stderr, "%c", (c & (1 << j)) ? '1' : '.'); } } - fprintf(stderr, ")\n"); + std::fprintf(stderr, ")\n"); } bool Matches(const Slice& s) { @@ -80,12 +79,12 @@ class BloomTest { std::vector<std::string> keys_; }; -TEST(BloomTest, EmptyFilter) { +TEST_F(BloomTest, EmptyFilter) { ASSERT_TRUE(!Matches("hello")); ASSERT_TRUE(!Matches("world")); } -TEST(BloomTest, Small) { +TEST_F(BloomTest, Small) { Add("hello"); Add("world"); ASSERT_TRUE(Matches("hello")); @@ -107,7 +106,7 @@ static int NextLength(int length) { return length; } -TEST(BloomTest, VaryingLengths) { +TEST_F(BloomTest, VaryingLengths) { char buffer[sizeof(int)]; // Count number of filters that significantly exceed the false positive rate @@ -133,8 +132,9 @@ TEST(BloomTest, VaryingLengths) { // Check false positive rate double rate = FalsePositiveRate(); if (kVerbose >= 1) { - fprintf(stderr, "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", - rate * 100.0, length, static_cast<int>(FilterSize())); + std::fprintf(stderr, + "False positives: %5.2f%% @ length = %6d ; bytes = %6d\n", + rate * 100.0, length, static_cast<int>(FilterSize())); } ASSERT_LE(rate, 0.02); // Must not be over 2% if (rate > 0.0125) @@ -143,8 +143,8 @@ TEST(BloomTest, VaryingLengths) { good_filters++; } if (kVerbose >= 1) { - fprintf(stderr, "Filters: %d good, %d mediocre\n", good_filters, - mediocre_filters); + std::fprintf(stderr, "Filters: %d good, %d mediocre\n", good_filters, + mediocre_filters); } ASSERT_LE(mediocre_filters, good_filters / 5); } @@ -152,5 +152,3 @@ TEST(BloomTest, VaryingLengths) { // Different bits-per-byte } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/cache.cc b/util/cache.cc index 12de306..ad1e9a2 100644 --- a/util/cache.cc +++ b/util/cache.cc @@ -2,11 +2,12 @@ // 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 <assert.h> -#include <stdio.h> -#include <stdlib.h> - #include "leveldb/cache.h" + +#include <cassert> +#include <cstdio> +#include <cstdlib> + #include "port/port.h" #include "port/thread_annotations.h" #include "util/hash.h" @@ -278,7 +279,7 @@ Cache::Handle* LRUCache::Insert(const Slice& key, uint32_t hash, void* value, e->hash = hash; e->in_cache = false; e->refs = 1; // for the returned handle. - memcpy(e->key_data, key.data(), key.size()); + std::memcpy(e->key_data, key.data(), key.size()); if (capacity_ > 0) { e->refs++; // for the cache's reference. diff --git a/util/cache_test.cc b/util/cache_test.cc index 974334b..e68da34 100644 --- a/util/cache_test.cc +++ b/util/cache_test.cc @@ -5,8 +5,9 @@ #include "leveldb/cache.h" #include <vector> + +#include "gtest/gtest.h" #include "util/coding.h" -#include "util/testharness.h" namespace leveldb { @@ -23,14 +24,14 @@ static int DecodeKey(const Slice& k) { static void* EncodeValue(uintptr_t v) { return reinterpret_cast<void*>(v); } static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v); } -class CacheTest { +class CacheTest : public testing::Test { public: static void Deleter(const Slice& key, void* v) { current_->deleted_keys_.push_back(DecodeKey(key)); current_->deleted_values_.push_back(DecodeValue(v)); } - static const int kCacheSize = 1000; + static constexpr int kCacheSize = 1000; std::vector<int> deleted_keys_; std::vector<int> deleted_values_; Cache* cache_; @@ -59,12 +60,11 @@ class CacheTest { } void Erase(int key) { cache_->Erase(EncodeKey(key)); } - static CacheTest* current_; }; CacheTest* CacheTest::current_; -TEST(CacheTest, HitAndMiss) { +TEST_F(CacheTest, HitAndMiss) { ASSERT_EQ(-1, Lookup(100)); Insert(100, 101); @@ -87,7 +87,7 @@ TEST(CacheTest, HitAndMiss) { ASSERT_EQ(101, deleted_values_[0]); } -TEST(CacheTest, Erase) { +TEST_F(CacheTest, Erase) { Erase(200); ASSERT_EQ(0, deleted_keys_.size()); @@ -106,7 +106,7 @@ TEST(CacheTest, Erase) { ASSERT_EQ(1, deleted_keys_.size()); } -TEST(CacheTest, EntriesArePinned) { +TEST_F(CacheTest, EntriesArePinned) { Insert(100, 101); Cache::Handle* h1 = cache_->Lookup(EncodeKey(100)); ASSERT_EQ(101, DecodeValue(cache_->Value(h1))); @@ -131,7 +131,7 @@ TEST(CacheTest, EntriesArePinned) { ASSERT_EQ(102, deleted_values_[1]); } -TEST(CacheTest, EvictionPolicy) { +TEST_F(CacheTest, EvictionPolicy) { Insert(100, 101); Insert(200, 201); Insert(300, 301); @@ -150,7 +150,7 @@ TEST(CacheTest, EvictionPolicy) { cache_->Release(h); } -TEST(CacheTest, UseExceedsCacheSize) { +TEST_F(CacheTest, UseExceedsCacheSize) { // Overfill the cache, keeping handles on all inserted entries. std::vector<Cache::Handle*> h; for (int i = 0; i < kCacheSize + 100; i++) { @@ -167,7 +167,7 @@ TEST(CacheTest, UseExceedsCacheSize) { } } -TEST(CacheTest, HeavyEntries) { +TEST_F(CacheTest, HeavyEntries) { // Add a bunch of light and heavy entries and then count the combined // size of items still in the cache, which must be approximately the // same as the total capacity. @@ -194,13 +194,13 @@ TEST(CacheTest, HeavyEntries) { ASSERT_LE(cached_weight, kCacheSize + kCacheSize / 10); } -TEST(CacheTest, NewId) { +TEST_F(CacheTest, NewId) { uint64_t a = cache_->NewId(); uint64_t b = cache_->NewId(); ASSERT_NE(a, b); } -TEST(CacheTest, Prune) { +TEST_F(CacheTest, Prune) { Insert(1, 100); Insert(2, 200); @@ -213,7 +213,7 @@ TEST(CacheTest, Prune) { ASSERT_EQ(-1, Lookup(2)); } -TEST(CacheTest, ZeroSizeCache) { +TEST_F(CacheTest, ZeroSizeCache) { delete cache_; cache_ = NewLRUCache(0); @@ -222,5 +222,3 @@ TEST(CacheTest, ZeroSizeCache) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/coding.h b/util/coding.h index 1983ae7..f0bb57b 100644 --- a/util/coding.h +++ b/util/coding.h @@ -48,29 +48,13 @@ int VarintLength(uint64_t v); char* EncodeVarint32(char* dst, uint32_t value); char* EncodeVarint64(char* dst, uint64_t value); -// TODO(costan): Remove port::kLittleEndian and the fast paths based on -// std::memcpy when clang learns to optimize the generic code, as -// described in https://bugs.llvm.org/show_bug.cgi?id=41761 -// -// The platform-independent code in DecodeFixed{32,64}() gets optimized to mov -// on x86 and ldr on ARM64, by both clang and gcc. However, only gcc optimizes -// the platform-independent code in EncodeFixed{32,64}() to mov / str. - // Lower-level versions of Put... that write directly into a character buffer // REQUIRES: dst has enough space for the value being written inline void EncodeFixed32(char* dst, uint32_t value) { uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst); - if (port::kLittleEndian) { - // Fast path for little-endian CPUs. All major compilers optimize this to a - // single mov (x86_64) / str (ARM) instruction. - std::memcpy(buffer, &value, sizeof(uint32_t)); - return; - } - - // Platform-independent code. - // Currently, only gcc optimizes this to a single mov / str instruction. + // Recent clang and gcc optimize this to a single mov / str instruction. buffer[0] = static_cast<uint8_t>(value); buffer[1] = static_cast<uint8_t>(value >> 8); buffer[2] = static_cast<uint8_t>(value >> 16); @@ -80,15 +64,7 @@ inline void EncodeFixed32(char* dst, uint32_t value) { inline void EncodeFixed64(char* dst, uint64_t value) { uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst); - if (port::kLittleEndian) { - // Fast path for little-endian CPUs. All major compilers optimize this to a - // single mov (x86_64) / str (ARM) instruction. - std::memcpy(buffer, &value, sizeof(uint64_t)); - return; - } - - // Platform-independent code. - // Currently, only gcc optimizes this to a single mov / str instruction. + // Recent clang and gcc optimize this to a single mov / str instruction. buffer[0] = static_cast<uint8_t>(value); buffer[1] = static_cast<uint8_t>(value >> 8); buffer[2] = static_cast<uint8_t>(value >> 16); @@ -105,16 +81,7 @@ inline void EncodeFixed64(char* dst, uint64_t value) { inline uint32_t DecodeFixed32(const char* ptr) { const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr); - if (port::kLittleEndian) { - // Fast path for little-endian CPUs. All major compilers optimize this to a - // single mov (x86_64) / ldr (ARM) instruction. - uint32_t result; - std::memcpy(&result, buffer, sizeof(uint32_t)); - return result; - } - - // Platform-independent code. - // Clang and gcc optimize this to a single mov / ldr instruction. + // Recent clang and gcc optimize this to a single mov / ldr instruction. return (static_cast<uint32_t>(buffer[0])) | (static_cast<uint32_t>(buffer[1]) << 8) | (static_cast<uint32_t>(buffer[2]) << 16) | @@ -124,16 +91,7 @@ inline uint32_t DecodeFixed32(const char* ptr) { inline uint64_t DecodeFixed64(const char* ptr) { const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr); - if (port::kLittleEndian) { - // Fast path for little-endian CPUs. All major compilers optimize this to a - // single mov (x86_64) / ldr (ARM) instruction. - uint64_t result; - std::memcpy(&result, buffer, sizeof(uint64_t)); - return result; - } - - // Platform-independent code. - // Clang and gcc optimize this to a single mov / ldr instruction. + // Recent clang and gcc optimize this to a single mov / ldr instruction. return (static_cast<uint64_t>(buffer[0])) | (static_cast<uint64_t>(buffer[1]) << 8) | (static_cast<uint64_t>(buffer[2]) << 16) | diff --git a/util/coding_test.cc b/util/coding_test.cc index 0d2a0c5..cceda14 100644 --- a/util/coding_test.cc +++ b/util/coding_test.cc @@ -2,15 +2,14 @@ // 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 "util/coding.h" + #include <vector> -#include "util/coding.h" -#include "util/testharness.h" +#include "gtest/gtest.h" namespace leveldb { -class Coding {}; - TEST(Coding, Fixed32) { std::string s; for (uint32_t v = 0; v < 100000; v++) { @@ -192,5 +191,3 @@ TEST(Coding, Strings) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/crc32c.cc b/util/crc32c.cc index c2e61f7..3f18908 100644 --- a/util/crc32c.cc +++ b/util/crc32c.cc @@ -6,8 +6,8 @@ #include "util/crc32c.h" -#include <stddef.h> -#include <stdint.h> +#include <cstddef> +#include <cstdint> #include "port/port.h" #include "util/coding.h" diff --git a/util/crc32c.h b/util/crc32c.h index 98fabb0..b420b5f 100644 --- a/util/crc32c.h +++ b/util/crc32c.h @@ -5,8 +5,8 @@ #ifndef STORAGE_LEVELDB_UTIL_CRC32C_H_ #define STORAGE_LEVELDB_UTIL_CRC32C_H_ -#include <stddef.h> -#include <stdint.h> +#include <cstddef> +#include <cstdint> namespace leveldb { namespace crc32c { diff --git a/util/crc32c_test.cc b/util/crc32c_test.cc index 18a8494..2fe1c41 100644 --- a/util/crc32c_test.cc +++ b/util/crc32c_test.cc @@ -3,13 +3,12 @@ // found in the LICENSE file. See the AUTHORS file for names of contributors. #include "util/crc32c.h" -#include "util/testharness.h" + +#include "gtest/gtest.h" namespace leveldb { namespace crc32c { -class CRC {}; - TEST(CRC, StandardResults) { // From rfc3720 section B.4. char buf[32]; @@ -55,5 +54,3 @@ TEST(CRC, Mask) { } // namespace crc32c } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/env.cc b/util/env.cc index d2f0aef..a53b230 100644 --- a/util/env.cc +++ b/util/env.cc @@ -4,14 +4,30 @@ #include "leveldb/env.h" +#include <cstdarg> + +// This workaround can be removed when leveldb::Env::DeleteFile is removed. +// See env.h for justification. +#if defined(_WIN32) && defined(LEVELDB_DELETEFILE_UNDEFINED) +#undef DeleteFile +#endif + namespace leveldb { +Env::Env() = default; + Env::~Env() = default; Status Env::NewAppendableFile(const std::string& fname, WritableFile** result) { return Status::NotSupported("NewAppendableFile", fname); } +Status Env::RemoveDir(const std::string& dirname) { return DeleteDir(dirname); } +Status Env::DeleteDir(const std::string& dirname) { return RemoveDir(dirname); } + +Status Env::RemoveFile(const std::string& fname) { return DeleteFile(fname); } +Status Env::DeleteFile(const std::string& fname) { return RemoveFile(fname); } + SequentialFile::~SequentialFile() = default; RandomAccessFile::~RandomAccessFile() = default; @@ -24,7 +40,7 @@ FileLock::~FileLock() = default; void Log(Logger* info_log, const char* format, ...) { if (info_log != nullptr) { - va_list ap; + std::va_list ap; va_start(ap, format); info_log->Logv(format, ap); va_end(ap); @@ -47,7 +63,7 @@ static Status DoWriteStringToFile(Env* env, const Slice& data, } delete file; // Will auto-close if we did not close above if (!s.ok()) { - env->DeleteFile(fname); + env->RemoveFile(fname); } return s; } diff --git a/util/env_posix.cc b/util/env_posix.cc index 00ca9ae..ffd06c4 100644 --- a/util/env_posix.cc +++ b/util/env_posix.cc @@ -4,9 +4,10 @@ #include <dirent.h> #include <fcntl.h> -#include <pthread.h> #include <sys/mman.h> +#ifndef __Fuchsia__ #include <sys/resource.h> +#endif #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> @@ -72,7 +73,14 @@ Status PosixError(const std::string& context, int error_number) { class Limiter { public: // Limit maximum number of resources to |max_acquires|. - Limiter(int max_acquires) : acquires_allowed_(max_acquires) {} + Limiter(int max_acquires) + : +#if !defined(NDEBUG) + max_acquires_(max_acquires), +#endif // !defined(NDEBUG) + acquires_allowed_(max_acquires) { + assert(max_acquires >= 0); + } Limiter(const Limiter&) = delete; Limiter operator=(const Limiter&) = delete; @@ -85,15 +93,35 @@ class Limiter { if (old_acquires_allowed > 0) return true; - acquires_allowed_.fetch_add(1, std::memory_order_relaxed); + int pre_increment_acquires_allowed = + acquires_allowed_.fetch_add(1, std::memory_order_relaxed); + + // Silence compiler warnings about unused arguments when NDEBUG is defined. + (void)pre_increment_acquires_allowed; + // If the check below fails, Release() was called more times than acquire. + assert(pre_increment_acquires_allowed < max_acquires_); + return false; } // Release a resource acquired by a previous call to Acquire() that returned // true. - void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); } + void Release() { + int old_acquires_allowed = + acquires_allowed_.fetch_add(1, std::memory_order_relaxed); + + // Silence compiler warnings about unused arguments when NDEBUG is defined. + (void)old_acquires_allowed; + // If the check below fails, Release() was called more times than acquire. + assert(old_acquires_allowed < max_acquires_); + } private: +#if !defined(NDEBUG) + // Catches an excessive number of Release() calls. + const int max_acquires_; +#endif // !defined(NDEBUG) + // The number of available resources. // // This is a counter and is not tied to the invariants of any other class, so @@ -108,7 +136,7 @@ class Limiter { class PosixSequentialFile final : public SequentialFile { public: PosixSequentialFile(std::string filename, int fd) - : fd_(fd), filename_(filename) {} + : fd_(fd), filename_(std::move(filename)) {} ~PosixSequentialFile() override { close(fd_); } Status Read(size_t n, Slice* result, char* scratch) override { @@ -214,7 +242,7 @@ class PosixMmapReadableFile final : public RandomAccessFile { // over the ownership of the region. // // |mmap_limiter| must outlive this instance. The caller must have already - // aquired the right to use one mmap region, which will be released when this + // acquired the right to use one mmap region, which will be released when this // instance is destroyed. PosixMmapReadableFile(std::string filename, char* mmap_base, size_t length, Limiter* mmap_limiter) @@ -587,7 +615,7 @@ class PosixEnv : public Env { return Status::OK(); } - Status DeleteFile(const std::string& filename) override { + Status RemoveFile(const std::string& filename) override { if (::unlink(filename.c_str()) != 0) { return PosixError(filename, errno); } @@ -601,7 +629,7 @@ class PosixEnv : public Env { return Status::OK(); } - Status DeleteDir(const std::string& dirname) override { + Status RemoveDir(const std::string& dirname) override { if (::rmdir(dirname.c_str()) != 0) { return PosixError(dirname, errno); } @@ -728,7 +756,7 @@ class PosixEnv : public Env { // Instances are constructed on the thread calling Schedule() and used on the // background thread. // - // This structure is thread-safe beacuse it is immutable. + // This structure is thread-safe because it is immutable. struct BackgroundWorkItem { explicit BackgroundWorkItem(void (*function)(void* arg), void* arg) : function(function), arg(arg) {} @@ -757,6 +785,10 @@ int MaxOpenFiles() { if (g_open_read_only_file_limit >= 0) { return g_open_read_only_file_limit; } +#ifdef __Fuchsia__ + // Fuchsia doesn't implement getrlimit. + g_open_read_only_file_limit = 50; +#else struct ::rlimit rlim; if (::getrlimit(RLIMIT_NOFILE, &rlim)) { // getrlimit failed, fallback to hard-coded default. @@ -767,6 +799,7 @@ int MaxOpenFiles() { // Allow use of 20% of available file descriptors for read-only files. g_open_read_only_file_limit = rlim.rlim_cur / 5; } +#endif return g_open_read_only_file_limit; } @@ -837,7 +870,7 @@ class SingletonEnv { public: SingletonEnv() { #if !defined(NDEBUG) - env_initialized_.store(true, std::memory_order::memory_order_relaxed); + env_initialized_.store(true, std::memory_order_relaxed); #endif // !defined(NDEBUG) static_assert(sizeof(env_storage_) >= sizeof(EnvType), "env_storage_ will not fit the Env"); @@ -854,7 +887,7 @@ class SingletonEnv { static void AssertEnvNotInitialized() { #if !defined(NDEBUG) - assert(!env_initialized_.load(std::memory_order::memory_order_relaxed)); + assert(!env_initialized_.load(std::memory_order_relaxed)); #endif // !defined(NDEBUG) } diff --git a/util/env_posix_test.cc b/util/env_posix_test.cc index 9675d73..34bda62 100644 --- a/util/env_posix_test.cc +++ b/util/env_posix_test.cc @@ -13,10 +13,11 @@ #include <unordered_set> #include <vector> +#include "gtest/gtest.h" #include "leveldb/env.h" #include "port/port.h" #include "util/env_posix_test_helper.h" -#include "util/testharness.h" +#include "util/testutil.h" #if HAVE_O_CLOEXEC @@ -168,7 +169,7 @@ namespace leveldb { static const int kReadOnlyFileLimit = 4; static const int kMMapLimit = 4; -class EnvPosixTest { +class EnvPosixTest : public testing::Test { public: static void SetFileLimits(int read_only_file_limit, int mmap_limit) { EnvPosixTestHelper::SetReadOnlyFDLimit(read_only_file_limit); @@ -180,150 +181,150 @@ class EnvPosixTest { Env* env_; }; -TEST(EnvPosixTest, TestOpenOnRead) { +TEST_F(EnvPosixTest, TestOpenOnRead) { // Write some test data to a single file that will be opened |n| times. std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string test_file = test_dir + "/open_on_read.txt"; - FILE* f = fopen(test_file.c_str(), "we"); + FILE* f = std::fopen(test_file.c_str(), "we"); ASSERT_TRUE(f != nullptr); const char kFileData[] = "abcdefghijklmnopqrstuvwxyz"; fputs(kFileData, f); - fclose(f); + std::fclose(f); // Open test file some number above the sum of the two limits to force // open-on-read behavior of POSIX Env leveldb::RandomAccessFile. const int kNumFiles = kReadOnlyFileLimit + kMMapLimit + 5; leveldb::RandomAccessFile* files[kNumFiles] = {0}; for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i])); + ASSERT_LEVELDB_OK(env_->NewRandomAccessFile(test_file, &files[i])); } char scratch; Slice read_result; for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch)); + ASSERT_LEVELDB_OK(files[i]->Read(i, 1, &read_result, &scratch)); ASSERT_EQ(kFileData[i], read_result[0]); } for (int i = 0; i < kNumFiles; i++) { delete files[i]; } - ASSERT_OK(env_->DeleteFile(test_file)); + ASSERT_LEVELDB_OK(env_->RemoveFile(test_file)); } #if HAVE_O_CLOEXEC -TEST(EnvPosixTest, TestCloseOnExecSequentialFile) { +TEST_F(EnvPosixTest, TestCloseOnExecSequentialFile) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_sequential.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); leveldb::SequentialFile* file = nullptr; - ASSERT_OK(env_->NewSequentialFile(file_path, &file)); + ASSERT_LEVELDB_OK(env_->NewSequentialFile(file_path, &file)); CheckCloseOnExecDoesNotLeakFDs(open_fds); delete file; - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } -TEST(EnvPosixTest, TestCloseOnExecRandomAccessFile) { +TEST_F(EnvPosixTest, TestCloseOnExecRandomAccessFile) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_random_access.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); // Exhaust the RandomAccessFile mmap limit. This way, the test // RandomAccessFile instance below is backed by a file descriptor, not by an // mmap region. - leveldb::RandomAccessFile* mmapped_files[kReadOnlyFileLimit] = {nullptr}; - for (int i = 0; i < kReadOnlyFileLimit; i++) { - ASSERT_OK(env_->NewRandomAccessFile(file_path, &mmapped_files[i])); + leveldb::RandomAccessFile* mmapped_files[kMMapLimit]; + for (int i = 0; i < kMMapLimit; i++) { + ASSERT_LEVELDB_OK(env_->NewRandomAccessFile(file_path, &mmapped_files[i])); } leveldb::RandomAccessFile* file = nullptr; - ASSERT_OK(env_->NewRandomAccessFile(file_path, &file)); + ASSERT_LEVELDB_OK(env_->NewRandomAccessFile(file_path, &file)); CheckCloseOnExecDoesNotLeakFDs(open_fds); delete file; - for (int i = 0; i < kReadOnlyFileLimit; i++) { + for (int i = 0; i < kMMapLimit; i++) { delete mmapped_files[i]; } - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } -TEST(EnvPosixTest, TestCloseOnExecWritableFile) { +TEST_F(EnvPosixTest, TestCloseOnExecWritableFile) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_writable.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); leveldb::WritableFile* file = nullptr; - ASSERT_OK(env_->NewWritableFile(file_path, &file)); + ASSERT_LEVELDB_OK(env_->NewWritableFile(file_path, &file)); CheckCloseOnExecDoesNotLeakFDs(open_fds); delete file; - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } -TEST(EnvPosixTest, TestCloseOnExecAppendableFile) { +TEST_F(EnvPosixTest, TestCloseOnExecAppendableFile) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_appendable.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); leveldb::WritableFile* file = nullptr; - ASSERT_OK(env_->NewAppendableFile(file_path, &file)); + ASSERT_LEVELDB_OK(env_->NewAppendableFile(file_path, &file)); CheckCloseOnExecDoesNotLeakFDs(open_fds); delete file; - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } -TEST(EnvPosixTest, TestCloseOnExecLockFile) { +TEST_F(EnvPosixTest, TestCloseOnExecLockFile) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_lock.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); leveldb::FileLock* lock = nullptr; - ASSERT_OK(env_->LockFile(file_path, &lock)); + ASSERT_LEVELDB_OK(env_->LockFile(file_path, &lock)); CheckCloseOnExecDoesNotLeakFDs(open_fds); - ASSERT_OK(env_->UnlockFile(lock)); + ASSERT_LEVELDB_OK(env_->UnlockFile(lock)); - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } -TEST(EnvPosixTest, TestCloseOnExecLogger) { +TEST_F(EnvPosixTest, TestCloseOnExecLogger) { std::unordered_set<int> open_fds; GetOpenFileDescriptors(&open_fds); std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string file_path = test_dir + "/close_on_exec_logger.txt"; - ASSERT_OK(WriteStringToFile(env_, "0123456789", file_path)); + ASSERT_LEVELDB_OK(WriteStringToFile(env_, "0123456789", file_path)); leveldb::Logger* file = nullptr; - ASSERT_OK(env_->NewLogger(file_path, &file)); + ASSERT_LEVELDB_OK(env_->NewLogger(file_path, &file)); CheckCloseOnExecDoesNotLeakFDs(open_fds); delete file; - ASSERT_OK(env_->DeleteFile(file_path)); + ASSERT_LEVELDB_OK(env_->RemoveFile(file_path)); } #endif // HAVE_O_CLOEXEC @@ -346,5 +347,7 @@ int main(int argc, char** argv) { // All tests currently run with the same read-only file limits. leveldb::EnvPosixTest::SetFileLimits(leveldb::kReadOnlyFileLimit, leveldb::kMMapLimit); - return leveldb::test::RunAllTests(); + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/util/env_test.cc b/util/env_test.cc index 2023e35..47174f5 100644 --- a/util/env_test.cc +++ b/util/env_test.cc @@ -6,30 +6,30 @@ #include <algorithm> +#include "gtest/gtest.h" #include "port/port.h" #include "port/thread_annotations.h" #include "util/mutexlock.h" -#include "util/testharness.h" #include "util/testutil.h" namespace leveldb { -class EnvTest { +class EnvTest : public testing::Test { public: EnvTest() : env_(Env::Default()) {} Env* env_; }; -TEST(EnvTest, ReadWrite) { +TEST_F(EnvTest, ReadWrite) { Random rnd(test::RandomSeed()); // Get file to use for testing. std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string test_file_name = test_dir + "/open_on_read.txt"; WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file)); + ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file)); // Fill a file with data generated via a sequence of randomly sized writes. static const size_t kDataSize = 10 * 1048576; @@ -38,26 +38,26 @@ TEST(EnvTest, ReadWrite) { int len = rnd.Skewed(18); // Up to 2^18 - 1, but typically much smaller std::string r; test::RandomString(&rnd, len, &r); - ASSERT_OK(writable_file->Append(r)); + ASSERT_LEVELDB_OK(writable_file->Append(r)); data += r; if (rnd.OneIn(10)) { - ASSERT_OK(writable_file->Flush()); + ASSERT_LEVELDB_OK(writable_file->Flush()); } } - ASSERT_OK(writable_file->Sync()); - ASSERT_OK(writable_file->Close()); + ASSERT_LEVELDB_OK(writable_file->Sync()); + ASSERT_LEVELDB_OK(writable_file->Close()); delete writable_file; // Read all data using a sequence of randomly sized reads. SequentialFile* sequential_file; - ASSERT_OK(env_->NewSequentialFile(test_file_name, &sequential_file)); + ASSERT_LEVELDB_OK(env_->NewSequentialFile(test_file_name, &sequential_file)); std::string read_result; std::string scratch; while (read_result.size() < data.size()) { int len = std::min<int>(rnd.Skewed(18), data.size() - read_result.size()); scratch.resize(std::max(len, 1)); // at least 1 so &scratch[0] is legal Slice read; - ASSERT_OK(sequential_file->Read(len, &read, &scratch[0])); + ASSERT_LEVELDB_OK(sequential_file->Read(len, &read, &scratch[0])); if (len > 0) { ASSERT_GT(read.size(), 0); } @@ -68,7 +68,7 @@ TEST(EnvTest, ReadWrite) { delete sequential_file; } -TEST(EnvTest, RunImmediately) { +TEST_F(EnvTest, RunImmediately) { struct RunState { port::Mutex mu; port::CondVar cvar{&mu}; @@ -92,7 +92,7 @@ TEST(EnvTest, RunImmediately) { } } -TEST(EnvTest, RunMany) { +TEST_F(EnvTest, RunMany) { struct RunState { port::Mutex mu; port::CondVar cvar{&mu}; @@ -151,7 +151,7 @@ static void ThreadBody(void* arg) { s->mu.Unlock(); } -TEST(EnvTest, StartThread) { +TEST_F(EnvTest, StartThread) { State state(0, 3); for (int i = 0; i < 3; i++) { env_->StartThread(&ThreadBody, &state); @@ -164,10 +164,10 @@ TEST(EnvTest, StartThread) { ASSERT_EQ(state.val, 3); } -TEST(EnvTest, TestOpenNonExistentFile) { +TEST_F(EnvTest, TestOpenNonExistentFile) { // Write some test data to a single file that will be opened |n| times. std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string non_existent_file = test_dir + "/non_existent_file"; ASSERT_TRUE(!env_->FileExists(non_existent_file)); @@ -182,54 +182,52 @@ TEST(EnvTest, TestOpenNonExistentFile) { ASSERT_TRUE(status.IsNotFound()); } -TEST(EnvTest, ReopenWritableFile) { +TEST_F(EnvTest, ReopenWritableFile) { std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string test_file_name = test_dir + "/reopen_writable_file.txt"; - env_->DeleteFile(test_file_name); + env_->RemoveFile(test_file_name); WritableFile* writable_file; - ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file)); + ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file)); std::string data("hello world!"); - ASSERT_OK(writable_file->Append(data)); - ASSERT_OK(writable_file->Close()); + ASSERT_LEVELDB_OK(writable_file->Append(data)); + ASSERT_LEVELDB_OK(writable_file->Close()); delete writable_file; - ASSERT_OK(env_->NewWritableFile(test_file_name, &writable_file)); + ASSERT_LEVELDB_OK(env_->NewWritableFile(test_file_name, &writable_file)); data = "42"; - ASSERT_OK(writable_file->Append(data)); - ASSERT_OK(writable_file->Close()); + ASSERT_LEVELDB_OK(writable_file->Append(data)); + ASSERT_LEVELDB_OK(writable_file->Close()); delete writable_file; - ASSERT_OK(ReadFileToString(env_, test_file_name, &data)); + ASSERT_LEVELDB_OK(ReadFileToString(env_, test_file_name, &data)); ASSERT_EQ(std::string("42"), data); - env_->DeleteFile(test_file_name); + env_->RemoveFile(test_file_name); } -TEST(EnvTest, ReopenAppendableFile) { +TEST_F(EnvTest, ReopenAppendableFile) { std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string test_file_name = test_dir + "/reopen_appendable_file.txt"; - env_->DeleteFile(test_file_name); + env_->RemoveFile(test_file_name); WritableFile* appendable_file; - ASSERT_OK(env_->NewAppendableFile(test_file_name, &appendable_file)); + ASSERT_LEVELDB_OK(env_->NewAppendableFile(test_file_name, &appendable_file)); std::string data("hello world!"); - ASSERT_OK(appendable_file->Append(data)); - ASSERT_OK(appendable_file->Close()); + ASSERT_LEVELDB_OK(appendable_file->Append(data)); + ASSERT_LEVELDB_OK(appendable_file->Close()); delete appendable_file; - ASSERT_OK(env_->NewAppendableFile(test_file_name, &appendable_file)); + ASSERT_LEVELDB_OK(env_->NewAppendableFile(test_file_name, &appendable_file)); data = "42"; - ASSERT_OK(appendable_file->Append(data)); - ASSERT_OK(appendable_file->Close()); + ASSERT_LEVELDB_OK(appendable_file->Append(data)); + ASSERT_LEVELDB_OK(appendable_file->Close()); delete appendable_file; - ASSERT_OK(ReadFileToString(env_, test_file_name, &data)); + ASSERT_LEVELDB_OK(ReadFileToString(env_, test_file_name, &data)); ASSERT_EQ(std::string("hello world!42"), data); - env_->DeleteFile(test_file_name); + env_->RemoveFile(test_file_name); } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/env_windows.cc b/util/env_windows.cc index 2dd7794..1c74b02 100644 --- a/util/env_windows.cc +++ b/util/env_windows.cc @@ -33,10 +33,6 @@ #include "util/mutexlock.h" #include "util/windows_logger.h" -#if defined(DeleteFile) -#undef DeleteFile -#endif // defined(DeleteFile) - namespace leveldb { namespace { @@ -118,7 +114,14 @@ class ScopedHandle { class Limiter { public: // Limit maximum number of resources to |max_acquires|. - Limiter(int max_acquires) : acquires_allowed_(max_acquires) {} + Limiter(int max_acquires) + : +#if !defined(NDEBUG) + max_acquires_(max_acquires), +#endif // !defined(NDEBUG) + acquires_allowed_(max_acquires) { + assert(max_acquires >= 0); + } Limiter(const Limiter&) = delete; Limiter operator=(const Limiter&) = delete; @@ -137,9 +140,22 @@ class Limiter { // Release a resource acquired by a previous call to Acquire() that returned // true. - void Release() { acquires_allowed_.fetch_add(1, std::memory_order_relaxed); } + void Release() { + int old_acquires_allowed = + acquires_allowed_.fetch_add(1, std::memory_order_relaxed); + + // Silence compiler warnings about unused arguments when NDEBUG is defined. + (void)old_acquires_allowed; + // If the check below fails, Release() was called more times than acquire. + assert(old_acquires_allowed < max_acquires_); + } private: +#if !defined(NDEBUG) + // Catches an excessive number of Release() calls. + const int max_acquires_; +#endif // !defined(NDEBUG) + // The number of available resources. // // This is a counter and is not tied to the invariants of any other class, so @@ -505,7 +521,7 @@ class WindowsEnv : public Env { return Status::OK(); } - Status DeleteFile(const std::string& filename) override { + Status RemoveFile(const std::string& filename) override { if (!::DeleteFileA(filename.c_str())) { return WindowsError(filename, ::GetLastError()); } @@ -519,7 +535,7 @@ class WindowsEnv : public Env { return Status::OK(); } - Status DeleteDir(const std::string& dirname) override { + Status RemoveDir(const std::string& dirname) override { if (!::RemoveDirectoryA(dirname.c_str())) { return WindowsError(dirname, ::GetLastError()); } @@ -626,7 +642,7 @@ class WindowsEnv : public Env { } Status NewLogger(const std::string& filename, Logger** result) override { - std::FILE* fp = std::fopen(filename.c_str(), "w"); + std::FILE* fp = std::fopen(filename.c_str(), "wN"); if (fp == nullptr) { *result = nullptr; return WindowsError(filename, ::GetLastError()); @@ -665,7 +681,7 @@ class WindowsEnv : public Env { // Instances are constructed on the thread calling Schedule() and used on the // background thread. // - // This structure is thread-safe beacuse it is immutable. + // This structure is thread-safe because it is immutable. struct BackgroundWorkItem { explicit BackgroundWorkItem(void (*function)(void* arg), void* arg) : function(function), arg(arg) {} @@ -749,7 +765,7 @@ class SingletonEnv { public: SingletonEnv() { #if !defined(NDEBUG) - env_initialized_.store(true, std::memory_order::memory_order_relaxed); + env_initialized_.store(true, std::memory_order_relaxed); #endif // !defined(NDEBUG) static_assert(sizeof(env_storage_) >= sizeof(EnvType), "env_storage_ will not fit the Env"); @@ -766,7 +782,7 @@ class SingletonEnv { static void AssertEnvNotInitialized() { #if !defined(NDEBUG) - assert(!env_initialized_.load(std::memory_order::memory_order_relaxed)); + assert(!env_initialized_.load(std::memory_order_relaxed)); #endif // !defined(NDEBUG) } diff --git a/util/env_windows_test.cc b/util/env_windows_test.cc index 3c22133..d6822d2 100644 --- a/util/env_windows_test.cc +++ b/util/env_windows_test.cc @@ -2,17 +2,17 @@ // 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 "gtest/gtest.h" #include "leveldb/env.h" - #include "port/port.h" #include "util/env_windows_test_helper.h" -#include "util/testharness.h" +#include "util/testutil.h" namespace leveldb { static const int kMMapLimit = 4; -class EnvWindowsTest { +class EnvWindowsTest : public testing::Test { public: static void SetFileLimits(int mmap_limit) { EnvWindowsTestHelper::SetReadOnlyMMapLimit(mmap_limit); @@ -23,17 +23,17 @@ class EnvWindowsTest { Env* env_; }; -TEST(EnvWindowsTest, TestOpenOnRead) { +TEST_F(EnvWindowsTest, TestOpenOnRead) { // Write some test data to a single file that will be opened |n| times. std::string test_dir; - ASSERT_OK(env_->GetTestDirectory(&test_dir)); + ASSERT_LEVELDB_OK(env_->GetTestDirectory(&test_dir)); std::string test_file = test_dir + "/open_on_read.txt"; - FILE* f = fopen(test_file.c_str(), "w"); + FILE* f = std::fopen(test_file.c_str(), "w"); ASSERT_TRUE(f != nullptr); const char kFileData[] = "abcdefghijklmnopqrstuvwxyz"; fputs(kFileData, f); - fclose(f); + std::fclose(f); // Open test file some number above the sum of the two limits to force // leveldb::WindowsEnv to switch from mapping the file into memory @@ -41,18 +41,18 @@ TEST(EnvWindowsTest, TestOpenOnRead) { const int kNumFiles = kMMapLimit + 5; leveldb::RandomAccessFile* files[kNumFiles] = {0}; for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(env_->NewRandomAccessFile(test_file, &files[i])); + ASSERT_LEVELDB_OK(env_->NewRandomAccessFile(test_file, &files[i])); } char scratch; Slice read_result; for (int i = 0; i < kNumFiles; i++) { - ASSERT_OK(files[i]->Read(i, 1, &read_result, &scratch)); + ASSERT_LEVELDB_OK(files[i]->Read(i, 1, &read_result, &scratch)); ASSERT_EQ(kFileData[i], read_result[0]); } for (int i = 0; i < kNumFiles; i++) { delete files[i]; } - ASSERT_OK(env_->DeleteFile(test_file)); + ASSERT_LEVELDB_OK(env_->RemoveFile(test_file)); } } // namespace leveldb @@ -60,5 +60,6 @@ TEST(EnvWindowsTest, TestOpenOnRead) { int main(int argc, char** argv) { // All tests currently run with the same read-only file limits. leveldb::EnvWindowsTest::SetFileLimits(leveldb::kMMapLimit); - return leveldb::test::RunAllTests(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/util/hash.cc b/util/hash.cc index dd47c11..8122fa8 100644 --- a/util/hash.cc +++ b/util/hash.cc @@ -4,7 +4,7 @@ #include "util/hash.h" -#include <string.h> +#include <cstring> #include "util/coding.h" diff --git a/util/hash.h b/util/hash.h index 74bdb6e..87ab279 100644 --- a/util/hash.h +++ b/util/hash.h @@ -7,8 +7,8 @@ #ifndef STORAGE_LEVELDB_UTIL_HASH_H_ #define STORAGE_LEVELDB_UTIL_HASH_H_ -#include <stddef.h> -#include <stdint.h> +#include <cstddef> +#include <cstdint> namespace leveldb { diff --git a/util/hash_test.cc b/util/hash_test.cc index 21f8171..0ea5977 100644 --- a/util/hash_test.cc +++ b/util/hash_test.cc @@ -3,11 +3,10 @@ // found in the LICENSE file. See the AUTHORS file for names of contributors. #include "util/hash.h" -#include "util/testharness.h" -namespace leveldb { +#include "gtest/gtest.h" -class HASH {}; +namespace leveldb { TEST(HASH, SignedUnsignedIssue) { const uint8_t data1[1] = {0x62}; @@ -40,5 +39,3 @@ TEST(HASH, SignedUnsignedIssue) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/histogram.cc b/util/histogram.cc index 65092c8..7af4030 100644 --- a/util/histogram.cc +++ b/util/histogram.cc @@ -4,8 +4,8 @@ #include "util/histogram.h" -#include <math.h> -#include <stdio.h> +#include <cmath> +#include <cstdio> #include "port/port.h" @@ -241,11 +241,11 @@ double Histogram::StandardDeviation() const { std::string Histogram::ToString() const { std::string r; char buf[200]; - snprintf(buf, sizeof(buf), "Count: %.0f Average: %.4f StdDev: %.2f\n", num_, - Average(), StandardDeviation()); + std::snprintf(buf, sizeof(buf), "Count: %.0f Average: %.4f StdDev: %.2f\n", + num_, Average(), StandardDeviation()); r.append(buf); - snprintf(buf, sizeof(buf), "Min: %.4f Median: %.4f Max: %.4f\n", - (num_ == 0.0 ? 0.0 : min_), Median(), max_); + std::snprintf(buf, sizeof(buf), "Min: %.4f Median: %.4f Max: %.4f\n", + (num_ == 0.0 ? 0.0 : min_), Median(), max_); r.append(buf); r.append("------------------------------------------------------\n"); const double mult = 100.0 / num_; @@ -253,12 +253,12 @@ std::string Histogram::ToString() const { for (int b = 0; b < kNumBuckets; b++) { if (buckets_[b] <= 0.0) continue; sum += buckets_[b]; - snprintf(buf, sizeof(buf), "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", - ((b == 0) ? 0.0 : kBucketLimit[b - 1]), // left - kBucketLimit[b], // right - buckets_[b], // count - mult * buckets_[b], // percentage - mult * sum); // cumulative percentage + std::snprintf(buf, sizeof(buf), "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ", + ((b == 0) ? 0.0 : kBucketLimit[b - 1]), // left + kBucketLimit[b], // right + buckets_[b], // count + mult * buckets_[b], // percentage + mult * sum); // cumulative percentage r.append(buf); // Add hash marks based on percentage; 20 marks for 100%. diff --git a/util/logging.cc b/util/logging.cc index 75e9d03..8d6fb5b 100644 --- a/util/logging.cc +++ b/util/logging.cc @@ -4,11 +4,9 @@ #include "util/logging.h" -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - +#include <cstdarg> +#include <cstdio> +#include <cstdlib> #include <limits> #include "leveldb/env.h" @@ -18,7 +16,7 @@ namespace leveldb { void AppendNumberTo(std::string* str, uint64_t num) { char buf[30]; - snprintf(buf, sizeof(buf), "%llu", (unsigned long long)num); + std::snprintf(buf, sizeof(buf), "%llu", static_cast<unsigned long long>(num)); str->append(buf); } @@ -29,8 +27,8 @@ void AppendEscapedStringTo(std::string* str, const Slice& value) { str->push_back(c); } else { char buf[10]; - snprintf(buf, sizeof(buf), "\\x%02x", - static_cast<unsigned int>(c) & 0xff); + std::snprintf(buf, sizeof(buf), "\\x%02x", + static_cast<unsigned int>(c) & 0xff); str->append(buf); } } diff --git a/util/logging.h b/util/logging.h index 8ff2da8..a0394b2 100644 --- a/util/logging.h +++ b/util/logging.h @@ -8,9 +8,8 @@ #ifndef STORAGE_LEVELDB_UTIL_LOGGING_H_ #define STORAGE_LEVELDB_UTIL_LOGGING_H_ -#include <stdint.h> -#include <stdio.h> - +#include <cstdint> +#include <cstdio> #include <string> #include "port/port.h" diff --git a/util/logging_test.cc b/util/logging_test.cc index 389cbeb..1746c57 100644 --- a/util/logging_test.cc +++ b/util/logging_test.cc @@ -2,17 +2,16 @@ // 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 "util/logging.h" + #include <limits> #include <string> +#include "gtest/gtest.h" #include "leveldb/slice.h" -#include "util/logging.h" -#include "util/testharness.h" namespace leveldb { -class Logging {}; - TEST(Logging, NumberToString) { ASSERT_EQ("0", NumberToString(0)); ASSERT_EQ("1", NumberToString(1)); @@ -139,5 +138,3 @@ TEST(Logging, ConsumeDecimalNumberNoDigits) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/no_destructor_test.cc b/util/no_destructor_test.cc index b41caca..e3602cc 100644 --- a/util/no_destructor_test.cc +++ b/util/no_destructor_test.cc @@ -2,12 +2,13 @@ // 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 "util/no_destructor.h" + #include <cstdint> #include <cstdlib> #include <utility> -#include "util/no_destructor.h" -#include "util/testharness.h" +#include "gtest/gtest.h" namespace leveldb { @@ -28,8 +29,6 @@ constexpr const uint64_t kGoldenB = 0xaabbccddeeffaabb; } // namespace -class NoDestructorTest {}; - TEST(NoDestructorTest, StackInstance) { NoDestructor<DoNotDestruct> instance(kGoldenA, kGoldenB); ASSERT_EQ(kGoldenA, instance.get()->a); @@ -43,5 +42,3 @@ TEST(NoDestructorTest, StaticInstance) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/posix_logger.h b/util/posix_logger.h index 28e15d1..6bbc1a0 100644 --- a/util/posix_logger.h +++ b/util/posix_logger.h @@ -30,7 +30,7 @@ class PosixLogger final : public Logger { ~PosixLogger() override { std::fclose(fp_); } - void Logv(const char* format, va_list arguments) override { + void Logv(const char* format, std::va_list arguments) override { // Record the time as close to the Logv() call as possible. struct ::timeval now_timeval; ::gettimeofday(&now_timeval, nullptr); @@ -62,7 +62,7 @@ class PosixLogger final : public Logger { (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size]; // Print the header into the buffer. - int buffer_offset = snprintf( + int buffer_offset = std::snprintf( buffer, buffer_size, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s ", now_components.tm_year + 1900, now_components.tm_mon + 1, now_components.tm_mday, now_components.tm_hour, now_components.tm_min, @@ -98,8 +98,8 @@ class PosixLogger final : public Logger { } // The dynamically-allocated buffer was incorrectly sized. This should - // not happen, assuming a correct implementation of (v)snprintf. Fail - // in tests, recover by truncating the log message in production. + // not happen, assuming a correct implementation of std::(v)snprintf. + // Fail in tests, recover by truncating the log message in production. assert(false); buffer_offset = buffer_size - 1; } diff --git a/util/random.h b/util/random.h index 76f7daf..fe76ab4 100644 --- a/util/random.h +++ b/util/random.h @@ -5,7 +5,7 @@ #ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ #define STORAGE_LEVELDB_UTIL_RANDOM_H_ -#include <stdint.h> +#include <cstdint> namespace leveldb { diff --git a/util/status.cc b/util/status.cc index 15ce747..0559f5b 100644 --- a/util/status.cc +++ b/util/status.cc @@ -4,7 +4,7 @@ #include "leveldb/status.h" -#include <stdio.h> +#include <cstdio> #include "port/port.h" @@ -12,9 +12,9 @@ namespace leveldb { const char* Status::CopyState(const char* state) { uint32_t size; - memcpy(&size, state, sizeof(size)); + std::memcpy(&size, state, sizeof(size)); char* result = new char[size + 5]; - memcpy(result, state, size + 5); + std::memcpy(result, state, size + 5); return result; } @@ -24,13 +24,13 @@ Status::Status(Code code, const Slice& msg, const Slice& msg2) { const uint32_t len2 = static_cast<uint32_t>(msg2.size()); const uint32_t size = len1 + (len2 ? (2 + len2) : 0); char* result = new char[size + 5]; - memcpy(result, &size, sizeof(size)); + std::memcpy(result, &size, sizeof(size)); result[4] = static_cast<char>(code); - memcpy(result + 5, msg.data(), len1); + std::memcpy(result + 5, msg.data(), len1); if (len2) { result[5 + len1] = ':'; result[6 + len1] = ' '; - memcpy(result + 7 + len1, msg2.data(), len2); + std::memcpy(result + 7 + len1, msg2.data(), len2); } state_ = result; } @@ -61,14 +61,14 @@ std::string Status::ToString() const { type = "IO error: "; break; default: - snprintf(tmp, sizeof(tmp), - "Unknown code(%d): ", static_cast<int>(code())); + std::snprintf(tmp, sizeof(tmp), + "Unknown code(%d): ", static_cast<int>(code())); type = tmp; break; } std::string result(type); uint32_t length; - memcpy(&length, state_, sizeof(length)); + std::memcpy(&length, state_, sizeof(length)); result.append(state_ + 5, length); return result; } diff --git a/util/status_test.cc b/util/status_test.cc index 2842319..dbf5faa 100644 --- a/util/status_test.cc +++ b/util/status_test.cc @@ -2,11 +2,12 @@ // 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 "leveldb/status.h" + #include <utility> +#include "gtest/gtest.h" #include "leveldb/slice.h" -#include "leveldb/status.h" -#include "util/testharness.h" namespace leveldb { @@ -36,5 +37,3 @@ TEST(Status, MoveConstructor) { } } // namespace leveldb - -int main(int argc, char** argv) { return leveldb::test::RunAllTests(); } diff --git a/util/testharness.cc b/util/testharness.cc deleted file mode 100644 index 318ecfa..0000000 --- a/util/testharness.cc +++ /dev/null @@ -1,81 +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 "util/testharness.h" - -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <string> -#include <vector> - -#include "leveldb/env.h" - -namespace leveldb { -namespace test { - -namespace { -struct Test { - const char* base; - const char* name; - void (*func)(); -}; -std::vector<Test>* tests; -} // namespace - -bool RegisterTest(const char* base, const char* name, void (*func)()) { - if (tests == nullptr) { - tests = new std::vector<Test>; - } - Test t; - t.base = base; - t.name = name; - t.func = func; - tests->push_back(t); - return true; -} - -int RunAllTests() { - const char* matcher = getenv("LEVELDB_TESTS"); - - int num = 0; - if (tests != nullptr) { - for (size_t i = 0; i < tests->size(); i++) { - const Test& t = (*tests)[i]; - if (matcher != nullptr) { - std::string name = t.base; - name.push_back('.'); - name.append(t.name); - if (strstr(name.c_str(), matcher) == nullptr) { - continue; - } - } - fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); - (*t.func)(); - ++num; - } - } - fprintf(stderr, "==== PASSED %d tests\n", num); - return 0; -} - -std::string TmpDir() { - std::string dir; - Status s = Env::Default()->GetTestDirectory(&dir); - ASSERT_TRUE(s.ok()) << s.ToString(); - return dir; -} - -int RandomSeed() { - const char* env = getenv("TEST_RANDOM_SEED"); - int result = (env != nullptr ? atoi(env) : 301); - if (result <= 0) { - result = 301; - } - return result; -} - -} // namespace test -} // namespace leveldb diff --git a/util/testharness.h b/util/testharness.h deleted file mode 100644 index 72cd162..0000000 --- a/util/testharness.h +++ /dev/null @@ -1,141 +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. - -#ifndef STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ -#define STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ - -#include <stdio.h> -#include <stdlib.h> - -#include <sstream> - -#include "leveldb/status.h" - -namespace leveldb { -namespace test { - -// Run some of the tests registered by the TEST() macro. If the -// environment variable "LEVELDB_TESTS" is not set, runs all tests. -// Otherwise, runs only the tests whose name contains the value of -// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: -// TEST(Foo, Hello) { ... } -// TEST(Foo, World) { ... } -// LEVELDB_TESTS=Hello will run the first test -// LEVELDB_TESTS=o will run both tests -// LEVELDB_TESTS=Junk will run no tests -// -// Returns 0 if all tests pass. -// Dies or returns a non-zero value if some test fails. -int RunAllTests(); - -// Return the directory to use for temporary storage. -std::string TmpDir(); - -// Return a randomization seed for this run. Typically returns the -// same number on repeated invocations of this binary, but automated -// runs may be able to vary the seed. -int RandomSeed(); - -// An instance of Tester is allocated to hold temporary state during -// the execution of an assertion. -class Tester { - private: - bool ok_; - const char* fname_; - int line_; - std::stringstream ss_; - - public: - Tester(const char* f, int l) : ok_(true), fname_(f), line_(l) {} - - ~Tester() { - if (!ok_) { - fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); - exit(1); - } - } - - Tester& Is(bool b, const char* msg) { - if (!b) { - ss_ << " Assertion failure " << msg; - ok_ = false; - } - return *this; - } - - Tester& IsOk(const Status& s) { - if (!s.ok()) { - ss_ << " " << s.ToString(); - ok_ = false; - } - return *this; - } - -#define BINARY_OP(name, op) \ - template <class X, class Y> \ - Tester& name(const X& x, const Y& y) { \ - if (!(x op y)) { \ - ss_ << " failed: " << x << (" " #op " ") << y; \ - ok_ = false; \ - } \ - return *this; \ - } - - BINARY_OP(IsEq, ==) - BINARY_OP(IsNe, !=) - BINARY_OP(IsGe, >=) - BINARY_OP(IsGt, >) - BINARY_OP(IsLe, <=) - BINARY_OP(IsLt, <) -#undef BINARY_OP - - // Attach the specified value to the error message if an error has occurred - template <class V> - Tester& operator<<(const V& value) { - if (!ok_) { - ss_ << " " << value; - } - return *this; - } -}; - -#define ASSERT_TRUE(c) ::leveldb::test::Tester(__FILE__, __LINE__).Is((c), #c) -#define ASSERT_OK(s) ::leveldb::test::Tester(__FILE__, __LINE__).IsOk((s)) -#define ASSERT_EQ(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsEq((a), (b)) -#define ASSERT_NE(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsNe((a), (b)) -#define ASSERT_GE(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsGe((a), (b)) -#define ASSERT_GT(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsGt((a), (b)) -#define ASSERT_LE(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsLe((a), (b)) -#define ASSERT_LT(a, b) \ - ::leveldb::test::Tester(__FILE__, __LINE__).IsLt((a), (b)) - -#define TCONCAT(a, b) TCONCAT1(a, b) -#define TCONCAT1(a, b) a##b - -#define TEST(base, name) \ - class TCONCAT(_Test_, name) : public base { \ - public: \ - void _Run(); \ - static void _RunIt() { \ - TCONCAT(_Test_, name) t; \ - t._Run(); \ - } \ - }; \ - bool TCONCAT(_Test_ignored_, name) = ::leveldb::test::RegisterTest( \ - #base, #name, &TCONCAT(_Test_, name)::_RunIt); \ - void TCONCAT(_Test_, name)::_Run() - -// Register the specified test. Typically not used directly, but -// invoked via the macro expansion of TEST. -bool RegisterTest(const char* base, const char* name, void (*func)()); - -} // namespace test -} // namespace leveldb - -#endif // STORAGE_LEVELDB_UTIL_TESTHARNESS_H_ diff --git a/util/testutil.cc b/util/testutil.cc index 6b151b9..5f77b08 100644 --- a/util/testutil.cc +++ b/util/testutil.cc @@ -4,6 +4,8 @@ #include "util/testutil.h" +#include <string> + #include "util/random.h" namespace leveldb { diff --git a/util/testutil.h b/util/testutil.h index bb4051b..e0e2d64 100644 --- a/util/testutil.h +++ b/util/testutil.h @@ -5,6 +5,8 @@ #ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_ #define STORAGE_LEVELDB_UTIL_TESTUTIL_H_ +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "helpers/memenv/memenv.h" #include "leveldb/env.h" #include "leveldb/slice.h" @@ -13,6 +15,20 @@ namespace leveldb { namespace test { +MATCHER(IsOK, "") { return arg.ok(); } + +// Macros for testing the results of functions that return leveldb::Status or +// absl::StatusOr<T> (for any type T). +#define EXPECT_LEVELDB_OK(expression) \ + EXPECT_THAT(expression, leveldb::test::IsOK()) +#define ASSERT_LEVELDB_OK(expression) \ + ASSERT_THAT(expression, leveldb::test::IsOK()) + +// Returns the random seed used at the start of the current test run. +inline int RandomSeed() { + return testing::UnitTest::GetInstance()->random_seed(); +} + // Store in *dst a random string of length "len" and return a Slice that // references the generated data. Slice RandomString(Random* rnd, int len, std::string* dst); diff --git a/util/windows_logger.h b/util/windows_logger.h index 9296063..26e6c7b 100644 --- a/util/windows_logger.h +++ b/util/windows_logger.h @@ -27,7 +27,7 @@ class WindowsLogger final : public Logger { ~WindowsLogger() override { std::fclose(fp_); } - void Logv(const char* format, va_list arguments) override { + void Logv(const char* format, std::va_list arguments) override { // Record the time as close to the Logv() call as possible. SYSTEMTIME now_components; ::GetLocalTime(&now_components); @@ -56,7 +56,7 @@ class WindowsLogger final : public Logger { (iteration == 0) ? stack_buffer : new char[dynamic_buffer_size]; // Print the header into the buffer. - int buffer_offset = snprintf( + int buffer_offset = std::snprintf( buffer, buffer_size, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s ", now_components.wYear, now_components.wMonth, now_components.wDay, now_components.wHour, now_components.wMinute, now_components.wSecond, @@ -92,8 +92,8 @@ class WindowsLogger final : public Logger { } // The dynamically-allocated buffer was incorrectly sized. This should - // not happen, assuming a correct implementation of (v)snprintf. Fail - // in tests, recover by truncating the log message in production. + // not happen, assuming a correct implementation of std::(v)snprintf. + // Fail in tests, recover by truncating the log message in production. assert(false); buffer_offset = buffer_size - 1; } |