diff --git a/.appveyor.yml b/.appveyor.yml
deleted file mode 100644
index c24b17e..0000000
--- a/.appveyor.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-# Build matrix / environment variables are explained on:
-# https://www.appveyor.com/docs/appveyor-yml/
-# This file can be validated on: https://ci.appveyor.com/tools/validate-yaml
-
-version: "{build}"
-
-environment:
- matrix:
- # AppVeyor currently has no custom job name feature.
- # http://help.appveyor.com/discussions/questions/1623-can-i-provide-a-friendly-name-for-jobs
- - JOB: Visual Studio 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- CMAKE_GENERATOR: Visual Studio 15 2017
-
-platform:
- - x86
- - x64
-
-configuration:
- - RelWithDebInfo
- - Debug
-
-build_script:
- - git submodule update --init --recursive
- - mkdir build
- - cd build
- - if "%platform%"=="x64" set CMAKE_GENERATOR=%CMAKE_GENERATOR% Win64
- - cmake --version
- - cmake .. -G "%CMAKE_GENERATOR%"
- -DCMAKE_CONFIGURATION_TYPES="%CONFIGURATION%"
- - cmake --build . --config "%CONFIGURATION%"
- - cd ..
-
-test_script:
- - cd build && ctest --verbose --build-config "%CONFIGURATION%" && cd ..
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..efb81ee
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,101 @@
+# Copyright 2021 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.
+
+name: ci
+on: [push, pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ build-and-test:
+ name: >-
+ CI
+ ${{ matrix.os }}
+ ${{ matrix.compiler }}
+ ${{ matrix.optimized && 'release' || 'debug' }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ compiler: [clang, gcc, msvc]
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ optimized: [true, false]
+ exclude:
+ # MSVC only works on Windows.
+ - os: ubuntu-latest
+ compiler: msvc
+ - os: macos-latest
+ compiler: msvc
+ # Not testing with GCC on macOS.
+ - os: macos-latest
+ compiler: gcc
+ # Only testing with MSVC on Windows.
+ - os: windows-latest
+ compiler: clang
+ - os: windows-latest
+ compiler: gcc
+ include:
+ - compiler: clang
+ CC: clang
+ CXX: clang++
+ - compiler: gcc
+ CC: gcc
+ CXX: g++
+ - compiler: msvc
+ CC:
+ CXX:
+
+ env:
+ CMAKE_BUILD_DIR: ${{ github.workspace }}/build
+ CMAKE_BUILD_TYPE: ${{ matrix.optimized && 'RelWithDebInfo' || 'Debug' }}
+ CC: ${{ matrix.CC }}
+ CXX: ${{ matrix.CXX }}
+ BINARY_SUFFIX: ${{ startsWith(matrix.os, 'windows') && '.exe' || '' }}
+ BINARY_PATH: >-
+ ${{ format(
+ startsWith(matrix.os, 'windows') && '{0}\build\{1}\' || '{0}/build/',
+ github.workspace,
+ matrix.optimized && 'RelWithDebInfo' || 'Debug') }}
+
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: true
+
+ - name: Install dependencies on Linux
+ if: ${{ runner.os == 'Linux' }}
+ run: |
+ sudo apt-get update
+ sudo apt-get install libgoogle-perftools-dev libkyotocabinet-dev \
+ libsnappy-dev libsqlite3-dev
+
+ - name: Generate build config
+ run: >-
+ cmake -S "${{ github.workspace }}" -B "${{ env.CMAKE_BUILD_DIR }}"
+ -DCMAKE_BUILD_TYPE=${{ env.CMAKE_BUILD_TYPE }}
+ -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/install_test/
+
+ - name: Build
+ run: >-
+ cmake --build "${{ env.CMAKE_BUILD_DIR }}"
+ --config "${{ env.CMAKE_BUILD_TYPE }}"
+
+ - name: Run Tests
+ working-directory: ${{ github.workspace }}/build
+ run: ctest -C "${{ env.CMAKE_BUILD_TYPE }}" --verbose
+
+ - name: Run LevelDB Benchmarks
+ run: ${{ env.BINARY_PATH }}db_bench${{ env.BINARY_SUFFIX }}
+
+ - name: Run SQLite Benchmarks
+ if: ${{ runner.os != 'Windows' }}
+ run: ${{ env.BINARY_PATH }}db_bench_sqlite3${{ env.BINARY_SUFFIX }}
+
+ - name: Run Kyoto Cabinet Benchmarks
+ if: ${{ runner.os == 'Linux' && matrix.compiler == 'clang' }}
+ run: ${{ env.BINARY_PATH }}db_bench_tree_db${{ env.BINARY_SUFFIX }}
+
+ - name: Test CMake installation
+ run: cmake --build "${{ env.CMAKE_BUILD_DIR }}" --target install
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..6e6d3f0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "third_party/googletest"]
+ path = third_party/googletest
+ url = https://github.com/google/googletest.git
+[submodule "third_party/benchmark"]
+ path = third_party/benchmark
+ url = https://github.com/google/benchmark
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index b4acf13..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,80 +0,0 @@
-# Build matrix / environment variables are explained on:
-# http://about.travis-ci.org/docs/user/build-configuration/
-# This file can be validated on: http://lint.travis-ci.org/
-
-language: cpp
-dist: bionic
-osx_image: xcode10.3
-
-compiler:
-- gcc
-- clang
-os:
-- linux
-- osx
-
-env:
-- BUILD_TYPE=Debug
-- BUILD_TYPE=RelWithDebInfo
-
-addons:
- apt:
- sources:
- - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'
- key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- - sourceline: 'ppa:ubuntu-toolchain-r/test'
- packages:
- - clang-9
- - cmake
- - gcc-9
- - g++-9
- - libgoogle-perftools-dev
- - libkyotocabinet-dev
- - libsnappy-dev
- - libsqlite3-dev
- - ninja-build
- homebrew:
- packages:
- - cmake
- - crc32c
- - gcc@9
- - gperftools
- - kyoto-cabinet
- - llvm@9
- - ninja
- - snappy
- - sqlite3
- update: true
-
-install:
-# The following Homebrew packages aren't linked by default, and need to be
-# prepended to the path explicitly.
-- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- export PATH="$(brew --prefix llvm)/bin:$PATH";
- fi
-# /usr/bin/gcc points to an older compiler on both Linux and macOS.
-- if [ "$CXX" = "g++" ]; then export CXX="g++-9" CC="gcc-9"; fi
-# /usr/bin/clang points to an older compiler on both Linux and macOS.
-#
-# Homebrew's llvm package doesn't ship a versioned clang++ binary, so the values
-# below don't work on macOS. Fortunately, the path change above makes the
-# default values (clang and clang++) resolve to the correct compiler on macOS.
-- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
- if [ "$CXX" = "clang++" ]; then export CXX="clang++-9" CC="clang-9"; fi;
- fi
-- echo ${CC}
-- echo ${CXX}
-- ${CXX} --version
-- cmake --version
-
-before_script:
-- mkdir -p build && cd build
-- cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE
-- cmake --build .
-- cd ..
-
-script:
-- cd build && ctest --verbose && cd ..
-- "if [ -f build/db_bench ] ; then build/db_bench ; fi"
-- "if [ -f build/db_bench_sqlite3 ] ; then build/db_bench_sqlite3 ; fi"
-- "if [ -f build/db_bench_tree_db ] ; then build/db_bench_tree_db ; fi"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a65afbf..b829c94 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,17 +4,23 @@
cmake_minimum_required(VERSION 3.9)
# Keep the version below in sync with the one in db.h
-project(leveldb VERSION 1.22.0 LANGUAGES C CXX)
-
-# This project can use C11, but will gracefully decay down to C89.
-set(CMAKE_C_STANDARD 11)
-set(CMAKE_C_STANDARD_REQUIRED OFF)
-set(CMAKE_C_EXTENSIONS OFF)
-
-# This project requires C++11.
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
+project(leveldb VERSION 1.23.0 LANGUAGES C CXX)
+
+# C standard can be overridden when this is used as a sub-project.
+if(NOT CMAKE_C_STANDARD)
+ # This project can use C11, but will gracefully decay down to C89.
+ set(CMAKE_C_STANDARD 11)
+ set(CMAKE_C_STANDARD_REQUIRED OFF)
+ set(CMAKE_C_EXTENSIONS OFF)
+endif(NOT CMAKE_C_STANDARD)
+
+# C++ standard can be overridden when this is used as a sub-project.
+if(NOT CMAKE_CXX_STANDARD)
+ # This project requires C++11.
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+endif(NOT CMAKE_CXX_STANDARD)
if (WIN32)
set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_WINDOWS)
@@ -28,9 +34,6 @@ option(LEVELDB_BUILD_TESTS "Build LevelDB's unit tests" ON)
option(LEVELDB_BUILD_BENCHMARKS "Build LevelDB's benchmarks" ON)
option(LEVELDB_INSTALL "Install LevelDB's header and library" ON)
-include(TestBigEndian)
-test_big_endian(LEVELDB_IS_BIG_ENDIAN)
-
include(CheckIncludeFile)
check_include_file("unistd.h" HAVE_UNISTD_H)
@@ -78,6 +81,10 @@ endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wthread-safety HAVE_CLANG_THREAD_SAFETY)
+# Used by googletest.
+check_cxx_compiler_flag(-Wno-missing-field-initializers
+ LEVELDB_HAVE_NO_MISSING_FIELD_INITIALIZERS)
+
include(CheckCXXSourceCompiles)
# Test whether C++17 __has_include is available.
@@ -92,13 +99,13 @@ set(LEVELDB_PUBLIC_INCLUDE_DIR "include/leveldb")
set(LEVELDB_PORT_CONFIG_DIR "include/port")
configure_file(
- "${PROJECT_SOURCE_DIR}/port/port_config.h.in"
+ "port/port_config.h.in"
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
)
include_directories(
"${PROJECT_BINARY_DIR}/include"
- "${PROJECT_SOURCE_DIR}"
+ "."
)
if(BUILD_SHARED_LIBS)
@@ -106,79 +113,82 @@ if(BUILD_SHARED_LIBS)
add_compile_options(-fvisibility=hidden)
endif(BUILD_SHARED_LIBS)
+# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
+include(GNUInstallDirs)
+
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"
- "${PROJECT_SOURCE_DIR}/db/db_impl.cc"
- "${PROJECT_SOURCE_DIR}/db/db_impl.h"
- "${PROJECT_SOURCE_DIR}/db/db_iter.cc"
- "${PROJECT_SOURCE_DIR}/db/db_iter.h"
- "${PROJECT_SOURCE_DIR}/db/dbformat.cc"
- "${PROJECT_SOURCE_DIR}/db/dbformat.h"
- "${PROJECT_SOURCE_DIR}/db/dumpfile.cc"
- "${PROJECT_SOURCE_DIR}/db/filename.cc"
- "${PROJECT_SOURCE_DIR}/db/filename.h"
- "${PROJECT_SOURCE_DIR}/db/log_format.h"
- "${PROJECT_SOURCE_DIR}/db/log_reader.cc"
- "${PROJECT_SOURCE_DIR}/db/log_reader.h"
- "${PROJECT_SOURCE_DIR}/db/log_writer.cc"
- "${PROJECT_SOURCE_DIR}/db/log_writer.h"
- "${PROJECT_SOURCE_DIR}/db/memtable.cc"
- "${PROJECT_SOURCE_DIR}/db/memtable.h"
- "${PROJECT_SOURCE_DIR}/db/repair.cc"
- "${PROJECT_SOURCE_DIR}/db/skiplist.h"
- "${PROJECT_SOURCE_DIR}/db/snapshot.h"
- "${PROJECT_SOURCE_DIR}/db/table_cache.cc"
- "${PROJECT_SOURCE_DIR}/db/table_cache.h"
- "${PROJECT_SOURCE_DIR}/db/version_edit.cc"
- "${PROJECT_SOURCE_DIR}/db/version_edit.h"
- "${PROJECT_SOURCE_DIR}/db/version_set.cc"
- "${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/port_stdcxx.h"
- "${PROJECT_SOURCE_DIR}/port/port.h"
- "${PROJECT_SOURCE_DIR}/port/thread_annotations.h"
- "${PROJECT_SOURCE_DIR}/table/block_builder.cc"
- "${PROJECT_SOURCE_DIR}/table/block_builder.h"
- "${PROJECT_SOURCE_DIR}/table/block.cc"
- "${PROJECT_SOURCE_DIR}/table/block.h"
- "${PROJECT_SOURCE_DIR}/table/filter_block.cc"
- "${PROJECT_SOURCE_DIR}/table/filter_block.h"
- "${PROJECT_SOURCE_DIR}/table/format.cc"
- "${PROJECT_SOURCE_DIR}/table/format.h"
- "${PROJECT_SOURCE_DIR}/table/iterator_wrapper.h"
- "${PROJECT_SOURCE_DIR}/table/iterator.cc"
- "${PROJECT_SOURCE_DIR}/table/merger.cc"
- "${PROJECT_SOURCE_DIR}/table/merger.h"
- "${PROJECT_SOURCE_DIR}/table/table_builder.cc"
- "${PROJECT_SOURCE_DIR}/table/table.cc"
- "${PROJECT_SOURCE_DIR}/table/two_level_iterator.cc"
- "${PROJECT_SOURCE_DIR}/table/two_level_iterator.h"
- "${PROJECT_SOURCE_DIR}/util/arena.cc"
- "${PROJECT_SOURCE_DIR}/util/arena.h"
- "${PROJECT_SOURCE_DIR}/util/bloom.cc"
- "${PROJECT_SOURCE_DIR}/util/cache.cc"
- "${PROJECT_SOURCE_DIR}/util/coding.cc"
- "${PROJECT_SOURCE_DIR}/util/coding.h"
- "${PROJECT_SOURCE_DIR}/util/comparator.cc"
- "${PROJECT_SOURCE_DIR}/util/crc32c.cc"
- "${PROJECT_SOURCE_DIR}/util/crc32c.h"
- "${PROJECT_SOURCE_DIR}/util/env.cc"
- "${PROJECT_SOURCE_DIR}/util/filter_policy.cc"
- "${PROJECT_SOURCE_DIR}/util/hash.cc"
- "${PROJECT_SOURCE_DIR}/util/hash.h"
- "${PROJECT_SOURCE_DIR}/util/logging.cc"
- "${PROJECT_SOURCE_DIR}/util/logging.h"
- "${PROJECT_SOURCE_DIR}/util/mutexlock.h"
- "${PROJECT_SOURCE_DIR}/util/no_destructor.h"
- "${PROJECT_SOURCE_DIR}/util/options.cc"
- "${PROJECT_SOURCE_DIR}/util/random.h"
- "${PROJECT_SOURCE_DIR}/util/status.cc"
+ "db/builder.cc"
+ "db/builder.h"
+ "db/c.cc"
+ "db/db_impl.cc"
+ "db/db_impl.h"
+ "db/db_iter.cc"
+ "db/db_iter.h"
+ "db/dbformat.cc"
+ "db/dbformat.h"
+ "db/dumpfile.cc"
+ "db/filename.cc"
+ "db/filename.h"
+ "db/log_format.h"
+ "db/log_reader.cc"
+ "db/log_reader.h"
+ "db/log_writer.cc"
+ "db/log_writer.h"
+ "db/memtable.cc"
+ "db/memtable.h"
+ "db/repair.cc"
+ "db/skiplist.h"
+ "db/snapshot.h"
+ "db/table_cache.cc"
+ "db/table_cache.h"
+ "db/version_edit.cc"
+ "db/version_edit.h"
+ "db/version_set.cc"
+ "db/version_set.h"
+ "db/write_batch_internal.h"
+ "db/write_batch.cc"
+ "port/port_stdcxx.h"
+ "port/port.h"
+ "port/thread_annotations.h"
+ "table/block_builder.cc"
+ "table/block_builder.h"
+ "table/block.cc"
+ "table/block.h"
+ "table/filter_block.cc"
+ "table/filter_block.h"
+ "table/format.cc"
+ "table/format.h"
+ "table/iterator_wrapper.h"
+ "table/iterator.cc"
+ "table/merger.cc"
+ "table/merger.h"
+ "table/table_builder.cc"
+ "table/table.cc"
+ "table/two_level_iterator.cc"
+ "table/two_level_iterator.h"
+ "util/arena.cc"
+ "util/arena.h"
+ "util/bloom.cc"
+ "util/cache.cc"
+ "util/coding.cc"
+ "util/coding.h"
+ "util/comparator.cc"
+ "util/crc32c.cc"
+ "util/crc32c.h"
+ "util/env.cc"
+ "util/filter_policy.cc"
+ "util/hash.cc"
+ "util/hash.h"
+ "util/logging.cc"
+ "util/logging.h"
+ "util/mutexlock.h"
+ "util/no_destructor.h"
+ "util/options.cc"
+ "util/random.h"
+ "util/status.cc"
# Only CMake 3.3+ supports PUBLIC sources in targets exported by "install".
$<$:PUBLIC>
@@ -202,22 +212,22 @@ target_sources(leveldb
if (WIN32)
target_sources(leveldb
PRIVATE
- "${PROJECT_SOURCE_DIR}/util/env_windows.cc"
- "${PROJECT_SOURCE_DIR}/util/windows_logger.h"
+ "util/env_windows.cc"
+ "util/windows_logger.h"
)
else (WIN32)
target_sources(leveldb
PRIVATE
- "${PROJECT_SOURCE_DIR}/util/env_posix.cc"
- "${PROJECT_SOURCE_DIR}/util/posix_logger.h"
+ "util/env_posix.cc"
+ "util/posix_logger.h"
)
endif (WIN32)
# 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"
+ "helpers/memenv/memenv.cc"
+ "helpers/memenv/memenv.h"
)
target_include_directories(leveldb
@@ -272,13 +282,84 @@ find_package(Threads REQUIRED)
target_link_libraries(leveldb Threads::Threads)
add_executable(leveldbutil
- "${PROJECT_SOURCE_DIR}/db/leveldbutil.cc"
+ "db/leveldbutil.cc"
)
target_link_libraries(leveldbutil leveldb)
if(LEVELDB_BUILD_TESTS)
enable_testing()
+ # Prevent overriding the parent project's compiler/linker settings on Windows.
+ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+ set(install_gtest OFF)
+ set(install_gmock OFF)
+ set(build_gmock ON)
+
+ # This project is tested using GoogleTest.
+ add_subdirectory("third_party/googletest")
+
+ # GoogleTest triggers a missing field initializers warning.
+ if(LEVELDB_HAVE_NO_MISSING_FIELD_INITIALIZERS)
+ set_property(TARGET gtest
+ APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)
+ set_property(TARGET gmock
+ APPEND PROPERTY COMPILE_OPTIONS -Wno-missing-field-initializers)
+ endif(LEVELDB_HAVE_NO_MISSING_FIELD_INITIALIZERS)
+
+ add_executable(leveldb_tests "")
+ target_sources(leveldb_tests
+ PRIVATE
+ # "db/fault_injection_test.cc"
+ # "issues/issue178_test.cc"
+ # "issues/issue200_test.cc"
+ # "issues/issue320_test.cc"
+ "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
+ # "util/env_test.cc"
+ "util/status_test.cc"
+ "util/no_destructor_test.cc"
+ "util/testutil.cc"
+ "util/testutil.h"
+ )
+ if(NOT BUILD_SHARED_LIBS)
+ target_sources(leveldb_tests
+ PRIVATE
+ "db/autocompact_test.cc"
+ "db/corruption_test.cc"
+ "db/db_test.cc"
+ "db/dbformat_test.cc"
+ "db/filename_test.cc"
+ "db/log_test.cc"
+ "db/recovery_test.cc"
+ "db/skiplist_test.cc"
+ "db/version_edit_test.cc"
+ "db/version_set_test.cc"
+ "db/write_batch_test.cc"
+ "helpers/memenv/memenv_test.cc"
+ "table/filter_block_test.cc"
+ "table/table_test.cc"
+ "util/arena_test.cc"
+ "util/bloom_test.cc"
+ "util/cache_test.cc"
+ "util/coding_test.cc"
+ "util/crc32c_test.cc"
+ "util/hash_test.cc"
+ "util/logging_test.cc"
+ )
+ endif(NOT BUILD_SHARED_LIBS)
+ target_link_libraries(leveldb_tests leveldb gmock gtest gtest_main)
+ target_compile_definitions(leveldb_tests
+ PRIVATE
+ ${LEVELDB_PLATFORM_NAME}=1
+ )
+ if (NOT HAVE_CXX17_HAS_INCLUDE)
+ target_compile_definitions(leveldb_tests
+ PRIVATE
+ LEVELDB_HAS_PORT_CONFIG_H=1
+ )
+ endif(NOT HAVE_CXX17_HAS_INCLUDE)
+
+ add_test(NAME "leveldb_tests" COMMAND "leveldb_tests")
+
function(leveldb_test test_file)
get_filename_component(test_target_name "${test_file}" NAME_WE)
@@ -286,14 +367,12 @@ if(LEVELDB_BUILD_TESTS)
target_sources("${test_target_name}"
PRIVATE
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
- "${PROJECT_SOURCE_DIR}/util/testharness.cc"
- "${PROJECT_SOURCE_DIR}/util/testharness.h"
- "${PROJECT_SOURCE_DIR}/util/testutil.cc"
- "${PROJECT_SOURCE_DIR}/util/testutil.h"
+ "util/testutil.cc"
+ "util/testutil.h"
"${test_file}"
)
- target_link_libraries("${test_target_name}" leveldb)
+ target_link_libraries("${test_target_name}" leveldb gmock gtest)
target_compile_definitions("${test_target_name}"
PRIVATE
${LEVELDB_PLATFORM_NAME}=1
@@ -308,54 +387,25 @@ if(LEVELDB_BUILD_TESTS)
add_test(NAME "${test_target_name}" COMMAND "${test_target_name}")
endfunction(leveldb_test)
- leveldb_test("${PROJECT_SOURCE_DIR}/db/c_test.c")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/fault_injection_test.cc")
-
- leveldb_test("${PROJECT_SOURCE_DIR}/issues/issue178_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/issues/issue200_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/issues/issue320_test.cc")
-
- leveldb_test("${PROJECT_SOURCE_DIR}/util/env_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/status_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/no_destructor_test.cc")
+ leveldb_test("db/c_test.c")
if(NOT BUILD_SHARED_LIBS)
- leveldb_test("${PROJECT_SOURCE_DIR}/db/autocompact_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/corruption_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/db_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/dbformat_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/filename_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/log_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/recovery_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/skiplist_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/version_edit_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/version_set_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/db/write_batch_test.cc")
-
- leveldb_test("${PROJECT_SOURCE_DIR}/helpers/memenv/memenv_test.cc")
-
- leveldb_test("${PROJECT_SOURCE_DIR}/table/filter_block_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/table/table_test.cc")
-
- leveldb_test("${PROJECT_SOURCE_DIR}/util/arena_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/bloom_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/cache_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/coding_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/crc32c_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/hash_test.cc")
- leveldb_test("${PROJECT_SOURCE_DIR}/util/logging_test.cc")
-
# TODO(costan): This test also uses
- # "${PROJECT_SOURCE_DIR}/util/env_{posix|windows}_test_helper.h"
+ # "util/env_{posix|windows}_test_helper.h"
if (WIN32)
- leveldb_test("${PROJECT_SOURCE_DIR}/util/env_windows_test.cc")
+ leveldb_test("util/env_windows_test.cc")
else (WIN32)
- leveldb_test("${PROJECT_SOURCE_DIR}/util/env_posix_test.cc")
+ leveldb_test("util/env_posix_test.cc")
endif (WIN32)
endif(NOT BUILD_SHARED_LIBS)
endif(LEVELDB_BUILD_TESTS)
if(LEVELDB_BUILD_BENCHMARKS)
+ # This project uses Google benchmark for benchmarking.
+ set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
+ set(BENCHMARK_ENABLE_EXCEPTIONS OFF CACHE BOOL "" FORCE)
+ add_subdirectory("third_party/benchmark")
+
function(leveldb_benchmark bench_file)
get_filename_component(bench_target_name "${bench_file}" NAME_WE)
@@ -363,16 +413,14 @@ if(LEVELDB_BUILD_BENCHMARKS)
target_sources("${bench_target_name}"
PRIVATE
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
- "${PROJECT_SOURCE_DIR}/util/histogram.cc"
- "${PROJECT_SOURCE_DIR}/util/histogram.h"
- "${PROJECT_SOURCE_DIR}/util/testharness.cc"
- "${PROJECT_SOURCE_DIR}/util/testharness.h"
- "${PROJECT_SOURCE_DIR}/util/testutil.cc"
- "${PROJECT_SOURCE_DIR}/util/testutil.h"
+ "util/histogram.cc"
+ "util/histogram.h"
+ "util/testutil.cc"
+ "util/testutil.h"
"${bench_file}"
)
- target_link_libraries("${bench_target_name}" leveldb)
+ target_link_libraries("${bench_target_name}" leveldb gmock gtest benchmark)
target_compile_definitions("${bench_target_name}"
PRIVATE
${LEVELDB_PLATFORM_NAME}=1
@@ -386,12 +434,12 @@ if(LEVELDB_BUILD_BENCHMARKS)
endfunction(leveldb_benchmark)
if(NOT BUILD_SHARED_LIBS)
- leveldb_benchmark("${PROJECT_SOURCE_DIR}/benchmarks/db_bench.cc")
+ leveldb_benchmark("benchmarks/db_bench.cc")
endif(NOT BUILD_SHARED_LIBS)
check_library_exists(sqlite3 sqlite3_open "" HAVE_SQLITE3)
if(HAVE_SQLITE3)
- leveldb_benchmark("${PROJECT_SOURCE_DIR}/benchmarks/db_bench_sqlite3.cc")
+ leveldb_benchmark("benchmarks/db_bench_sqlite3.cc")
target_link_libraries(db_bench_sqlite3 sqlite3)
endif(HAVE_SQLITE3)
@@ -411,13 +459,12 @@ int main() {
" HAVE_KYOTOCABINET)
set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQURED_LIBRARIES})
if(HAVE_KYOTOCABINET)
- leveldb_benchmark("${PROJECT_SOURCE_DIR}/benchmarks/db_bench_tree_db.cc")
+ leveldb_benchmark("benchmarks/db_bench_tree_db.cc")
target_link_libraries(db_bench_tree_db kyotocabinet)
endif(HAVE_KYOTOCABINET)
endif(LEVELDB_BUILD_BENCHMARKS)
if(LEVELDB_INSTALL)
- include(GNUInstallDirs)
install(TARGETS leveldb
EXPORT leveldbTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
@@ -426,38 +473,43 @@ if(LEVELDB_INSTALL)
)
install(
FILES
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h"
- "${PROJECT_SOURCE_DIR}/${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h"
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/leveldb
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h"
+ "${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h"
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/leveldb"
)
include(CMakePackageConfigHelpers)
+ configure_package_config_file(
+ "cmake/${PROJECT_NAME}Config.cmake.in"
+ "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
+ )
write_basic_package_version_file(
- "${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake"
- COMPATIBILITY SameMajorVersion
+ "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake"
+ COMPATIBILITY SameMajorVersion
)
install(
EXPORT leveldbTargets
NAMESPACE leveldb::
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/leveldb"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
install(
FILES
- "${PROJECT_SOURCE_DIR}/cmake/leveldbConfig.cmake"
- "${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake"
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/leveldb"
+ "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake"
+ "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
endif(LEVELDB_INSTALL)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a74572a..7ede021 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,5 +32,5 @@ the CLA.
## Writing Code ##
If your contribution contains code, please make sure that it follows
-[the style guide](http://google.github.io/styleguide/cppguide.html).
+[the style guide](https://google.github.io/styleguide/cppguide.html).
Otherwise we will have to ask you to make changes, and that's no fun for anyone.
diff --git a/README.md b/README.md
index dadfd56..3c4d14d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
**LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.**
-[![Build Status](https://travis-ci.org/google/leveldb.svg?branch=master)](https://travis-ci.org/google/leveldb)
-[![Build status](https://ci.appveyor.com/api/projects/status/g2j5j4rfkda6eyw5/branch/master?svg=true)](https://ci.appveyor.com/project/pwnall/leveldb)
+[![ci](https://github.com/google/leveldb/actions/workflows/build.yml/badge.svg)](https://github.com/google/leveldb/actions/workflows/build.yml)
Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
@@ -14,7 +13,7 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
* Multiple changes can be made in one atomic batch.
* Users can create a transient snapshot to get a consistent view of data.
* Forward and backward iteration is supported over the data.
- * Data is automatically compressed using the [Snappy compression library](http://google.github.io/snappy/).
+ * Data is automatically compressed using the [Snappy compression library](https://google.github.io/snappy/).
* External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.
# Documentation
@@ -27,6 +26,12 @@ Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
* Only a single process (possibly multi-threaded) can access a particular database at a time.
* There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library.
+# Getting the Source
+
+```bash
+git clone --recurse-submodules https://github.com/google/leveldb.git
+```
+
# Building
This project supports [CMake](https://cmake.org/) out of the box.
diff --git a/benchmarks/db_bench.cc b/benchmarks/db_bench.cc
index 3696023..429a61a 100644
--- a/benchmarks/db_bench.cc
+++ b/benchmarks/db_bench.cc
@@ -2,11 +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
-#include
#include
+#include
+#include
+#include
+
#include "leveldb/cache.h"
+#include "leveldb/comparator.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/filter_policy.h"
@@ -33,6 +36,7 @@
// readmissing -- read N missing keys in random order
// readhot -- read N times in random order from 1% section of DB
// seekrandom -- N random seeks
+// seekordered -- N ordered seeks
// open -- cost of opening a DB
// crc32c -- repeated crc32c of 4K of data
// Meta operations:
@@ -77,6 +81,9 @@ static double FLAGS_compression_ratio = 0.5;
// Print histogram of operation timings
static bool FLAGS_histogram = false;
+// Count the number of string comparisons performed
+static bool FLAGS_comparisons = false;
+
// Number of bytes to buffer in memtable before compacting
// (initialized to default value by "main")
static int FLAGS_write_buffer_size = 0;
@@ -100,6 +107,9 @@ static int FLAGS_open_files = 0;
// Negative means use default settings.
static int FLAGS_bloom_bits = -1;
+// Common key prefix length.
+static int FLAGS_key_prefix = 0;
+
// If true, do not destroy the existing database. If you set this
// flag and also specify a benchmark that wants a fresh database, that
// benchmark will fail.
@@ -116,6 +126,33 @@ namespace leveldb {
namespace {
leveldb::Env* g_env = nullptr;
+class CountComparator : public Comparator {
+ public:
+ CountComparator(const Comparator* wrapped) : wrapped_(wrapped) {}
+ ~CountComparator() override {}
+ int Compare(const Slice& a, const Slice& b) const override {
+ count_.fetch_add(1, std::memory_order_relaxed);
+ return wrapped_->Compare(a, b);
+ }
+ const char* Name() const override { return wrapped_->Name(); }
+ void FindShortestSeparator(std::string* start,
+ const Slice& limit) const override {
+ wrapped_->FindShortestSeparator(start, limit);
+ }
+
+ void FindShortSuccessor(std::string* key) const override {
+ return wrapped_->FindShortSuccessor(key);
+ }
+
+ size_t comparisons() const { return count_.load(std::memory_order_relaxed); }
+
+ void reset() { count_.store(0, std::memory_order_relaxed); }
+
+ private:
+ mutable std::atomic count_{0};
+ const Comparator* const wrapped_;
+};
+
// Helper for quickly generating random data.
class RandomGenerator {
private:
@@ -148,6 +185,26 @@ class RandomGenerator {
}
};
+class KeyBuffer {
+ public:
+ KeyBuffer() {
+ assert(FLAGS_key_prefix < sizeof(buffer_));
+ memset(buffer_, 'a', FLAGS_key_prefix);
+ }
+ KeyBuffer& operator=(KeyBuffer& other) = delete;
+ KeyBuffer(KeyBuffer& other) = delete;
+
+ void Set(int k) {
+ std::snprintf(buffer_ + FLAGS_key_prefix,
+ sizeof(buffer_) - FLAGS_key_prefix, "%016d", k);
+ }
+
+ Slice slice() const { return Slice(buffer_, FLAGS_key_prefix + 16); }
+
+ private:
+ char buffer_[1024];
+};
+
#if defined(__linux)
static Slice TrimSpace(Slice s) {
size_t start = 0;
@@ -220,8 +277,8 @@ class Stats {
double micros = now - last_op_finish_;
hist_.Add(micros);
if (micros > 20000) {
- fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
- fflush(stderr);
+ std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
+ std::fflush(stderr);
}
last_op_finish_ = now;
}
@@ -242,8 +299,8 @@ class Stats {
next_report_ += 50000;
else
next_report_ += 100000;
- fprintf(stderr, "... finished %d ops%30s\r", done_, "");
- fflush(stderr);
+ std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
+ std::fflush(stderr);
}
}
@@ -260,18 +317,20 @@ class Stats {
// elapsed times.
double elapsed = (finish_ - start_) * 1e-6;
char rate[100];
- snprintf(rate, sizeof(rate), "%6.1f MB/s",
- (bytes_ / 1048576.0) / elapsed);
+ std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
+ (bytes_ / 1048576.0) / elapsed);
extra = rate;
}
AppendWithSpace(&extra, message_);
- fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", name.ToString().c_str(),
- seconds_ * 1e6 / done_, (extra.empty() ? "" : " "), extra.c_str());
+ std::fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n",
+ name.ToString().c_str(), seconds_ * 1e6 / done_,
+ (extra.empty() ? "" : " "), extra.c_str());
if (FLAGS_histogram) {
- fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());
+ std::fprintf(stdout, "Microseconds per op:\n%s\n",
+ hist_.ToString().c_str());
}
- fflush(stdout);
+ std::fflush(stdout);
}
};
@@ -302,7 +361,7 @@ struct ThreadState {
Stats stats;
SharedState* shared;
- ThreadState(int index) : tid(index), rand(1000 + index), shared(nullptr) {}
+ ThreadState(int index, int seed) : tid(index), rand(seed), shared(nullptr) {}
};
} // namespace
@@ -318,55 +377,61 @@ class Benchmark {
WriteOptions write_options_;
int reads_;
int heap_counter_;
+ CountComparator count_comparator_;
+ int total_thread_count_;
void PrintHeader() {
- const int kKeySize = 16;
+ const int kKeySize = 16 + FLAGS_key_prefix;
PrintEnvironment();
- fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
- fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n",
- FLAGS_value_size,
- static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
- fprintf(stdout, "Entries: %d\n", num_);
- fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
- ((static_cast(kKeySize + FLAGS_value_size) * num_) /
- 1048576.0));
- fprintf(stdout, "FileSize: %.1f MB (estimated)\n",
- (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /
- 1048576.0));
+ std::fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
+ std::fprintf(
+ stdout, "Values: %d bytes each (%d bytes after compression)\n",
+ FLAGS_value_size,
+ static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
+ std::fprintf(stdout, "Entries: %d\n", num_);
+ std::fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
+ ((static_cast(kKeySize + FLAGS_value_size) * num_) /
+ 1048576.0));
+ std::fprintf(
+ stdout, "FileSize: %.1f MB (estimated)\n",
+ (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /
+ 1048576.0));
PrintWarnings();
- fprintf(stdout, "------------------------------------------------\n");
+ std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
- fprintf(
+ std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
- fprintf(stdout,
- "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
+ std::fprintf(
+ stdout,
+ "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
// See if snappy is working by attempting to compress a compressible string
const char text[] = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
std::string compressed;
if (!port::Snappy_Compress(text, sizeof(text), &compressed)) {
- fprintf(stdout, "WARNING: Snappy compression is not enabled\n");
+ std::fprintf(stdout, "WARNING: Snappy compression is not enabled\n");
} else if (compressed.size() >= sizeof(text)) {
- fprintf(stdout, "WARNING: Snappy compression is not effective\n");
+ std::fprintf(stdout, "WARNING: Snappy compression is not effective\n");
}
}
void PrintEnvironment() {
- fprintf(stderr, "LevelDB: version %d.%d\n", kMajorVersion,
- kMinorVersion);
+ std::fprintf(stderr, "LevelDB: version %d.%d\n", kMajorVersion,
+ kMinorVersion);
#if defined(__linux)
time_t now = time(nullptr);
- fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline
+ std::fprintf(stderr, "Date: %s",
+ ctime(&now)); // ctime() adds newline
- FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
+ FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
@@ -386,9 +451,9 @@ class Benchmark {
cache_size = val.ToString();
}
}
- fclose(cpuinfo);
- fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
- fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
+ std::fclose(cpuinfo);
+ std::fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
+ std::fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
}
#endif
}
@@ -404,12 +469,14 @@ class Benchmark {
value_size_(FLAGS_value_size),
entries_per_batch_(1),
reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
- heap_counter_(0) {
+ heap_counter_(0),
+ count_comparator_(BytewiseComparator()),
+ total_thread_count_(0) {
std::vector files;
g_env->GetChildren(FLAGS_db, &files);
for (size_t i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("heap-")) {
- g_env->DeleteFile(std::string(FLAGS_db) + "/" + files[i]);
+ g_env->RemoveFile(std::string(FLAGS_db) + "/" + files[i]);
}
}
if (!FLAGS_use_existing_db) {
@@ -487,6 +554,8 @@ class Benchmark {
method = &Benchmark::ReadMissing;
} else if (name == Slice("seekrandom")) {
method = &Benchmark::SeekRandom;
+ } else if (name == Slice("seekordered")) {
+ method = &Benchmark::SeekOrdered;
} else if (name == Slice("readhot")) {
method = &Benchmark::ReadHot;
} else if (name == Slice("readrandomsmall")) {
@@ -515,14 +584,15 @@ class Benchmark {
PrintStats("leveldb.sstables");
} else {
if (!name.empty()) { // No error message for empty name
- fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());
+ std::fprintf(stderr, "unknown benchmark '%s'\n",
+ name.ToString().c_str());
}
}
if (fresh_db) {
if (FLAGS_use_existing_db) {
- fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n",
- name.ToString().c_str());
+ std::fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n",
+ name.ToString().c_str());
method = nullptr;
} else {
delete db_;
@@ -583,7 +653,11 @@ class Benchmark {
arg[i].bm = this;
arg[i].method = method;
arg[i].shared = &shared;
- arg[i].thread = new ThreadState(i);
+ ++total_thread_count_;
+ // Seed the thread's random state deterministically based upon thread
+ // creation across all benchmarks. This ensures that the seeds are unique
+ // but reproducible when rerunning the same set of benchmarks.
+ arg[i].thread = new ThreadState(i, /*seed=*/1000 + total_thread_count_);
arg[i].thread->shared = &shared;
g_env->StartThread(ThreadBody, &arg[i]);
}
@@ -604,6 +678,11 @@ class Benchmark {
arg[0].thread->stats.Merge(arg[i].thread->stats);
}
arg[0].thread->stats.Report(name);
+ if (FLAGS_comparisons) {
+ fprintf(stdout, "Comparisons: %zu\n", count_comparator_.comparisons());
+ count_comparator_.reset();
+ fflush(stdout);
+ }
for (int i = 0; i < n; i++) {
delete arg[i].thread;
@@ -624,7 +703,7 @@ class Benchmark {
bytes += size;
}
// Print so result is not dead
- fprintf(stderr, "... crc=0x%x\r", static_cast(crc));
+ std::fprintf(stderr, "... crc=0x%x\r", static_cast(crc));
thread->stats.AddBytes(bytes);
thread->stats.AddMessage(label);
@@ -648,8 +727,8 @@ class Benchmark {
thread->stats.AddMessage("(snappy failure)");
} else {
char buf[100];
- snprintf(buf, sizeof(buf), "(output: %.1f%%)",
- (produced * 100.0) / bytes);
+ std::snprintf(buf, sizeof(buf), "(output: %.1f%%)",
+ (produced * 100.0) / bytes);
thread->stats.AddMessage(buf);
thread->stats.AddBytes(bytes);
}
@@ -686,13 +765,16 @@ class Benchmark {
options.write_buffer_size = FLAGS_write_buffer_size;
options.max_file_size = FLAGS_max_file_size;
options.block_size = FLAGS_block_size;
+ if (FLAGS_comparisons) {
+ options.comparator = &count_comparator_;
+ }
options.max_open_files = FLAGS_open_files;
options.filter_policy = filter_policy_;
options.reuse_logs = FLAGS_reuse_logs;
Status s = DB::Open(options, FLAGS_db, &db_);
if (!s.ok()) {
- fprintf(stderr, "open error: %s\n", s.ToString().c_str());
- exit(1);
+ std::fprintf(stderr, "open error: %s\n", s.ToString().c_str());
+ std::exit(1);
}
}
@@ -711,7 +793,7 @@ class Benchmark {
void DoWrite(ThreadState* thread, bool seq) {
if (num_ != FLAGS_num) {
char msg[100];
- snprintf(msg, sizeof(msg), "(%d ops)", num_);
+ std::snprintf(msg, sizeof(msg), "(%d ops)", num_);
thread->stats.AddMessage(msg);
}
@@ -719,20 +801,20 @@ class Benchmark {
WriteBatch batch;
Status s;
int64_t bytes = 0;
+ KeyBuffer key;
for (int i = 0; i < num_; i += entries_per_batch_) {
batch.Clear();
for (int j = 0; j < entries_per_batch_; j++) {
- const int k = seq ? i + j : (thread->rand.Next() % FLAGS_num);
- char key[100];
- snprintf(key, sizeof(key), "%016d", k);
- batch.Put(key, gen.Generate(value_size_));
- bytes += value_size_ + strlen(key);
+ const int k = seq ? i + j : thread->rand.Uniform(FLAGS_num);
+ key.Set(k);
+ batch.Put(key.slice(), gen.Generate(value_size_));
+ bytes += value_size_ + key.slice().size();
thread->stats.FinishedSingleOp();
}
s = db_->Write(write_options_, &batch);
if (!s.ok()) {
- fprintf(stderr, "put error: %s\n", s.ToString().c_str());
- exit(1);
+ std::fprintf(stderr, "put error: %s\n", s.ToString().c_str());
+ std::exit(1);
}
}
thread->stats.AddBytes(bytes);
@@ -768,28 +850,29 @@ class Benchmark {
ReadOptions options;
std::string value;
int found = 0;
+ KeyBuffer key;
for (int i = 0; i < reads_; i++) {
- char key[100];
- const int k = thread->rand.Next() % FLAGS_num;
- snprintf(key, sizeof(key), "%016d", k);
- if (db_->Get(options, key, &value).ok()) {
+ const int k = thread->rand.Uniform(FLAGS_num);
+ key.Set(k);
+ if (db_->Get(options, key.slice(), &value).ok()) {
found++;
}
thread->stats.FinishedSingleOp();
}
char msg[100];
- snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_);
+ std::snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_);
thread->stats.AddMessage(msg);
}
void ReadMissing(ThreadState* thread) {
ReadOptions options;
std::string value;
+ KeyBuffer key;
for (int i = 0; i < reads_; i++) {
- char key[100];
- const int k = thread->rand.Next() % FLAGS_num;
- snprintf(key, sizeof(key), "%016d.", k);
- db_->Get(options, key, &value);
+ const int k = thread->rand.Uniform(FLAGS_num);
+ key.Set(k);
+ Slice s = Slice(key.slice().data(), key.slice().size() - 1);
+ db_->Get(options, s, &value);
thread->stats.FinishedSingleOp();
}
}
@@ -798,11 +881,11 @@ class Benchmark {
ReadOptions options;
std::string value;
const int range = (FLAGS_num + 99) / 100;
+ KeyBuffer key;
for (int i = 0; i < reads_; i++) {
- char key[100];
- const int k = thread->rand.Next() % range;
- snprintf(key, sizeof(key), "%016d", k);
- db_->Get(options, key, &value);
+ const int k = thread->rand.Uniform(range);
+ key.Set(k);
+ db_->Get(options, key.slice(), &value);
thread->stats.FinishedSingleOp();
}
}
@@ -810,13 +893,13 @@ class Benchmark {
void SeekRandom(ThreadState* thread) {
ReadOptions options;
int found = 0;
+ KeyBuffer key;
for (int i = 0; i < reads_; i++) {
Iterator* iter = db_->NewIterator(options);
- char key[100];
- const int k = thread->rand.Next() % FLAGS_num;
- snprintf(key, sizeof(key), "%016d", k);
- iter->Seek(key);
- if (iter->Valid() && iter->key() == key) found++;
+ const int k = thread->rand.Uniform(FLAGS_num);
+ key.Set(k);
+ iter->Seek(key.slice());
+ if (iter->Valid() && iter->key() == key.slice()) found++;
delete iter;
thread->stats.FinishedSingleOp();
}
@@ -825,23 +908,42 @@ class Benchmark {
thread->stats.AddMessage(msg);
}
+ void SeekOrdered(ThreadState* thread) {
+ ReadOptions options;
+ Iterator* iter = db_->NewIterator(options);
+ int found = 0;
+ int k = 0;
+ KeyBuffer key;
+ for (int i = 0; i < reads_; i++) {
+ k = (k + (thread->rand.Uniform(100))) % FLAGS_num;
+ key.Set(k);
+ iter->Seek(key.slice());
+ if (iter->Valid() && iter->key() == key.slice()) found++;
+ thread->stats.FinishedSingleOp();
+ }
+ delete iter;
+ char msg[100];
+ std::snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_);
+ thread->stats.AddMessage(msg);
+ }
+
void DoDelete(ThreadState* thread, bool seq) {
RandomGenerator gen;
WriteBatch batch;
Status s;
+ KeyBuffer key;
for (int i = 0; i < num_; i += entries_per_batch_) {
batch.Clear();
for (int j = 0; j < entries_per_batch_; j++) {
- const int k = seq ? i + j : (thread->rand.Next() % FLAGS_num);
- char key[100];
- snprintf(key, sizeof(key), "%016d", k);
- batch.Delete(key);
+ const int k = seq ? i + j : (thread->rand.Uniform(FLAGS_num));
+ key.Set(k);
+ batch.Delete(key.slice());
thread->stats.FinishedSingleOp();
}
s = db_->Write(write_options_, &batch);
if (!s.ok()) {
- fprintf(stderr, "del error: %s\n", s.ToString().c_str());
- exit(1);
+ std::fprintf(stderr, "del error: %s\n", s.ToString().c_str());
+ std::exit(1);
}
}
}
@@ -856,6 +958,7 @@ class Benchmark {
} else {
// Special thread that keeps writing until other threads are done.
RandomGenerator gen;
+ KeyBuffer key;
while (true) {
{
MutexLock l(&thread->shared->mu);
@@ -865,13 +968,13 @@ class Benchmark {
}
}
- const int k = thread->rand.Next() % FLAGS_num;
- char key[100];
- snprintf(key, sizeof(key), "%016d", k);
- Status s = db_->Put(write_options_, key, gen.Generate(value_size_));
+ const int k = thread->rand.Uniform(FLAGS_num);
+ key.Set(k);
+ Status s =
+ db_->Put(write_options_, key.slice(), gen.Generate(value_size_));
if (!s.ok()) {
- fprintf(stderr, "put error: %s\n", s.ToString().c_str());
- exit(1);
+ std::fprintf(stderr, "put error: %s\n", s.ToString().c_str());
+ std::exit(1);
}
}
@@ -887,7 +990,7 @@ class Benchmark {
if (!db_->GetProperty(key, &stats)) {
stats = "(failed)";
}
- fprintf(stdout, "\n%s\n", stats.c_str());
+ std::fprintf(stdout, "\n%s\n", stats.c_str());
}
static void WriteToFile(void* arg, const char* buf, int n) {
@@ -896,18 +999,19 @@ class Benchmark {
void HeapProfile() {
char fname[100];
- snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db, ++heap_counter_);
+ std::snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db,
+ ++heap_counter_);
WritableFile* file;
Status s = g_env->NewWritableFile(fname, &file);
if (!s.ok()) {
- fprintf(stderr, "%s\n", s.ToString().c_str());
+ std::fprintf(stderr, "%s\n", s.ToString().c_str());
return;
}
bool ok = port::GetHeapProfile(WriteToFile, file);
delete file;
if (!ok) {
- fprintf(stderr, "heap profiling not supported\n");
- g_env->DeleteFile(fname);
+ std::fprintf(stderr, "heap profiling not supported\n");
+ g_env->RemoveFile(fname);
}
}
};
@@ -932,6 +1036,9 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_histogram = n;
+ } else if (sscanf(argv[i], "--comparisons=%d%c", &n, &junk) == 1 &&
+ (n == 0 || n == 1)) {
+ FLAGS_comparisons = n;
} else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_use_existing_db = n;
@@ -952,6 +1059,8 @@ int main(int argc, char** argv) {
FLAGS_max_file_size = n;
} else if (sscanf(argv[i], "--block_size=%d%c", &n, &junk) == 1) {
FLAGS_block_size = n;
+ } else if (sscanf(argv[i], "--key_prefix=%d%c", &n, &junk) == 1) {
+ FLAGS_key_prefix = n;
} else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) {
FLAGS_cache_size = n;
} else if (sscanf(argv[i], "--bloom_bits=%d%c", &n, &junk) == 1) {
@@ -961,8 +1070,8 @@ int main(int argc, char** argv) {
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
- fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
- exit(1);
+ std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
+ std::exit(1);
}
}
diff --git a/benchmarks/db_bench_log.cc b/benchmarks/db_bench_log.cc
new file mode 100644
index 0000000..a1845bf
--- /dev/null
+++ b/benchmarks/db_bench_log.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2019 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
+#include
+#include
+
+#include "gtest/gtest.h"
+#include "benchmark/benchmark.h"
+#include "db/version_set.h"
+#include "leveldb/comparator.h"
+#include "leveldb/db.h"
+#include "leveldb/env.h"
+#include "leveldb/options.h"
+#include "port/port.h"
+#include "util/mutexlock.h"
+#include "util/testutil.h"
+
+namespace leveldb {
+
+namespace {
+
+std::string MakeKey(unsigned int num) {
+ char buf[30];
+ std::snprintf(buf, sizeof(buf), "%016u", num);
+ return std::string(buf);
+}
+
+void BM_LogAndApply(benchmark::State& state) {
+ const int num_base_files = state.range(0);
+
+ std::string dbname = testing::TempDir() + "leveldb_test_benchmark";
+ DestroyDB(dbname, Options());
+
+ DB* db = nullptr;
+ Options opts;
+ opts.create_if_missing = true;
+ Status s = DB::Open(opts, dbname, &db);
+ ASSERT_LEVELDB_OK(s);
+ ASSERT_TRUE(db != nullptr);
+
+ delete db;
+ db = nullptr;
+
+ Env* env = Env::Default();
+
+ port::Mutex mu;
+ MutexLock l(&mu);
+
+ InternalKeyComparator cmp(BytewiseComparator());
+ Options options;
+ VersionSet vset(dbname, &options, nullptr, &cmp);
+ bool save_manifest;
+ ASSERT_LEVELDB_OK(vset.Recover(&save_manifest));
+ VersionEdit vbase;
+ uint64_t fnum = 1;
+ for (int i = 0; i < num_base_files; i++) {
+ InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);
+ InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);
+ vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);
+ }
+ ASSERT_LEVELDB_OK(vset.LogAndApply(&vbase, &mu));
+
+ uint64_t start_micros = env->NowMicros();
+
+ for (auto st : state) {
+ VersionEdit vedit;
+ vedit.RemoveFile(2, fnum);
+ InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);
+ InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);
+ vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);
+ vset.LogAndApply(&vedit, &mu);
+ }
+
+ uint64_t stop_micros = env->NowMicros();
+ unsigned int us = stop_micros - start_micros;
+ char buf[16];
+ std::snprintf(buf, sizeof(buf), "%d", num_base_files);
+ std::fprintf(stderr,
+ "BM_LogAndApply/%-6s %8" PRIu64
+ " iters : %9u us (%7.0f us / iter)\n",
+ buf, state.iterations(), us, ((float)us) / state.iterations());
+}
+
+BENCHMARK(BM_LogAndApply)->Arg(1)->Arg(100)->Arg(10000)->Arg(100000);
+
+} // namespace
+
+} // namespace leveldb
+
+BENCHMARK_MAIN();
diff --git a/benchmarks/db_bench_sqlite3.cc b/benchmarks/db_bench_sqlite3.cc
index f183f4f..c9be652 100644
--- a/benchmarks/db_bench_sqlite3.cc
+++ b/benchmarks/db_bench_sqlite3.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include
-#include
-#include
+
+#include
+#include
#include "util/histogram.h"
#include "util/random.h"
@@ -69,6 +70,9 @@ static int FLAGS_num_pages = 4096;
// benchmark will fail.
static bool FLAGS_use_existing_db = false;
+// If true, the SQLite table has ROWIDs.
+static bool FLAGS_use_rowids = false;
+
// If true, we allow batch writes to occur
static bool FLAGS_transaction = true;
@@ -80,23 +84,23 @@ static const char* FLAGS_db = nullptr;
inline static void ExecErrorCheck(int status, char* err_msg) {
if (status != SQLITE_OK) {
- fprintf(stderr, "SQL error: %s\n", err_msg);
+ std::fprintf(stderr, "SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
- exit(1);
+ std::exit(1);
}
}
inline static void StepErrorCheck(int status) {
if (status != SQLITE_DONE) {
- fprintf(stderr, "SQL step error: status = %d\n", status);
- exit(1);
+ std::fprintf(stderr, "SQL step error: status = %d\n", status);
+ std::exit(1);
}
}
inline static void ErrorCheck(int status) {
if (status != SQLITE_OK) {
- fprintf(stderr, "sqlite3 error: status = %d\n", status);
- exit(1);
+ std::fprintf(stderr, "sqlite3 error: status = %d\n", status);
+ std::exit(1);
}
}
@@ -178,36 +182,38 @@ class Benchmark {
void PrintHeader() {
const int kKeySize = 16;
PrintEnvironment();
- fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
- fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size);
- fprintf(stdout, "Entries: %d\n", num_);
- fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
- ((static_cast(kKeySize + FLAGS_value_size) * num_) /
- 1048576.0));
+ std::fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
+ std::fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size);
+ std::fprintf(stdout, "Entries: %d\n", num_);
+ std::fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
+ ((static_cast(kKeySize + FLAGS_value_size) * num_) /
+ 1048576.0));
PrintWarnings();
- fprintf(stdout, "------------------------------------------------\n");
+ std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
- fprintf(
+ std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
- fprintf(stdout,
- "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
+ std::fprintf(
+ stdout,
+ "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
}
void PrintEnvironment() {
- fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION);
+ std::fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION);
#if defined(__linux)
time_t now = time(nullptr);
- fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline
+ std::fprintf(stderr, "Date: %s",
+ ctime(&now)); // ctime() adds newline
- FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
+ FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
@@ -227,9 +233,9 @@ class Benchmark {
cache_size = val.ToString();
}
}
- fclose(cpuinfo);
- fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
- fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
+ std::fclose(cpuinfo);
+ std::fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
+ std::fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
}
#endif
}
@@ -250,8 +256,8 @@ class Benchmark {
double micros = (now - last_op_finish_) * 1e6;
hist_.Add(micros);
if (micros > 20000) {
- fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
- fflush(stderr);
+ std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
+ std::fflush(stderr);
}
last_op_finish_ = now;
}
@@ -272,8 +278,8 @@ class Benchmark {
next_report_ += 50000;
else
next_report_ += 100000;
- fprintf(stderr, "... finished %d ops%30s\r", done_, "");
- fflush(stderr);
+ std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
+ std::fflush(stderr);
}
}
@@ -286,8 +292,8 @@ class Benchmark {
if (bytes_ > 0) {
char rate[100];
- snprintf(rate, sizeof(rate), "%6.1f MB/s",
- (bytes_ / 1048576.0) / (finish - start_));
+ std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
+ (bytes_ / 1048576.0) / (finish - start_));
if (!message_.empty()) {
message_ = std::string(rate) + " " + message_;
} else {
@@ -295,13 +301,14 @@ class Benchmark {
}
}
- fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", name.ToString().c_str(),
- (finish - start_) * 1e6 / done_, (message_.empty() ? "" : " "),
- message_.c_str());
+ std::fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n",
+ name.ToString().c_str(), (finish - start_) * 1e6 / done_,
+ (message_.empty() ? "" : " "), message_.c_str());
if (FLAGS_histogram) {
- fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());
+ std::fprintf(stdout, "Microseconds per op:\n%s\n",
+ hist_.ToString().c_str());
}
- fflush(stdout);
+ std::fflush(stdout);
}
public:
@@ -325,7 +332,7 @@ class Benchmark {
std::string file_name(test_dir);
file_name += "/";
file_name += files[i];
- Env::Default()->DeleteFile(file_name.c_str());
+ Env::Default()->RemoveFile(file_name.c_str());
}
}
}
@@ -401,7 +408,8 @@ class Benchmark {
} else {
known = false;
if (name != Slice()) { // No error message for empty name
- fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());
+ std::fprintf(stderr, "unknown benchmark '%s'\n",
+ name.ToString().c_str());
}
}
if (known) {
@@ -421,26 +429,26 @@ class Benchmark {
// Open database
std::string tmp_dir;
Env::Default()->GetTestDirectory(&tmp_dir);
- snprintf(file_name, sizeof(file_name), "%s/dbbench_sqlite3-%d.db",
- tmp_dir.c_str(), db_num_);
+ std::snprintf(file_name, sizeof(file_name), "%s/dbbench_sqlite3-%d.db",
+ tmp_dir.c_str(), db_num_);
status = sqlite3_open(file_name, &db_);
if (status) {
- fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_));
- exit(1);
+ std::fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_));
+ std::exit(1);
}
// Change SQLite cache size
char cache_size[100];
- snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d",
- FLAGS_num_pages);
+ std::snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d",
+ FLAGS_num_pages);
status = sqlite3_exec(db_, cache_size, nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
// FLAGS_page_size is defaulted to 1024
if (FLAGS_page_size != 1024) {
char page_size[100];
- snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d",
- FLAGS_page_size);
+ std::snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d",
+ FLAGS_page_size);
status = sqlite3_exec(db_, page_size, nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
}
@@ -462,6 +470,7 @@ class Benchmark {
std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE";
std::string create_stmt =
"CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))";
+ if (!FLAGS_use_rowids) create_stmt += " WITHOUT ROWID";
std::string stmt_array[] = {locking_stmt, create_stmt};
int stmt_array_length = sizeof(stmt_array) / sizeof(std::string);
for (int i = 0; i < stmt_array_length; i++) {
@@ -487,7 +496,7 @@ class Benchmark {
if (num_entries != num_) {
char msg[100];
- snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
+ std::snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
message_ = msg;
}
@@ -534,7 +543,7 @@ class Benchmark {
const int k =
(order == SEQUENTIAL) ? i + j : (rand_.Next() % num_entries);
char key[100];
- snprintf(key, sizeof(key), "%016d", k);
+ std::snprintf(key, sizeof(key), "%016d", k);
// Bind KV values into replace_stmt
status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC);
@@ -607,7 +616,7 @@ class Benchmark {
// Create key value
char key[100];
int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_);
- snprintf(key, sizeof(key), "%016d", k);
+ std::snprintf(key, sizeof(key), "%016d", k);
// Bind key value into read_stmt
status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC);
@@ -678,6 +687,9 @@ int main(int argc, char** argv) {
} else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_use_existing_db = n;
+ } else if (sscanf(argv[i], "--use_rowids=%d%c", &n, &junk) == 1 &&
+ (n == 0 || n == 1)) {
+ FLAGS_use_rowids = n;
} else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) {
FLAGS_num = n;
} else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {
@@ -696,8 +708,8 @@ int main(int argc, char** argv) {
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
- fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
- exit(1);
+ std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
+ std::exit(1);
}
}
diff --git a/benchmarks/db_bench_tree_db.cc b/benchmarks/db_bench_tree_db.cc
index b2f6646..533600b 100644
--- a/benchmarks/db_bench_tree_db.cc
+++ b/benchmarks/db_bench_tree_db.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include
-#include
-#include
+
+#include
+#include
#include "util/histogram.h"
#include "util/random.h"
@@ -74,7 +75,7 @@ static const char* FLAGS_db = nullptr;
inline static void DBSynchronize(kyotocabinet::TreeDB* db_) {
// Synchronize will flush writes to disk
if (!db_->synchronize()) {
- fprintf(stderr, "synchronize error: %s\n", db_->error().name());
+ std::fprintf(stderr, "synchronize error: %s\n", db_->error().name());
}
}
@@ -149,42 +150,47 @@ class Benchmark {
void PrintHeader() {
const int kKeySize = 16;
PrintEnvironment();
- fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
- fprintf(stdout, "Values: %d bytes each (%d bytes after compression)\n",
- FLAGS_value_size,
- static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
- fprintf(stdout, "Entries: %d\n", num_);
- fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
- ((static_cast(kKeySize + FLAGS_value_size) * num_) /
- 1048576.0));
- fprintf(stdout, "FileSize: %.1f MB (estimated)\n",
- (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /
- 1048576.0));
+ std::fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
+ std::fprintf(
+ stdout, "Values: %d bytes each (%d bytes after compression)\n",
+ FLAGS_value_size,
+ static_cast(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
+ std::fprintf(stdout, "Entries: %d\n", num_);
+ std::fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
+ ((static_cast(kKeySize + FLAGS_value_size) * num_) /
+ 1048576.0));
+ std::fprintf(
+ stdout, "FileSize: %.1f MB (estimated)\n",
+ (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_) /
+ 1048576.0));
PrintWarnings();
- fprintf(stdout, "------------------------------------------------\n");
+ std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
- fprintf(
+ std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
- fprintf(stdout,
- "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
+ std::fprintf(
+ stdout,
+ "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
}
void PrintEnvironment() {
- fprintf(stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n",
- kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV);
+ std::fprintf(
+ stderr, "Kyoto Cabinet: version %s, lib ver %d, lib rev %d\n",
+ kyotocabinet::VERSION, kyotocabinet::LIBVER, kyotocabinet::LIBREV);
#if defined(__linux)
time_t now = time(nullptr);
- fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline
+ std::fprintf(stderr, "Date: %s",
+ ctime(&now)); // ctime() adds newline
- FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
+ FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
@@ -204,9 +210,10 @@ class Benchmark {
cache_size = val.ToString();
}
}
- fclose(cpuinfo);
- fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
- fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
+ std::fclose(cpuinfo);
+ std::fprintf(stderr, "CPU: %d * %s\n", num_cpus,
+ cpu_type.c_str());
+ std::fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
}
#endif
}
@@ -227,8 +234,8 @@ class Benchmark {
double micros = (now - last_op_finish_) * 1e6;
hist_.Add(micros);
if (micros > 20000) {
- fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
- fflush(stderr);
+ std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
+ std::fflush(stderr);
}
last_op_finish_ = now;
}
@@ -249,8 +256,8 @@ class Benchmark {
next_report_ += 50000;
else
next_report_ += 100000;
- fprintf(stderr, "... finished %d ops%30s\r", done_, "");
- fflush(stderr);
+ std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
+ std::fflush(stderr);
}
}
@@ -263,8 +270,8 @@ class Benchmark {
if (bytes_ > 0) {
char rate[100];
- snprintf(rate, sizeof(rate), "%6.1f MB/s",
- (bytes_ / 1048576.0) / (finish - start_));
+ std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
+ (bytes_ / 1048576.0) / (finish - start_));
if (!message_.empty()) {
message_ = std::string(rate) + " " + message_;
} else {
@@ -272,13 +279,14 @@ class Benchmark {
}
}
- fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n", name.ToString().c_str(),
- (finish - start_) * 1e6 / done_, (message_.empty() ? "" : " "),
- message_.c_str());
+ std::fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n",
+ name.ToString().c_str(), (finish - start_) * 1e6 / done_,
+ (message_.empty() ? "" : " "), message_.c_str());
if (FLAGS_histogram) {
- fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());
+ std::fprintf(stdout, "Microseconds per op:\n%s\n",
+ hist_.ToString().c_str());
}
- fflush(stdout);
+ std::fflush(stdout);
}
public:
@@ -301,7 +309,7 @@ class Benchmark {
std::string file_name(test_dir);
file_name += "/";
file_name += files[i];
- Env::Default()->DeleteFile(file_name.c_str());
+ Env::Default()->RemoveFile(file_name.c_str());
}
}
}
@@ -309,7 +317,7 @@ class Benchmark {
~Benchmark() {
if (!db_->close()) {
- fprintf(stderr, "close error: %s\n", db_->error().name());
+ std::fprintf(stderr, "close error: %s\n", db_->error().name());
}
}
@@ -373,7 +381,8 @@ class Benchmark {
} else {
known = false;
if (name != Slice()) { // No error message for empty name
- fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());
+ std::fprintf(stderr, "unknown benchmark '%s'\n",
+ name.ToString().c_str());
}
}
if (known) {
@@ -392,8 +401,8 @@ class Benchmark {
db_num_++;
std::string test_dir;
Env::Default()->GetTestDirectory(&test_dir);
- snprintf(file_name, sizeof(file_name), "%s/dbbench_polyDB-%d.kct",
- test_dir.c_str(), db_num_);
+ std::snprintf(file_name, sizeof(file_name), "%s/dbbench_polyDB-%d.kct",
+ test_dir.c_str(), db_num_);
// Create tuning options and open the database
int open_options =
@@ -412,7 +421,7 @@ class Benchmark {
open_options |= kyotocabinet::PolyDB::OAUTOSYNC;
}
if (!db_->open(file_name, open_options)) {
- fprintf(stderr, "open error: %s\n", db_->error().name());
+ std::fprintf(stderr, "open error: %s\n", db_->error().name());
}
}
@@ -432,7 +441,7 @@ class Benchmark {
if (num_entries != num_) {
char msg[100];
- snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
+ std::snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
message_ = msg;
}
@@ -440,11 +449,11 @@ class Benchmark {
for (int i = 0; i < num_entries; i++) {
const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries);
char key[100];
- snprintf(key, sizeof(key), "%016d", k);
+ std::snprintf(key, sizeof(key), "%016d", k);
bytes_ += value_size + strlen(key);
std::string cpp_key = key;
if (!db_->set(cpp_key, gen_.Generate(value_size).ToString())) {
- fprintf(stderr, "set error: %s\n", db_->error().name());
+ std::fprintf(stderr, "set error: %s\n", db_->error().name());
}
FinishedSingleOp();
}
@@ -466,7 +475,7 @@ class Benchmark {
for (int i = 0; i < reads_; i++) {
char key[100];
const int k = rand_.Next() % reads_;
- snprintf(key, sizeof(key), "%016d", k);
+ std::snprintf(key, sizeof(key), "%016d", k);
db_->get(key, &value);
FinishedSingleOp();
}
@@ -504,8 +513,8 @@ int main(int argc, char** argv) {
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
- fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
- exit(1);
+ std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
+ std::exit(1);
}
}
diff --git a/cmake/leveldbConfig.cmake b/cmake/leveldbConfig.cmake
deleted file mode 100644
index eea6e5c..0000000
--- a/cmake/leveldbConfig.cmake
+++ /dev/null
@@ -1 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/leveldbTargets.cmake")
diff --git a/cmake/leveldbConfig.cmake.in b/cmake/leveldbConfig.cmake.in
new file mode 100644
index 0000000..2572728
--- /dev/null
+++ b/cmake/leveldbConfig.cmake.in
@@ -0,0 +1,9 @@
+# Copyright 2019 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.
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/leveldbTargets.cmake")
+
+check_required_components(leveldb)
\ No newline at end of file
diff --git a/db/autocompact_test.cc b/db/autocompact_test.cc
index e6c97a0..69341e3 100644
--- a/db/autocompact_test.cc
+++ b/db/autocompact_test.cc
@@ -2,24 +2,24 @@
// 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 "db/db_impl.h"
#include "leveldb/cache.h"
#include "leveldb/db.h"
-#include "util/testharness.h"
#include "util/testutil.h"
namespace leveldb {
-class AutoCompactTest {
+class AutoCompactTest : public testing::Test {
public:
AutoCompactTest() {
- dbname_ = test::TmpDir() + "/autocompact_test";
+ dbname_ = testing::TempDir() + "autocompact_test";
tiny_cache_ = NewLRUCache(100);
options_.block_cache = tiny_cache_;
DestroyDB(dbname_, options_);
options_.create_if_missing = true;
options_.compression = kNoCompression;
- ASSERT_OK(DB::Open(options_, dbname_, &db_));
+ EXPECT_LEVELDB_OK(DB::Open(options_, dbname_, &db_));
}
~AutoCompactTest() {
@@ -30,7 +30,7 @@ class AutoCompactTest {
std::string Key(int i) {
char buf[100];
- snprintf(buf, sizeof(buf), "key%06d", i);
+ std::snprintf(buf, sizeof(buf), "key%06d", i);
return std::string(buf);
}
@@ -62,15 +62,15 @@ void AutoCompactTest::DoReads(int n) {
// Fill database
for (int i = 0; i < kCount; i++) {
- ASSERT_OK(db_->Put(WriteOptions(), Key(i), value));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), Key(i), value));
}
- ASSERT_OK(dbi->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbi->TEST_CompactMemTable());
// Delete everything
for (int i = 0; i < kCount; i++) {
- ASSERT_OK(db_->Delete(WriteOptions(), Key(i)));
+ ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), Key(i)));
}
- ASSERT_OK(dbi->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbi->TEST_CompactMemTable());
// Get initial measurement of the space we will be reading.
const int64_t initial_size = Size(Key(0), Key(n));
@@ -89,8 +89,8 @@ void AutoCompactTest::DoReads(int n) {
// Wait a little bit to allow any triggered compactions to complete.
Env::Default()->SleepForMicroseconds(1000000);
uint64_t size = Size(Key(0), Key(n));
- fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", read + 1,
- size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0);
+ std::fprintf(stderr, "iter %3d => %7.3f MB [other %7.3f MB]\n", read + 1,
+ size / 1048576.0, Size(Key(n), Key(kCount)) / 1048576.0);
if (size <= initial_size / 10) {
break;
}
@@ -103,10 +103,8 @@ void AutoCompactTest::DoReads(int n) {
ASSERT_GE(final_other_size, initial_other_size / 5 - 1048576);
}
-TEST(AutoCompactTest, ReadAll) { DoReads(kCount); }
+TEST_F(AutoCompactTest, ReadAll) { DoReads(kCount); }
-TEST(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); }
+TEST_F(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); }
} // namespace leveldb
-
-int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
diff --git a/db/builder.cc b/db/builder.cc
index 9520ee4..e6329e0 100644
--- a/db/builder.cc
+++ b/db/builder.cc
@@ -30,11 +30,14 @@ Status BuildTable(const std::string& dbname, Env* env, const Options& options,
TableBuilder* builder = new TableBuilder(options, file);
meta->smallest.DecodeFrom(iter->key());
+ Slice key;
for (; iter->Valid(); iter->Next()) {
- Slice key = iter->key();
- meta->largest.DecodeFrom(key);
+ key = iter->key();
builder->Add(key, iter->value());
}
+ if (!key.empty()) {
+ meta->largest.DecodeFrom(key);
+ }
// Finish and check for builder errors
s = builder->Finish();
@@ -71,7 +74,7 @@ Status BuildTable(const std::string& dbname, Env* env, const Options& options,
if (s.ok() && meta->file_size > 0) {
// Keep it
} else {
- env->DeleteFile(fname);
+ env->RemoveFile(fname);
}
return s;
}
diff --git a/db/c.cc b/db/c.cc
index 3a492f9..8bdde38 100644
--- a/db/c.cc
+++ b/db/c.cc
@@ -4,6 +4,8 @@
#include "leveldb/c.h"
+#include
+
#include
#include
@@ -119,7 +121,7 @@ struct leveldb_filterpolicy_t : public FilterPolicy {
size_t len;
char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len);
dst->append(filter, len);
- free(filter);
+ std::free(filter);
}
bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
@@ -150,15 +152,16 @@ static bool SaveError(char** errptr, const Status& s) {
*errptr = strdup(s.ToString().c_str());
} else {
// TODO(sanjay): Merge with existing error?
- free(*errptr);
+ std::free(*errptr);
*errptr = strdup(s.ToString().c_str());
}
return true;
}
static char* CopyString(const std::string& str) {
- char* result = reinterpret_cast(malloc(sizeof(char) * str.size()));
- memcpy(result, str.data(), sizeof(char) * str.size());
+ char* result =
+ reinterpret_cast(std::malloc(sizeof(char) * str.size()));
+ std::memcpy(result, str.data(), sizeof(char) * str.size());
return result;
}
@@ -547,13 +550,13 @@ char* leveldb_env_get_test_directory(leveldb_env_t* env) {
return nullptr;
}
- char* buffer = static_cast(malloc(result.size() + 1));
- memcpy(buffer, result.data(), result.size());
+ char* buffer = static_cast(std::malloc(result.size() + 1));
+ std::memcpy(buffer, result.data(), result.size());
buffer[result.size()] = '\0';
return buffer;
}
-void leveldb_free(void* ptr) { free(ptr); }
+void leveldb_free(void* ptr) { std::free(ptr); }
int leveldb_major_version() { return kMajorVersion; }
diff --git a/db/corruption_test.cc b/db/corruption_test.cc
index 42f5237..dc7da76 100644
--- a/db/corruption_test.cc
+++ b/db/corruption_test.cc
@@ -4,6 +4,7 @@
#include
+#include "gtest/gtest.h"
#include "db/db_impl.h"
#include "db/filename.h"
#include "db/log_format.h"
@@ -13,14 +14,13 @@
#include "leveldb/table.h"
#include "leveldb/write_batch.h"
#include "util/logging.h"
-#include "util/testharness.h"
#include "util/testutil.h"
namespace leveldb {
static const int kValueSize = 1000;
-class CorruptionTest {
+class CorruptionTest : public testing::Test {
public:
CorruptionTest()
: db_(nullptr),
@@ -46,19 +46,19 @@ class CorruptionTest {
return DB::Open(options_, dbname_, &db_);
}
- void Reopen() { ASSERT_OK(TryReopen()); }
+ void Reopen() { ASSERT_LEVELDB_OK(TryReopen()); }
void RepairDB() {
delete db_;
db_ = nullptr;
- ASSERT_OK(::leveldb::RepairDB(dbname_, options_));
+ ASSERT_LEVELDB_OK(::leveldb::RepairDB(dbname_, options_));
}
void Build(int n) {
std::string key_space, value_space;
WriteBatch batch;
for (int i = 0; i < n; i++) {
- // if ((i % 100) == 0) fprintf(stderr, "@ %d of %d\n", i, n);
+ // if ((i % 100) == 0) std::fprintf(stderr, "@ %d of %d\n", i, n);
Slice key = Key(i, &key_space);
batch.Clear();
batch.Put(key, Value(i, &value_space));
@@ -68,7 +68,7 @@ class CorruptionTest {
if (i == n - 1) {
options.sync = true;
}
- ASSERT_OK(db_->Write(options, &batch));
+ ASSERT_LEVELDB_OK(db_->Write(options, &batch));
}
}
@@ -102,9 +102,10 @@ class CorruptionTest {
}
delete iter;
- fprintf(stderr,
- "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n",
- min_expected, max_expected, correct, bad_keys, bad_values, missed);
+ std::fprintf(
+ stderr,
+ "expected=%d..%d; got=%d; bad_keys=%d; bad_values=%d; missed=%d\n",
+ min_expected, max_expected, correct, bad_keys, bad_values, missed);
ASSERT_LE(min_expected, correct);
ASSERT_GE(max_expected, correct);
}
@@ -112,7 +113,7 @@ class CorruptionTest {
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
// Pick file to corrupt
std::vector filenames;
- ASSERT_OK(env_.target()->GetChildren(dbname_, &filenames));
+ ASSERT_LEVELDB_OK(env_.target()->GetChildren(dbname_, &filenames));
uint64_t number;
FileType type;
std::string fname;
@@ -127,7 +128,7 @@ class CorruptionTest {
ASSERT_TRUE(!fname.empty()) << filetype;
uint64_t file_size;
- ASSERT_OK(env_.target()->GetFileSize(fname, &file_size));
+ ASSERT_LEVELDB_OK(env_.target()->GetFileSize(fname, &file_size));
if (offset < 0) {
// Relative to end of file; make it absolute
@@ -169,7 +170,7 @@ class CorruptionTest {
// Return the ith key
Slice Key(int i, std::string* storage) {
char buf[100];
- snprintf(buf, sizeof(buf), "%016d", i);
+ std::snprintf(buf, sizeof(buf), "%016d", i);
storage->assign(buf, strlen(buf));
return Slice(*storage);
}
@@ -189,7 +190,7 @@ class CorruptionTest {
Cache* tiny_cache_;
};
-TEST(CorruptionTest, Recovery) {
+TEST_F(CorruptionTest, Recovery) {
Build(100);
Check(100, 100);
Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record
@@ -200,13 +201,13 @@ TEST(CorruptionTest, Recovery) {
Check(36, 36);
}
-TEST(CorruptionTest, RecoverWriteError) {
+TEST_F(CorruptionTest, RecoverWriteError) {
env_.writable_file_error_ = true;
Status s = TryReopen();
ASSERT_TRUE(!s.ok());
}
-TEST(CorruptionTest, NewFileErrorDuringWrite) {
+TEST_F(CorruptionTest, NewFileErrorDuringWrite) {
// Do enough writing to force minor compaction
env_.writable_file_error_ = true;
const int num = 3 + (Options().write_buffer_size / kValueSize);
@@ -223,7 +224,7 @@ TEST(CorruptionTest, NewFileErrorDuringWrite) {
Reopen();
}
-TEST(CorruptionTest, TableFile) {
+TEST_F(CorruptionTest, TableFile) {
Build(100);
DBImpl* dbi = reinterpret_cast(db_);
dbi->TEST_CompactMemTable();
@@ -234,7 +235,7 @@ TEST(CorruptionTest, TableFile) {
Check(90, 99);
}
-TEST(CorruptionTest, TableFileRepair) {
+TEST_F(CorruptionTest, TableFileRepair) {
options_.block_size = 2 * kValueSize; // Limit scope of corruption
options_.paranoid_checks = true;
Reopen();
@@ -250,7 +251,7 @@ TEST(CorruptionTest, TableFileRepair) {
Check(95, 99);
}
-TEST(CorruptionTest, TableFileIndexData) {
+TEST_F(CorruptionTest, TableFileIndexData) {
Build(10000); // Enough to build multiple Tables
DBImpl* dbi = reinterpret_cast(db_);
dbi->TEST_CompactMemTable();
@@ -260,36 +261,36 @@ TEST(CorruptionTest, TableFileIndexData) {
Check(5000, 9999);
}
-TEST(CorruptionTest, MissingDescriptor) {
+TEST_F(CorruptionTest, MissingDescriptor) {
Build(1000);
RepairDB();
Reopen();
Check(1000, 1000);
}
-TEST(CorruptionTest, SequenceNumberRecovery) {
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v3"));
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v4"));
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v5"));
+TEST_F(CorruptionTest, SequenceNumberRecovery) {
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v1"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v2"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v3"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v4"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v5"));
RepairDB();
Reopen();
std::string v;
- ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("v5", v);
// Write something. If sequence number was not recovered properly,
// it will be hidden by an earlier write.
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v6"));
- ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v6"));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("v6", v);
Reopen();
- ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("v6", v);
}
-TEST(CorruptionTest, CorruptedDescriptor) {
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello"));
+TEST_F(CorruptionTest, CorruptedDescriptor) {
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "hello"));
DBImpl* dbi = reinterpret_cast(db_);
dbi->TEST_CompactMemTable();
dbi->TEST_CompactRange(0, nullptr, nullptr);
@@ -301,11 +302,11 @@ TEST(CorruptionTest, CorruptedDescriptor) {
RepairDB();
Reopen();
std::string v;
- ASSERT_OK(db_->Get(ReadOptions(), "foo", &v));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("hello", v);
}
-TEST(CorruptionTest, CompactionInputError) {
+TEST_F(CorruptionTest, CompactionInputError) {
Build(10);
DBImpl* dbi = reinterpret_cast(db_);
dbi->TEST_CompactMemTable();
@@ -320,7 +321,7 @@ TEST(CorruptionTest, CompactionInputError) {
Check(10000, 10000);
}
-TEST(CorruptionTest, CompactionInputErrorParanoid) {
+TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
options_.paranoid_checks = true;
options_.write_buffer_size = 512 << 10;
Reopen();
@@ -341,22 +342,21 @@ TEST(CorruptionTest, CompactionInputErrorParanoid) {
ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";
}
-TEST(CorruptionTest, UnrelatedKeys) {
+TEST_F(CorruptionTest, UnrelatedKeys) {
Build(10);
DBImpl* dbi = reinterpret_cast(db_);
dbi->TEST_CompactMemTable();
Corrupt(kTableFile, 100, 1);
std::string tmp1, tmp2;
- ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
+ ASSERT_LEVELDB_OK(
+ db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
std::string v;
- ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
dbi->TEST_CompactMemTable();
- ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
+ ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
}
} // namespace leveldb
-
-int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
diff --git a/db/db_impl.cc b/db/db_impl.cc
index 4754ba3..1a4e459 100644
--- a/db/db_impl.cc
+++ b/db/db_impl.cc
@@ -4,11 +4,10 @@
#include "db/db_impl.h"
-#include
-#include
-
#include
#include
+#include
+#include
#include
#include
#include
@@ -198,6 +197,9 @@ Status DBImpl::NewDB() {
new_db.EncodeTo(&record);
s = log.AddRecord(record);
if (s.ok()) {
+ s = file->Sync();
+ }
+ if (s.ok()) {
s = file->Close();
}
}
@@ -206,7 +208,7 @@ Status DBImpl::NewDB() {
// Make "CURRENT" file that points to the new manifest file.
s = SetCurrentFile(env_, dbname_, 1);
} else {
- env_->DeleteFile(manifest);
+ env_->RemoveFile(manifest);
}
return s;
}
@@ -220,7 +222,7 @@ void DBImpl::MaybeIgnoreError(Status* s) const {
}
}
-void DBImpl::DeleteObsoleteFiles() {
+void DBImpl::RemoveObsoleteFiles() {
mutex_.AssertHeld();
if (!bg_error_.ok()) {
@@ -282,7 +284,7 @@ void DBImpl::DeleteObsoleteFiles() {
// are therefore safe to delete while allowing other threads to proceed.
mutex_.Unlock();
for (const std::string& filename : files_to_delete) {
- env_->DeleteFile(dbname_ + "/" + filename);
+ env_->RemoveFile(dbname_ + "/" + filename);
}
mutex_.Lock();
}
@@ -302,6 +304,8 @@ Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
if (!env_->FileExists(CurrentFileName(dbname_))) {
if (options_.create_if_missing) {
+ Log(options_.info_log, "Creating DB %s since it was missing.",
+ dbname_.c_str());
s = NewDB();
if (!s.ok()) {
return s;
@@ -351,8 +355,8 @@ Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
}
if (!expected.empty()) {
char buf[50];
- snprintf(buf, sizeof(buf), "%d missing files; e.g.",
- static_cast(expected.size()));
+ std::snprintf(buf, sizeof(buf), "%d missing files; e.g.",
+ static_cast(expected.size()));
return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));
}
@@ -569,7 +573,7 @@ void DBImpl::CompactMemTable() {
imm_->Unref();
imm_ = nullptr;
has_imm_.store(false, std::memory_order_release);
- DeleteObsoleteFiles();
+ RemoveObsoleteFiles();
} else {
RecordBackgroundError(s);
}
@@ -729,7 +733,7 @@ void DBImpl::BackgroundCompaction() {
// Move file to next level
assert(c->num_input_files(0) == 1);
FileMetaData* f = c->input(0, 0);
- c->edit()->DeleteFile(c->level(), f->number);
+ c->edit()->RemoveFile(c->level(), f->number);
c->edit()->AddFile(c->level() + 1, f->number, f->file_size, f->smallest,
f->largest);
status = versions_->LogAndApply(c->edit(), &mutex_);
@@ -749,7 +753,7 @@ void DBImpl::BackgroundCompaction() {
}
CleanupCompaction(compact);
c->ReleaseInputs();
- DeleteObsoleteFiles();
+ RemoveObsoleteFiles();
}
delete c;
@@ -1213,9 +1217,9 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
uint64_t last_sequence = versions_->LastSequence();
Writer* last_writer = &w;
if (status.ok() && updates != nullptr) { // nullptr batch is for compactions
- WriteBatch* updates = BuildBatchGroup(&last_writer);
- WriteBatchInternal::SetSequence(updates, last_sequence + 1);
- last_sequence += WriteBatchInternal::Count(updates);
+ WriteBatch* write_batch = BuildBatchGroup(&last_writer);
+ WriteBatchInternal::SetSequence(write_batch, last_sequence + 1);
+ last_sequence += WriteBatchInternal::Count(write_batch);
// Add to log and apply to memtable. We can release the lock
// during this phase since &w is currently responsible for logging
@@ -1223,7 +1227,7 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
// into mem_.
{
mutex_.Unlock();
- status = log_->AddRecord(WriteBatchInternal::Contents(updates));
+ status = log_->AddRecord(WriteBatchInternal::Contents(write_batch));
bool sync_error = false;
if (status.ok() && options.sync) {
status = logfile_->Sync();
@@ -1232,7 +1236,7 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
}
}
if (status.ok()) {
- status = WriteBatchInternal::InsertInto(updates, mem_);
+ status = WriteBatchInternal::InsertInto(write_batch, mem_);
}
mutex_.Lock();
if (sync_error) {
@@ -1242,7 +1246,7 @@ Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
RecordBackgroundError(status);
}
}
- if (updates == tmp_batch_) tmp_batch_->Clear();
+ if (write_batch == tmp_batch_) tmp_batch_->Clear();
versions_->SetLastSequence(last_sequence);
}
@@ -1397,26 +1401,26 @@ bool DBImpl::GetProperty(const Slice& property, std::string* value) {
return false;
} else {
char buf[100];
- snprintf(buf, sizeof(buf), "%d",
- versions_->NumLevelFiles(static_cast(level)));
+ std::snprintf(buf, sizeof(buf), "%d",
+ versions_->NumLevelFiles(static_cast(level)));
*value = buf;
return true;
}
} else if (in == "stats") {
char buf[200];
- snprintf(buf, sizeof(buf),
- " Compactions\n"
- "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n"
- "--------------------------------------------------\n");
+ std::snprintf(buf, sizeof(buf),
+ " Compactions\n"
+ "Level Files Size(MB) Time(sec) Read(MB) Write(MB)\n"
+ "--------------------------------------------------\n");
value->append(buf);
for (int level = 0; level < config::kNumLevels; level++) {
int files = versions_->NumLevelFiles(level);
if (stats_[level].micros > 0 || files > 0) {
- snprintf(buf, sizeof(buf), "%3d %8d %8.0f %9.0f %8.0f %9.0f\n", level,
- files, versions_->NumLevelBytes(level) / 1048576.0,
- stats_[level].micros / 1e6,
- stats_[level].bytes_read / 1048576.0,
- stats_[level].bytes_written / 1048576.0);
+ std::snprintf(buf, sizeof(buf), "%3d %8d %8.0f %9.0f %8.0f %9.0f\n",
+ level, files, versions_->NumLevelBytes(level) / 1048576.0,
+ stats_[level].micros / 1e6,
+ stats_[level].bytes_read / 1048576.0,
+ stats_[level].bytes_written / 1048576.0);
value->append(buf);
}
}
@@ -1433,8 +1437,8 @@ bool DBImpl::GetProperty(const Slice& property, std::string* value) {
total_usage += imm_->ApproximateMemoryUsage();
}
char buf[50];
- snprintf(buf, sizeof(buf), "%llu",
- static_cast(total_usage));
+ std::snprintf(buf, sizeof(buf), "%llu",
+ static_cast(total_usage));
value->append(buf);
return true;
}
@@ -1506,7 +1510,7 @@ Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {
s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
}
if (s.ok()) {
- impl->DeleteObsoleteFiles();
+ impl->RemoveObsoleteFiles();
impl->MaybeScheduleCompaction();
}
impl->mutex_.Unlock();
@@ -1539,15 +1543,15 @@ Status DestroyDB(const std::string& dbname, const Options& options) {
for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type) &&
type != kDBLockFile) { // Lock file will be deleted at end
- Status del = env->DeleteFile(dbname + "/" + filenames[i]);
+ Status del = env->RemoveFile(dbname + "/" + filenames[i]);
if (result.ok() && !del.ok()) {
result = del;
}
}
}
env->UnlockFile(lock); // Ignore error since state is already gone
- env->DeleteFile(lockname);
- env->DeleteDir(dbname); // Ignore error in case dir contains other files
+ env->RemoveFile(lockname);
+ env->RemoveDir(dbname); // Ignore error in case dir contains other files
}
return result;
}
diff --git a/db/db_impl.h b/db/db_impl.h
index 685735c..c7b0172 100644
--- a/db/db_impl.h
+++ b/db/db_impl.h
@@ -116,7 +116,7 @@ class DBImpl : public DB {
void MaybeIgnoreError(Status* s) const;
// Delete any unneeded files and stale in-memory entries.
- void DeleteObsoleteFiles() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+ void RemoveObsoleteFiles() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Compact the in-memory write buffer to disk. Switches to a new
// log-file/memtable and writes a new descriptor iff successful.
diff --git a/db/db_iter.cc b/db/db_iter.cc
index 98715a9..532c2db 100644
--- a/db/db_iter.cc
+++ b/db/db_iter.cc
@@ -21,9 +21,9 @@ static void DumpInternalIter(Iterator* iter) {
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
ParsedInternalKey k;
if (!ParseInternalKey(iter->key(), &k)) {
- fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str());
+ std::fprintf(stderr, "Corrupt '%s'\n", EscapeString(iter->key()).c_str());
} else {
- fprintf(stderr, "@ '%s'\n", k.DebugString().c_str());
+ std::fprintf(stderr, "@ '%s'\n", k.DebugString().c_str());
}
}
}
diff --git a/db/db_iter.h b/db/db_iter.h
index fd93e91..5977fc8 100644
--- a/db/db_iter.h
+++ b/db/db_iter.h
@@ -5,7 +5,7 @@
#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_
#define STORAGE_LEVELDB_DB_DB_ITER_H_
-#include
+#include
#include "db/dbformat.h"
#include "leveldb/db.h"
diff --git a/db/db_test.cc b/db/db_test.cc
index 9a8faf1..9bd6e14 100644
--- a/db/db_test.cc
+++ b/db/db_test.cc
@@ -5,8 +5,10 @@
#include "leveldb/db.h"
#include
+#include
#include
+#include "gtest/gtest.h"
#include "db/db_impl.h"
#include "db/filename.h"
#include "db/version_set.h"
@@ -20,7 +22,6 @@
#include "util/hash.h"
#include "util/logging.h"
#include "util/mutexlock.h"
-#include "util/testharness.h"
#include "util/testutil.h"
namespace leveldb {
@@ -226,7 +227,7 @@ class SpecialEnv : public EnvWrapper {
}
};
-class DBTest {
+class DBTest : public testing::Test {
public:
std::string dbname_;
SpecialEnv* env_;
@@ -236,7 +237,7 @@ class DBTest {
DBTest() : env_(new SpecialEnv(Env::Default())), option_config_(kDefault) {
filter_policy_ = NewBloomFilterPolicy(10);
- dbname_ = test::TmpDir() + "/db_test";
+ dbname_ = testing::TempDir() + "db_test";
DestroyDB(dbname_, Options());
db_ = nullptr;
Reopen();
@@ -283,7 +284,9 @@ class DBTest {
DBImpl* dbfull() { return reinterpret_cast(db_); }
- void Reopen(Options* options = nullptr) { ASSERT_OK(TryReopen(options)); }
+ void Reopen(Options* options = nullptr) {
+ ASSERT_LEVELDB_OK(TryReopen(options));
+ }
void Close() {
delete db_;
@@ -294,7 +297,7 @@ class DBTest {
delete db_;
db_ = nullptr;
DestroyDB(dbname_, Options());
- ASSERT_OK(TryReopen(options));
+ ASSERT_LEVELDB_OK(TryReopen(options));
}
Status TryReopen(Options* options) {
@@ -348,11 +351,11 @@ class DBTest {
// Check reverse iteration results are the reverse of forward results
size_t matched = 0;
for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
- ASSERT_LT(matched, forward.size());
- ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);
+ EXPECT_LT(matched, forward.size());
+ EXPECT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);
matched++;
}
- ASSERT_EQ(matched, forward.size());
+ EXPECT_EQ(matched, forward.size());
delete iter;
return result;
@@ -402,7 +405,7 @@ class DBTest {
int NumTableFilesAtLevel(int level) {
std::string property;
- ASSERT_TRUE(db_->GetProperty(
+ EXPECT_TRUE(db_->GetProperty(
"leveldb.num-files-at-level" + NumberToString(level), &property));
return std::stoi(property);
}
@@ -422,7 +425,7 @@ class DBTest {
for (int level = 0; level < config::kNumLevels; level++) {
int f = NumTableFilesAtLevel(level);
char buf[100];
- snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
+ std::snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
result += buf;
if (f > 0) {
last_non_zero_offset = result.size();
@@ -467,14 +470,14 @@ class DBTest {
}
void DumpFileCounts(const char* label) {
- fprintf(stderr, "---\n%s:\n", label);
- fprintf(
+ std::fprintf(stderr, "---\n%s:\n", label);
+ std::fprintf(
stderr, "maxoverlap: %lld\n",
static_cast(dbfull()->TEST_MaxNextLevelOverlappingBytes()));
for (int level = 0; level < config::kNumLevels; level++) {
int num = NumTableFilesAtLevel(level);
if (num > 0) {
- fprintf(stderr, " level %3d : %d files\n", level, num);
+ std::fprintf(stderr, " level %3d : %d files\n", level, num);
}
}
}
@@ -497,12 +500,12 @@ class DBTest {
bool DeleteAnSSTFile() {
std::vector filenames;
- ASSERT_OK(env_->GetChildren(dbname_, &filenames));
+ EXPECT_LEVELDB_OK(env_->GetChildren(dbname_, &filenames));
uint64_t number;
FileType type;
for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {
- ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number)));
+ EXPECT_LEVELDB_OK(env_->RemoveFile(TableFileName(dbname_, number)));
return true;
}
}
@@ -512,7 +515,7 @@ class DBTest {
// Returns number of files renamed.
int RenameLDBToSST() {
std::vector filenames;
- ASSERT_OK(env_->GetChildren(dbname_, &filenames));
+ EXPECT_LEVELDB_OK(env_->GetChildren(dbname_, &filenames));
uint64_t number;
FileType type;
int files_renamed = 0;
@@ -520,7 +523,7 @@ class DBTest {
if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {
const std::string from = TableFileName(dbname_, number);
const std::string to = SSTTableFileName(dbname_, number);
- ASSERT_OK(env_->RenameFile(from, to));
+ EXPECT_LEVELDB_OK(env_->RenameFile(from, to));
files_renamed++;
}
}
@@ -535,63 +538,63 @@ class DBTest {
int option_config_;
};
-TEST(DBTest, Empty) {
+TEST_F(DBTest, Empty) {
do {
ASSERT_TRUE(db_ != nullptr);
ASSERT_EQ("NOT_FOUND", Get("foo"));
} while (ChangeOptions());
}
-TEST(DBTest, EmptyKey) {
+TEST_F(DBTest, EmptyKey) {
do {
- ASSERT_OK(Put("", "v1"));
+ ASSERT_LEVELDB_OK(Put("", "v1"));
ASSERT_EQ("v1", Get(""));
- ASSERT_OK(Put("", "v2"));
+ ASSERT_LEVELDB_OK(Put("", "v2"));
ASSERT_EQ("v2", Get(""));
} while (ChangeOptions());
}
-TEST(DBTest, EmptyValue) {
+TEST_F(DBTest, EmptyValue) {
do {
- ASSERT_OK(Put("key", "v1"));
+ ASSERT_LEVELDB_OK(Put("key", "v1"));
ASSERT_EQ("v1", Get("key"));
- ASSERT_OK(Put("key", ""));
+ ASSERT_LEVELDB_OK(Put("key", ""));
ASSERT_EQ("", Get("key"));
- ASSERT_OK(Put("key", "v2"));
+ ASSERT_LEVELDB_OK(Put("key", "v2"));
ASSERT_EQ("v2", Get("key"));
} while (ChangeOptions());
}
-TEST(DBTest, ReadWrite) {
+TEST_F(DBTest, ReadWrite) {
do {
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
ASSERT_EQ("v1", Get("foo"));
- ASSERT_OK(Put("bar", "v2"));
- ASSERT_OK(Put("foo", "v3"));
+ ASSERT_LEVELDB_OK(Put("bar", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v3"));
ASSERT_EQ("v3", Get("foo"));
ASSERT_EQ("v2", Get("bar"));
} while (ChangeOptions());
}
-TEST(DBTest, PutDeleteGet) {
+TEST_F(DBTest, PutDeleteGet) {
do {
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v1"));
ASSERT_EQ("v1", Get("foo"));
- ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v2"));
ASSERT_EQ("v2", Get("foo"));
- ASSERT_OK(db_->Delete(WriteOptions(), "foo"));
+ ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), "foo"));
ASSERT_EQ("NOT_FOUND", Get("foo"));
} while (ChangeOptions());
}
-TEST(DBTest, GetFromImmutableLayer) {
+TEST_F(DBTest, GetFromImmutableLayer) {
do {
Options options = CurrentOptions();
options.env = env_;
options.write_buffer_size = 100000; // Small write buffer
Reopen(&options);
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
ASSERT_EQ("v1", Get("foo"));
// Block sync calls.
@@ -604,17 +607,17 @@ TEST(DBTest, GetFromImmutableLayer) {
} while (ChangeOptions());
}
-TEST(DBTest, GetFromVersions) {
+TEST_F(DBTest, GetFromVersions) {
do {
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("v1", Get("foo"));
} while (ChangeOptions());
}
-TEST(DBTest, GetMemUsage) {
+TEST_F(DBTest, GetMemUsage) {
do {
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
std::string val;
ASSERT_TRUE(db_->GetProperty("leveldb.approximate-memory-usage", &val));
int mem_usage = std::stoi(val);
@@ -623,14 +626,14 @@ TEST(DBTest, GetMemUsage) {
} while (ChangeOptions());
}
-TEST(DBTest, GetSnapshot) {
+TEST_F(DBTest, GetSnapshot) {
do {
// Try with both a short key and a long key
for (int i = 0; i < 2; i++) {
std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
- ASSERT_OK(Put(key, "v1"));
+ ASSERT_LEVELDB_OK(Put(key, "v1"));
const Snapshot* s1 = db_->GetSnapshot();
- ASSERT_OK(Put(key, "v2"));
+ ASSERT_LEVELDB_OK(Put(key, "v2"));
ASSERT_EQ("v2", Get(key));
ASSERT_EQ("v1", Get(key, s1));
dbfull()->TEST_CompactMemTable();
@@ -641,16 +644,16 @@ TEST(DBTest, GetSnapshot) {
} while (ChangeOptions());
}
-TEST(DBTest, GetIdenticalSnapshots) {
+TEST_F(DBTest, GetIdenticalSnapshots) {
do {
// Try with both a short key and a long key
for (int i = 0; i < 2; i++) {
std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
- ASSERT_OK(Put(key, "v1"));
+ ASSERT_LEVELDB_OK(Put(key, "v1"));
const Snapshot* s1 = db_->GetSnapshot();
const Snapshot* s2 = db_->GetSnapshot();
const Snapshot* s3 = db_->GetSnapshot();
- ASSERT_OK(Put(key, "v2"));
+ ASSERT_LEVELDB_OK(Put(key, "v2"));
ASSERT_EQ("v2", Get(key));
ASSERT_EQ("v1", Get(key, s1));
ASSERT_EQ("v1", Get(key, s2));
@@ -666,13 +669,13 @@ TEST(DBTest, GetIdenticalSnapshots) {
} while (ChangeOptions());
}
-TEST(DBTest, IterateOverEmptySnapshot) {
+TEST_F(DBTest, IterateOverEmptySnapshot) {
do {
const Snapshot* snapshot = db_->GetSnapshot();
ReadOptions read_options;
read_options.snapshot = snapshot;
- ASSERT_OK(Put("foo", "v1"));
- ASSERT_OK(Put("foo", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
Iterator* iterator1 = db_->NewIterator(read_options);
iterator1->SeekToFirst();
@@ -690,41 +693,41 @@ TEST(DBTest, IterateOverEmptySnapshot) {
} while (ChangeOptions());
}
-TEST(DBTest, GetLevel0Ordering) {
+TEST_F(DBTest, GetLevel0Ordering) {
do {
// Check that we process level-0 files in correct order. The code
// below generates two level-0 files where the earlier one comes
// before the later one in the level-0 file list since the earlier
// one has a smaller "smallest" key.
- ASSERT_OK(Put("bar", "b"));
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("bar", "b"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
dbfull()->TEST_CompactMemTable();
- ASSERT_OK(Put("foo", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("v2", Get("foo"));
} while (ChangeOptions());
}
-TEST(DBTest, GetOrderedByLevels) {
+TEST_F(DBTest, GetOrderedByLevels) {
do {
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
Compact("a", "z");
ASSERT_EQ("v1", Get("foo"));
- ASSERT_OK(Put("foo", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
ASSERT_EQ("v2", Get("foo"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("v2", Get("foo"));
} while (ChangeOptions());
}
-TEST(DBTest, GetPicksCorrectFile) {
+TEST_F(DBTest, GetPicksCorrectFile) {
do {
// Arrange to have multiple files in a non-level-0 level.
- ASSERT_OK(Put("a", "va"));
+ ASSERT_LEVELDB_OK(Put("a", "va"));
Compact("a", "b");
- ASSERT_OK(Put("x", "vx"));
+ ASSERT_LEVELDB_OK(Put("x", "vx"));
Compact("x", "y");
- ASSERT_OK(Put("f", "vf"));
+ ASSERT_LEVELDB_OK(Put("f", "vf"));
Compact("f", "g");
ASSERT_EQ("va", Get("a"));
ASSERT_EQ("vf", Get("f"));
@@ -732,7 +735,7 @@ TEST(DBTest, GetPicksCorrectFile) {
} while (ChangeOptions());
}
-TEST(DBTest, GetEncountersEmptyLevel) {
+TEST_F(DBTest, GetEncountersEmptyLevel) {
do {
// Arrange for the following to happen:
// * sstable A in level 0
@@ -770,7 +773,7 @@ TEST(DBTest, GetEncountersEmptyLevel) {
} while (ChangeOptions());
}
-TEST(DBTest, IterEmpty) {
+TEST_F(DBTest, IterEmpty) {
Iterator* iter = db_->NewIterator(ReadOptions());
iter->SeekToFirst();
@@ -785,8 +788,8 @@ TEST(DBTest, IterEmpty) {
delete iter;
}
-TEST(DBTest, IterSingle) {
- ASSERT_OK(Put("a", "va"));
+TEST_F(DBTest, IterSingle) {
+ ASSERT_LEVELDB_OK(Put("a", "va"));
Iterator* iter = db_->NewIterator(ReadOptions());
iter->SeekToFirst();
@@ -823,10 +826,10 @@ TEST(DBTest, IterSingle) {
delete iter;
}
-TEST(DBTest, IterMulti) {
- ASSERT_OK(Put("a", "va"));
- ASSERT_OK(Put("b", "vb"));
- ASSERT_OK(Put("c", "vc"));
+TEST_F(DBTest, IterMulti) {
+ ASSERT_LEVELDB_OK(Put("a", "va"));
+ ASSERT_LEVELDB_OK(Put("b", "vb"));
+ ASSERT_LEVELDB_OK(Put("c", "vc"));
Iterator* iter = db_->NewIterator(ReadOptions());
iter->SeekToFirst();
@@ -881,11 +884,11 @@ TEST(DBTest, IterMulti) {
ASSERT_EQ(IterStatus(iter), "b->vb");
// Make sure iter stays at snapshot
- ASSERT_OK(Put("a", "va2"));
- ASSERT_OK(Put("a2", "va3"));
- ASSERT_OK(Put("b", "vb2"));
- ASSERT_OK(Put("c", "vc2"));
- ASSERT_OK(Delete("b"));
+ ASSERT_LEVELDB_OK(Put("a", "va2"));
+ ASSERT_LEVELDB_OK(Put("a2", "va3"));
+ ASSERT_LEVELDB_OK(Put("b", "vb2"));
+ ASSERT_LEVELDB_OK(Put("c", "vc2"));
+ ASSERT_LEVELDB_OK(Delete("b"));
iter->SeekToFirst();
ASSERT_EQ(IterStatus(iter), "a->va");
iter->Next();
@@ -906,12 +909,12 @@ TEST(DBTest, IterMulti) {
delete iter;
}
-TEST(DBTest, IterSmallAndLargeMix) {
- ASSERT_OK(Put("a", "va"));
- ASSERT_OK(Put("b", std::string(100000, 'b')));
- ASSERT_OK(Put("c", "vc"));
- ASSERT_OK(Put("d", std::string(100000, 'd')));
- ASSERT_OK(Put("e", std::string(100000, 'e')));
+TEST_F(DBTest, IterSmallAndLargeMix) {
+ ASSERT_LEVELDB_OK(Put("a", "va"));
+ ASSERT_LEVELDB_OK(Put("b", std::string(100000, 'b')));
+ ASSERT_LEVELDB_OK(Put("c", "vc"));
+ ASSERT_LEVELDB_OK(Put("d", std::string(100000, 'd')));
+ ASSERT_LEVELDB_OK(Put("e", std::string(100000, 'e')));
Iterator* iter = db_->NewIterator(ReadOptions());
@@ -944,12 +947,30 @@ TEST(DBTest, IterSmallAndLargeMix) {
delete iter;
}
-TEST(DBTest, IterMultiWithDelete) {
+TEST_F(DBTest, IterMultiWithDelete) {
+ do {
+ ASSERT_LEVELDB_OK(Put("a", "va"));
+ ASSERT_LEVELDB_OK(Put("b", "vb"));
+ ASSERT_LEVELDB_OK(Put("c", "vc"));
+ ASSERT_LEVELDB_OK(Delete("b"));
+ ASSERT_EQ("NOT_FOUND", Get("b"));
+
+ Iterator* iter = db_->NewIterator(ReadOptions());
+ iter->Seek("c");
+ ASSERT_EQ(IterStatus(iter), "c->vc");
+ iter->Prev();
+ ASSERT_EQ(IterStatus(iter), "a->va");
+ delete iter;
+ } while (ChangeOptions());
+}
+
+TEST_F(DBTest, IterMultiWithDeleteAndCompaction) {
do {
- ASSERT_OK(Put("a", "va"));
- ASSERT_OK(Put("b", "vb"));
- ASSERT_OK(Put("c", "vc"));
- ASSERT_OK(Delete("b"));
+ ASSERT_LEVELDB_OK(Put("b", "vb"));
+ ASSERT_LEVELDB_OK(Put("c", "vc"));
+ ASSERT_LEVELDB_OK(Put("a", "va"));
+ dbfull()->TEST_CompactMemTable();
+ ASSERT_LEVELDB_OK(Delete("b"));
ASSERT_EQ("NOT_FOUND", Get("b"));
Iterator* iter = db_->NewIterator(ReadOptions());
@@ -957,39 +978,41 @@ TEST(DBTest, IterMultiWithDelete) {
ASSERT_EQ(IterStatus(iter), "c->vc");
iter->Prev();
ASSERT_EQ(IterStatus(iter), "a->va");
+ iter->Seek("b");
+ ASSERT_EQ(IterStatus(iter), "c->vc");
delete iter;
} while (ChangeOptions());
}
-TEST(DBTest, Recover) {
+TEST_F(DBTest, Recover) {
do {
- ASSERT_OK(Put("foo", "v1"));
- ASSERT_OK(Put("baz", "v5"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("baz", "v5"));
Reopen();
ASSERT_EQ("v1", Get("foo"));
ASSERT_EQ("v1", Get("foo"));
ASSERT_EQ("v5", Get("baz"));
- ASSERT_OK(Put("bar", "v2"));
- ASSERT_OK(Put("foo", "v3"));
+ ASSERT_LEVELDB_OK(Put("bar", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v3"));
Reopen();
ASSERT_EQ("v3", Get("foo"));
- ASSERT_OK(Put("foo", "v4"));
+ ASSERT_LEVELDB_OK(Put("foo", "v4"));
ASSERT_EQ("v4", Get("foo"));
ASSERT_EQ("v2", Get("bar"));
ASSERT_EQ("v5", Get("baz"));
} while (ChangeOptions());
}
-TEST(DBTest, RecoveryWithEmptyLog) {
+TEST_F(DBTest, RecoveryWithEmptyLog) {
do {
- ASSERT_OK(Put("foo", "v1"));
- ASSERT_OK(Put("foo", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
Reopen();
Reopen();
- ASSERT_OK(Put("foo", "v3"));
+ ASSERT_LEVELDB_OK(Put("foo", "v3"));
Reopen();
ASSERT_EQ("v3", Get("foo"));
} while (ChangeOptions());
@@ -997,7 +1020,7 @@ TEST(DBTest, RecoveryWithEmptyLog) {
// Check that writes done during a memtable compaction are recovered
// if the database is shutdown during the memtable compaction.
-TEST(DBTest, RecoverDuringMemtableCompaction) {
+TEST_F(DBTest, RecoverDuringMemtableCompaction) {
do {
Options options = CurrentOptions();
options.env = env_;
@@ -1005,10 +1028,12 @@ TEST(DBTest, RecoverDuringMemtableCompaction) {
Reopen(&options);
// Trigger a long memtable compaction and reopen the database during it
- ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file
- ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable
- ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction
- ASSERT_OK(Put("bar", "v2")); // Goes to new log file
+ ASSERT_LEVELDB_OK(Put("foo", "v1")); // Goes to 1st log file
+ ASSERT_LEVELDB_OK(
+ Put("big1", std::string(10000000, 'x'))); // Fills memtable
+ ASSERT_LEVELDB_OK(
+ Put("big2", std::string(1000, 'y'))); // Triggers compaction
+ ASSERT_LEVELDB_OK(Put("bar", "v2")); // Goes to new log file
Reopen(&options);
ASSERT_EQ("v1", Get("foo"));
@@ -1020,11 +1045,11 @@ TEST(DBTest, RecoverDuringMemtableCompaction) {
static std::string Key(int i) {
char buf[100];
- snprintf(buf, sizeof(buf), "key%06d", i);
+ std::snprintf(buf, sizeof(buf), "key%06d", i);
return std::string(buf);
}
-TEST(DBTest, MinorCompactionsHappen) {
+TEST_F(DBTest, MinorCompactionsHappen) {
Options options = CurrentOptions();
options.write_buffer_size = 10000;
Reopen(&options);
@@ -1033,7 +1058,7 @@ TEST(DBTest, MinorCompactionsHappen) {
int starting_num_tables = TotalTableFiles();
for (int i = 0; i < N; i++) {
- ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
+ ASSERT_LEVELDB_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
}
int ending_num_tables = TotalTableFiles();
ASSERT_GT(ending_num_tables, starting_num_tables);
@@ -1049,14 +1074,14 @@ TEST(DBTest, MinorCompactionsHappen) {
}
}
-TEST(DBTest, RecoverWithLargeLog) {
+TEST_F(DBTest, RecoverWithLargeLog) {
{
Options options = CurrentOptions();
Reopen(&options);
- ASSERT_OK(Put("big1", std::string(200000, '1')));
- ASSERT_OK(Put("big2", std::string(200000, '2')));
- ASSERT_OK(Put("small3", std::string(10, '3')));
- ASSERT_OK(Put("small4", std::string(10, '4')));
+ ASSERT_LEVELDB_OK(Put("big1", std::string(200000, '1')));
+ ASSERT_LEVELDB_OK(Put("big2", std::string(200000, '2')));
+ ASSERT_LEVELDB_OK(Put("small3", std::string(10, '3')));
+ ASSERT_LEVELDB_OK(Put("small4", std::string(10, '4')));
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
}
@@ -1073,7 +1098,7 @@ TEST(DBTest, RecoverWithLargeLog) {
ASSERT_GT(NumTableFilesAtLevel(0), 1);
}
-TEST(DBTest, CompactionsGenerateMultipleFiles) {
+TEST_F(DBTest, CompactionsGenerateMultipleFiles) {
Options options = CurrentOptions();
options.write_buffer_size = 100000000; // Large write buffer
Reopen(&options);
@@ -1085,7 +1110,7 @@ TEST(DBTest, CompactionsGenerateMultipleFiles) {
std::vector values;
for (int i = 0; i < 80; i++) {
values.push_back(RandomString(&rnd, 100000));
- ASSERT_OK(Put(Key(i), values[i]));
+ ASSERT_LEVELDB_OK(Put(Key(i), values[i]));
}
// Reopening moves updates to level-0
@@ -1099,7 +1124,7 @@ TEST(DBTest, CompactionsGenerateMultipleFiles) {
}
}
-TEST(DBTest, RepeatedWritesToSameKey) {
+TEST_F(DBTest, RepeatedWritesToSameKey) {
Options options = CurrentOptions();
options.env = env_;
options.write_buffer_size = 100000; // Small write buffer
@@ -1114,11 +1139,11 @@ TEST(DBTest, RepeatedWritesToSameKey) {
for (int i = 0; i < 5 * kMaxFiles; i++) {
Put("key", value);
ASSERT_LE(TotalTableFiles(), kMaxFiles);
- fprintf(stderr, "after %d: %d files\n", i + 1, TotalTableFiles());
+ std::fprintf(stderr, "after %d: %d files\n", i + 1, TotalTableFiles());
}
}
-TEST(DBTest, SparseMerge) {
+TEST_F(DBTest, SparseMerge) {
Options options = CurrentOptions();
options.compression = kNoCompression;
Reopen(&options);
@@ -1136,7 +1161,7 @@ TEST(DBTest, SparseMerge) {
// Write approximately 100MB of "B" values
for (int i = 0; i < 100000; i++) {
char key[100];
- snprintf(key, sizeof(key), "B%010d", i);
+ std::snprintf(key, sizeof(key), "B%010d", i);
Put(key, value);
}
Put("C", "vc");
@@ -1161,14 +1186,14 @@ TEST(DBTest, SparseMerge) {
static bool Between(uint64_t val, uint64_t low, uint64_t high) {
bool result = (val >= low) && (val <= high);
if (!result) {
- fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
- (unsigned long long)(val), (unsigned long long)(low),
- (unsigned long long)(high));
+ std::fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
+ (unsigned long long)(val), (unsigned long long)(low),
+ (unsigned long long)(high));
}
return result;
}
-TEST(DBTest, ApproximateSizes) {
+TEST_F(DBTest, ApproximateSizes) {
do {
Options options = CurrentOptions();
options.write_buffer_size = 100000000; // Large write buffer
@@ -1186,7 +1211,7 @@ TEST(DBTest, ApproximateSizes) {
static const int S2 = 105000; // Allow some expansion from metadata
Random rnd(301);
for (int i = 0; i < N; i++) {
- ASSERT_OK(Put(Key(i), RandomString(&rnd, S1)));
+ ASSERT_LEVELDB_OK(Put(Key(i), RandomString(&rnd, S1)));
}
// 0 because GetApproximateSizes() does not account for memtable space
@@ -1227,7 +1252,7 @@ TEST(DBTest, ApproximateSizes) {
} while (ChangeOptions());
}
-TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
+TEST_F(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
do {
Options options = CurrentOptions();
options.compression = kNoCompression;
@@ -1235,18 +1260,18 @@ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
Random rnd(301);
std::string big1 = RandomString(&rnd, 100000);
- ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));
- ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));
- ASSERT_OK(Put(Key(2), big1));
- ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));
- ASSERT_OK(Put(Key(4), big1));
- ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));
- ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
- ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
+ ASSERT_LEVELDB_OK(Put(Key(0), RandomString(&rnd, 10000)));
+ ASSERT_LEVELDB_OK(Put(Key(1), RandomString(&rnd, 10000)));
+ ASSERT_LEVELDB_OK(Put(Key(2), big1));
+ ASSERT_LEVELDB_OK(Put(Key(3), RandomString(&rnd, 10000)));
+ ASSERT_LEVELDB_OK(Put(Key(4), big1));
+ ASSERT_LEVELDB_OK(Put(Key(5), RandomString(&rnd, 10000)));
+ ASSERT_LEVELDB_OK(Put(Key(6), RandomString(&rnd, 300000)));
+ ASSERT_LEVELDB_OK(Put(Key(7), RandomString(&rnd, 10000)));
if (options.reuse_logs) {
// Need to force a memtable compaction since recovery does not do so.
- ASSERT_OK(dbfull()->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable());
}
// Check sizes across recovery by reopening a few times
@@ -1270,7 +1295,7 @@ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
} while (ChangeOptions());
}
-TEST(DBTest, IteratorPinsRef) {
+TEST_F(DBTest, IteratorPinsRef) {
Put("foo", "hello");
// Get iterator that will yield the current contents of the DB.
@@ -1279,7 +1304,8 @@ TEST(DBTest, IteratorPinsRef) {
// Write to force compactions
Put("foo", "newvalue1");
for (int i = 0; i < 100; i++) {
- ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
+ ASSERT_LEVELDB_OK(
+ Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
}
Put("foo", "newvalue2");
@@ -1292,7 +1318,7 @@ TEST(DBTest, IteratorPinsRef) {
delete iter;
}
-TEST(DBTest, Snapshot) {
+TEST_F(DBTest, Snapshot) {
do {
Put("foo", "v1");
const Snapshot* s1 = db_->GetSnapshot();
@@ -1321,7 +1347,7 @@ TEST(DBTest, Snapshot) {
} while (ChangeOptions());
}
-TEST(DBTest, HiddenValuesAreRemoved) {
+TEST_F(DBTest, HiddenValuesAreRemoved) {
do {
Random rnd(301);
FillLevels("a", "z");
@@ -1333,7 +1359,7 @@ TEST(DBTest, HiddenValuesAreRemoved) {
Put("foo", "tiny");
Put("pastfoo2", "v2"); // Advance sequence number one more
- ASSERT_OK(dbfull()->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable());
ASSERT_GT(NumTableFilesAtLevel(0), 0);
ASSERT_EQ(big, Get("foo", snapshot));
@@ -1352,9 +1378,9 @@ TEST(DBTest, HiddenValuesAreRemoved) {
} while (ChangeOptions());
}
-TEST(DBTest, DeletionMarkers1) {
+TEST_F(DBTest, DeletionMarkers1) {
Put("foo", "v1");
- ASSERT_OK(dbfull()->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable());
const int last = config::kMaxMemCompactLevel;
ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
@@ -1368,7 +1394,7 @@ TEST(DBTest, DeletionMarkers1) {
Delete("foo");
Put("foo", "v2");
ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
- ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
Slice z("z");
dbfull()->TEST_CompactRange(last - 2, nullptr, &z);
@@ -1381,9 +1407,9 @@ TEST(DBTest, DeletionMarkers1) {
ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");
}
-TEST(DBTest, DeletionMarkers2) {
+TEST_F(DBTest, DeletionMarkers2) {
Put("foo", "v1");
- ASSERT_OK(dbfull()->TEST_CompactMemTable());
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable());
const int last = config::kMaxMemCompactLevel;
ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
@@ -1396,7 +1422,7 @@ TEST(DBTest, DeletionMarkers2) {
Delete("foo");
ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
- ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
+ ASSERT_LEVELDB_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
dbfull()->TEST_CompactRange(last - 2, nullptr, nullptr);
// DEL kept: "last" file overlaps
@@ -1407,17 +1433,17 @@ TEST(DBTest, DeletionMarkers2) {
ASSERT_EQ(AllEntriesFor("foo"), "[ ]");
}
-TEST(DBTest, OverlapInLevel0) {
+TEST_F(DBTest, OverlapInLevel0) {
do {
ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config";
// Fill levels 1 and 2 to disable the pushing of new memtables to levels >
// 0.
- ASSERT_OK(Put("100", "v100"));
- ASSERT_OK(Put("999", "v999"));
+ ASSERT_LEVELDB_OK(Put("100", "v100"));
+ ASSERT_LEVELDB_OK(Put("999", "v999"));
dbfull()->TEST_CompactMemTable();
- ASSERT_OK(Delete("100"));
- ASSERT_OK(Delete("999"));
+ ASSERT_LEVELDB_OK(Delete("100"));
+ ASSERT_LEVELDB_OK(Delete("999"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("0,1,1", FilesPerLevel());
@@ -1425,12 +1451,12 @@ TEST(DBTest, OverlapInLevel0) {
// files[0] 200 .. 900
// files[1] 300 .. 500
// Note that files are sorted by smallest key.
- ASSERT_OK(Put("300", "v300"));
- ASSERT_OK(Put("500", "v500"));
+ ASSERT_LEVELDB_OK(Put("300", "v300"));
+ ASSERT_LEVELDB_OK(Put("500", "v500"));
dbfull()->TEST_CompactMemTable();
- ASSERT_OK(Put("200", "v200"));
- ASSERT_OK(Put("600", "v600"));
- ASSERT_OK(Put("900", "v900"));
+ ASSERT_LEVELDB_OK(Put("200", "v200"));
+ ASSERT_LEVELDB_OK(Put("600", "v600"));
+ ASSERT_LEVELDB_OK(Put("900", "v900"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("2,1,1", FilesPerLevel());
@@ -1442,23 +1468,23 @@ TEST(DBTest, OverlapInLevel0) {
// Do a memtable compaction. Before bug-fix, the compaction would
// not detect the overlap with level-0 files and would incorrectly place
// the deletion in a deeper level.
- ASSERT_OK(Delete("600"));
+ ASSERT_LEVELDB_OK(Delete("600"));
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("3", FilesPerLevel());
ASSERT_EQ("NOT_FOUND", Get("600"));
} while (ChangeOptions());
}
-TEST(DBTest, L0_CompactionBug_Issue44_a) {
+TEST_F(DBTest, L0_CompactionBug_Issue44_a) {
Reopen();
- ASSERT_OK(Put("b", "v"));
+ ASSERT_LEVELDB_OK(Put("b", "v"));
Reopen();
- ASSERT_OK(Delete("b"));
- ASSERT_OK(Delete("a"));
+ ASSERT_LEVELDB_OK(Delete("b"));
+ ASSERT_LEVELDB_OK(Delete("a"));
Reopen();
- ASSERT_OK(Delete("a"));
+ ASSERT_LEVELDB_OK(Delete("a"));
Reopen();
- ASSERT_OK(Put("a", "v"));
+ ASSERT_LEVELDB_OK(Put("a", "v"));
Reopen();
Reopen();
ASSERT_EQ("(a->v)", Contents());
@@ -1466,7 +1492,7 @@ TEST(DBTest, L0_CompactionBug_Issue44_a) {
ASSERT_EQ("(a->v)", Contents());
}
-TEST(DBTest, L0_CompactionBug_Issue44_b) {
+TEST_F(DBTest, L0_CompactionBug_Issue44_b) {
Reopen();
Put("", "");
Reopen();
@@ -1492,16 +1518,16 @@ TEST(DBTest, L0_CompactionBug_Issue44_b) {
ASSERT_EQ("(->)(c->cv)", Contents());
}
-TEST(DBTest, Fflush_Issue474) {
+TEST_F(DBTest, Fflush_Issue474) {
static const int kNum = 100000;
Random rnd(test::RandomSeed());
for (int i = 0; i < kNum; i++) {
- fflush(nullptr);
- ASSERT_OK(Put(RandomKey(&rnd), RandomString(&rnd, 100)));
+ std::fflush(nullptr);
+ ASSERT_LEVELDB_OK(Put(RandomKey(&rnd), RandomString(&rnd, 100)));
}
}
-TEST(DBTest, ComparatorCheck) {
+TEST_F(DBTest, ComparatorCheck) {
class NewComparator : public Comparator {
public:
const char* Name() const override { return "leveldb.NewComparator"; }
@@ -1524,7 +1550,7 @@ TEST(DBTest, ComparatorCheck) {
<< s.ToString();
}
-TEST(DBTest, CustomComparator) {
+TEST_F(DBTest, CustomComparator) {
class NumberComparator : public Comparator {
public:
const char* Name() const override { return "test.NumberComparator"; }
@@ -1542,11 +1568,11 @@ TEST(DBTest, CustomComparator) {
private:
static int ToNumber(const Slice& x) {
// Check that there are no extra characters.
- ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size() - 1] == ']')
+ EXPECT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size() - 1] == ']')
<< EscapeString(x);
int val;
char ignored;
- ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1)
+ EXPECT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1)
<< EscapeString(x);
return val;
}
@@ -1558,8 +1584,8 @@ TEST(DBTest, CustomComparator) {
new_options.filter_policy = nullptr; // Cannot use bloom filters
new_options.write_buffer_size = 1000; // Compact more often
DestroyAndReopen(&new_options);
- ASSERT_OK(Put("[10]", "ten"));
- ASSERT_OK(Put("[0x14]", "twenty"));
+ ASSERT_LEVELDB_OK(Put("[10]", "ten"));
+ ASSERT_LEVELDB_OK(Put("[0x14]", "twenty"));
for (int i = 0; i < 2; i++) {
ASSERT_EQ("ten", Get("[10]"));
ASSERT_EQ("ten", Get("[0xa]"));
@@ -1573,14 +1599,14 @@ TEST(DBTest, CustomComparator) {
for (int run = 0; run < 2; run++) {
for (int i = 0; i < 1000; i++) {
char buf[100];
- snprintf(buf, sizeof(buf), "[%d]", i * 10);
- ASSERT_OK(Put(buf, buf));
+ std::snprintf(buf, sizeof(buf), "[%d]", i * 10);
+ ASSERT_LEVELDB_OK(Put(buf, buf));
}
Compact("[0]", "[1000000]");
}
}
-TEST(DBTest, ManualCompaction) {
+TEST_F(DBTest, ManualCompaction) {
ASSERT_EQ(config::kMaxMemCompactLevel, 2)
<< "Need to update this test to match kMaxMemCompactLevel";
@@ -1614,8 +1640,8 @@ TEST(DBTest, ManualCompaction) {
ASSERT_EQ("0,0,1", FilesPerLevel());
}
-TEST(DBTest, DBOpen_Options) {
- std::string dbname = test::TmpDir() + "/db_options_test";
+TEST_F(DBTest, DBOpen_Options) {
+ std::string dbname = testing::TempDir() + "db_options_test";
DestroyDB(dbname, Options());
// Does not exist, and create_if_missing == false: error
@@ -1629,7 +1655,7 @@ TEST(DBTest, DBOpen_Options) {
// Does not exist, and create_if_missing == true: OK
opts.create_if_missing = true;
s = DB::Open(opts, dbname, &db);
- ASSERT_OK(s);
+ ASSERT_LEVELDB_OK(s);
ASSERT_TRUE(db != nullptr);
delete db;
@@ -1646,50 +1672,50 @@ TEST(DBTest, DBOpen_Options) {
opts.create_if_missing = true;
opts.error_if_exists = false;
s = DB::Open(opts, dbname, &db);
- ASSERT_OK(s);
+ ASSERT_LEVELDB_OK(s);
ASSERT_TRUE(db != nullptr);
delete db;
db = nullptr;
}
-TEST(DBTest, DestroyEmptyDir) {
- std::string dbname = test::TmpDir() + "/db_empty_dir";
+TEST_F(DBTest, DestroyEmptyDir) {
+ std::string dbname = testing::TempDir() + "db_empty_dir";
TestEnv env(Env::Default());
- env.DeleteDir(dbname);
+ env.RemoveDir(dbname);
ASSERT_TRUE(!env.FileExists(dbname));
Options opts;
opts.env = &env;
- ASSERT_OK(env.CreateDir(dbname));
+ ASSERT_LEVELDB_OK(env.CreateDir(dbname));
ASSERT_TRUE(env.FileExists(dbname));
std::vector children;
- ASSERT_OK(env.GetChildren(dbname, &children));
+ ASSERT_LEVELDB_OK(env.GetChildren(dbname, &children));
// The stock Env's do not filter out '.' and '..' special files.
ASSERT_EQ(2, children.size());
- ASSERT_OK(DestroyDB(dbname, opts));
+ ASSERT_LEVELDB_OK(DestroyDB(dbname, opts));
ASSERT_TRUE(!env.FileExists(dbname));
// Should also be destroyed if Env is filtering out dot files.
env.SetIgnoreDotFiles(true);
- ASSERT_OK(env.CreateDir(dbname));
+ ASSERT_LEVELDB_OK(env.CreateDir(dbname));
ASSERT_TRUE(env.FileExists(dbname));
- ASSERT_OK(env.GetChildren(dbname, &children));
+ ASSERT_LEVELDB_OK(env.GetChildren(dbname, &children));
ASSERT_EQ(0, children.size());
- ASSERT_OK(DestroyDB(dbname, opts));
+ ASSERT_LEVELDB_OK(DestroyDB(dbname, opts));
ASSERT_TRUE(!env.FileExists(dbname));
}
-TEST(DBTest, DestroyOpenDB) {
- std::string dbname = test::TmpDir() + "/open_db_dir";
- env_->DeleteDir(dbname);
+TEST_F(DBTest, DestroyOpenDB) {
+ std::string dbname = testing::TempDir() + "open_db_dir";
+ env_->RemoveDir(dbname);
ASSERT_TRUE(!env_->FileExists(dbname));
Options opts;
opts.create_if_missing = true;
DB* db = nullptr;
- ASSERT_OK(DB::Open(opts, dbname, &db));
+ ASSERT_LEVELDB_OK(DB::Open(opts, dbname, &db));
ASSERT_TRUE(db != nullptr);
// Must fail to destroy an open db.
@@ -1701,23 +1727,23 @@ TEST(DBTest, DestroyOpenDB) {
db = nullptr;
// Should succeed destroying a closed db.
- ASSERT_OK(DestroyDB(dbname, Options()));
+ ASSERT_LEVELDB_OK(DestroyDB(dbname, Options()));
ASSERT_TRUE(!env_->FileExists(dbname));
}
-TEST(DBTest, Locking) {
+TEST_F(DBTest, Locking) {
DB* db2 = nullptr;
Status s = DB::Open(CurrentOptions(), dbname_, &db2);
ASSERT_TRUE(!s.ok()) << "Locking did not prevent re-opening db";
}
// Check that number of files does not grow when we are out of space
-TEST(DBTest, NoSpace) {
+TEST_F(DBTest, NoSpace) {
Options options = CurrentOptions();
options.env = env_;
Reopen(&options);
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
ASSERT_EQ("v1", Get("foo"));
Compact("a", "z");
const int num_files = CountFiles();
@@ -1732,18 +1758,18 @@ TEST(DBTest, NoSpace) {
ASSERT_LT(CountFiles(), num_files + 3);
}
-TEST(DBTest, NonWritableFileSystem) {
+TEST_F(DBTest, NonWritableFileSystem) {
Options options = CurrentOptions();
options.write_buffer_size = 1000;
options.env = env_;
Reopen(&options);
- ASSERT_OK(Put("foo", "v1"));
+ ASSERT_LEVELDB_OK(Put("foo", "v1"));
// Force errors for new files.
env_->non_writable_.store(true, std::memory_order_release);
std::string big(100000, 'x');
int errors = 0;
for (int i = 0; i < 20; i++) {
- fprintf(stderr, "iter %d; errors %d\n", i, errors);
+ std::fprintf(stderr, "iter %d; errors %d\n", i, errors);
if (!Put("foo", big).ok()) {
errors++;
DelayMilliseconds(100);
@@ -1753,7 +1779,7 @@ TEST(DBTest, NonWritableFileSystem) {
env_->non_writable_.store(false, std::memory_order_release);
}
-TEST(DBTest, WriteSyncError) {
+TEST_F(DBTest, WriteSyncError) {
// Check that log sync errors cause the DB to disallow future writes.
// (a) Cause log sync calls to fail
@@ -1764,7 +1790,7 @@ TEST(DBTest, WriteSyncError) {
// (b) Normal write should succeed
WriteOptions w;
- ASSERT_OK(db_->Put(w, "k1", "v1"));
+ ASSERT_LEVELDB_OK(db_->Put(w, "k1", "v1"));
ASSERT_EQ("v1", Get("k1"));
// (c) Do a sync write; should fail
@@ -1784,7 +1810,7 @@ TEST(DBTest, WriteSyncError) {
ASSERT_EQ("NOT_FOUND", Get("k3"));
}
-TEST(DBTest, ManifestWriteError) {
+TEST_F(DBTest, ManifestWriteError) {
// Test for the following problem:
// (a) Compaction produces file F
// (b) Log record containing F is written to MANIFEST file, but Sync() fails
@@ -1803,7 +1829,7 @@ TEST(DBTest, ManifestWriteError) {
options.create_if_missing = true;
options.error_if_exists = false;
DestroyAndReopen(&options);
- ASSERT_OK(Put("foo", "bar"));
+ ASSERT_LEVELDB_OK(Put("foo", "bar"));
ASSERT_EQ("bar", Get("foo"));
// Memtable compaction (will succeed)
@@ -1824,8 +1850,8 @@ TEST(DBTest, ManifestWriteError) {
}
}
-TEST(DBTest, MissingSSTFile) {
- ASSERT_OK(Put("foo", "bar"));
+TEST_F(DBTest, MissingSSTFile) {
+ ASSERT_LEVELDB_OK(Put("foo", "bar"));
ASSERT_EQ("bar", Get("foo"));
// Dump the memtable to disk.
@@ -1841,8 +1867,8 @@ TEST(DBTest, MissingSSTFile) {
ASSERT_TRUE(s.ToString().find("issing") != std::string::npos) << s.ToString();
}
-TEST(DBTest, StillReadSST) {
- ASSERT_OK(Put("foo", "bar"));
+TEST_F(DBTest, StillReadSST) {
+ ASSERT_LEVELDB_OK(Put("foo", "bar"));
ASSERT_EQ("bar", Get("foo"));
// Dump the memtable to disk.
@@ -1857,18 +1883,18 @@ TEST(DBTest, StillReadSST) {
ASSERT_EQ("bar", Get("foo"));
}
-TEST(DBTest, FilesDeletedAfterCompaction) {
- ASSERT_OK(Put("foo", "v2"));
+TEST_F(DBTest, FilesDeletedAfterCompaction) {
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
Compact("a", "z");
const int num_files = CountFiles();
for (int i = 0; i < 10; i++) {
- ASSERT_OK(Put("foo", "v2"));
+ ASSERT_LEVELDB_OK(Put("foo", "v2"));
Compact("a", "z");
}
ASSERT_EQ(CountFiles(), num_files);
}
-TEST(DBTest, BloomFilter) {
+TEST_F(DBTest, BloomFilter) {
env_->count_random_reads_ = true;
Options options = CurrentOptions();
options.env = env_;
@@ -1879,11 +1905,11 @@ TEST(DBTest, BloomFilter) {
// Populate multiple layers
const int N = 10000;
for (int i = 0; i < N; i++) {
- ASSERT_OK(Put(Key(i), Key(i)));
+ ASSERT_LEVELDB_OK(Put(Key(i), Key(i)));
}
Compact("a", "z");
for (int i = 0; i < N; i += 100) {
- ASSERT_OK(Put(Key(i), Key(i)));
+ ASSERT_LEVELDB_OK(Put(Key(i), Key(i)));
}
dbfull()->TEST_CompactMemTable();
@@ -1896,7 +1922,7 @@ TEST(DBTest, BloomFilter) {
ASSERT_EQ(Key(i), Get(Key(i)));
}
int reads = env_->random_read_counter_.Read();
- fprintf(stderr, "%d present => %d reads\n", N, reads);
+ std::fprintf(stderr, "%d present => %d reads\n", N, reads);
ASSERT_GE(reads, N);
ASSERT_LE(reads, N + 2 * N / 100);
@@ -1906,7 +1932,7 @@ TEST(DBTest, BloomFilter) {
ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing"));
}
reads = env_->random_read_counter_.Read();
- fprintf(stderr, "%d missing => %d reads\n", N, reads);
+ std::fprintf(stderr, "%d missing => %d reads\n", N, reads);
ASSERT_LE(reads, 3 * N / 100);
env_->delay_data_sync_.store(false, std::memory_order_release);
@@ -1939,7 +1965,7 @@ static void MTThreadBody(void* arg) {
int id = t->id;
DB* db = t->state->test->db_;
int counter = 0;
- fprintf(stderr, "... starting thread %d\n", id);
+ std::fprintf(stderr, "... starting thread %d\n", id);
Random rnd(1000 + id);
std::string value;
char valbuf[1500];
@@ -1948,14 +1974,14 @@ static void MTThreadBody(void* arg) {
int key = rnd.Uniform(kNumKeys);
char keybuf[20];
- snprintf(keybuf, sizeof(keybuf), "%016d", key);
+ std::snprintf(keybuf, sizeof(keybuf), "%016d", key);
if (rnd.OneIn(2)) {
// Write values of the form .
// We add some padding for force compactions.
- snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", key, id,
- static_cast(counter));
- ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));
+ std::snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d", key, id,
+ static_cast(counter));
+ ASSERT_LEVELDB_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));
} else {
// Read a value and verify that it matches the pattern written above.
Status s = db->Get(ReadOptions(), Slice(keybuf), &value);
@@ -1963,7 +1989,7 @@ static void MTThreadBody(void* arg) {
// Key has not yet been written
} else {
// Check that the writer thread counter is >= the counter in the value
- ASSERT_OK(s);
+ ASSERT_LEVELDB_OK(s);
int k, w, c;
ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value;
ASSERT_EQ(k, key);
@@ -1975,12 +2001,12 @@ static void MTThreadBody(void* arg) {
counter++;
}
t->state->thread_done[id].store(true, std::memory_order_release);
- fprintf(stderr, "... stopping thread %d after %d ops\n", id, counter);
+ std::fprintf(stderr, "... stopping thread %d after %d ops\n", id, counter);
}
} // namespace
-TEST(DBTest, MultiThreaded) {
+TEST_F(DBTest, MultiThreaded) {
do {
// Initialize state
MTState mt;
@@ -2125,40 +2151,82 @@ static bool CompareIterators(int step, DB* model, DB* db,
Iterator* dbiter = db->NewIterator(options);
bool ok = true;
int count = 0;
+ std::vector seek_keys;
+ // Compare equality of all elements using Next(). Save some of the keys for
+ // comparing Seek equality.
for (miter->SeekToFirst(), dbiter->SeekToFirst();
ok && miter->Valid() && dbiter->Valid(); miter->Next(), dbiter->Next()) {
count++;
if (miter->key().compare(dbiter->key()) != 0) {
- fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", step,
- EscapeString(miter->key()).c_str(),
- EscapeString(dbiter->key()).c_str());
+ std::fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n", step,
+ EscapeString(miter->key()).c_str(),
+ EscapeString(dbiter->key()).c_str());
ok = false;
break;
}
if (miter->value().compare(dbiter->value()) != 0) {
- fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
- step, EscapeString(miter->key()).c_str(),
- EscapeString(miter->value()).c_str(),
- EscapeString(miter->value()).c_str());
+ std::fprintf(stderr,
+ "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
+ step, EscapeString(miter->key()).c_str(),
+ EscapeString(miter->value()).c_str(),
+ EscapeString(miter->value()).c_str());
ok = false;
+ break;
+ }
+
+ if (count % 10 == 0) {
+ seek_keys.push_back(miter->key().ToString());
}
}
if (ok) {
if (miter->Valid() != dbiter->Valid()) {
- fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
- step, miter->Valid(), dbiter->Valid());
+ std::fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
+ step, miter->Valid(), dbiter->Valid());
ok = false;
}
}
- fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
+
+ if (ok) {
+ // Validate iterator equality when performing seeks.
+ for (auto kiter = seek_keys.begin(); ok && kiter != seek_keys.end();
+ ++kiter) {
+ miter->Seek(*kiter);
+ dbiter->Seek(*kiter);
+ if (!miter->Valid() || !dbiter->Valid()) {
+ std::fprintf(stderr, "step %d: Seek iterators invalid: %d vs. %d\n",
+ step, miter->Valid(), dbiter->Valid());
+ ok = false;
+ }
+ if (miter->key().compare(dbiter->key()) != 0) {
+ std::fprintf(stderr, "step %d: Seek key mismatch: '%s' vs. '%s'\n",
+ step, EscapeString(miter->key()).c_str(),
+ EscapeString(dbiter->key()).c_str());
+ ok = false;
+ break;
+ }
+
+ if (miter->value().compare(dbiter->value()) != 0) {
+ std::fprintf(
+ stderr,
+ "step %d: Seek value mismatch for key '%s': '%s' vs. '%s'\n", step,
+ EscapeString(miter->key()).c_str(),
+ EscapeString(miter->value()).c_str(),
+ EscapeString(miter->value()).c_str());
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ std::fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
delete miter;
delete dbiter;
return ok;
}
-TEST(DBTest, Randomized) {
+TEST_F(DBTest, Randomized) {
Random rnd(test::RandomSeed());
do {
ModelDB model(CurrentOptions());
@@ -2168,7 +2236,7 @@ TEST(DBTest, Randomized) {
std::string k, v;
for (int step = 0; step < N; step++) {
if (step % 100 == 0) {
- fprintf(stderr, "Step %d of %d\n", step, N);
+ std::fprintf(stderr, "Step %d of %d\n", step, N);
}
// TODO(sanjay): Test Get() works
int p = rnd.Uniform(100);
@@ -2176,13 +2244,13 @@ TEST(DBTest, Randomized) {
k = RandomKey(&rnd);
v = RandomString(
&rnd, rnd.OneIn(20) ? 100 + rnd.Uniform(100) : rnd.Uniform(8));
- ASSERT_OK(model.Put(WriteOptions(), k, v));
- ASSERT_OK(db_->Put(WriteOptions(), k, v));
+ ASSERT_LEVELDB_OK(model.Put(WriteOptions(), k, v));
+ ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), k, v));
} else if (p < 90) { // Delete
k = RandomKey(&rnd);
- ASSERT_OK(model.Delete(WriteOptions(), k));
- ASSERT_OK(db_->Delete(WriteOptions(), k));
+ ASSERT_LEVELDB_OK(model.Delete(WriteOptions(), k));
+ ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), k));
} else { // Multi-element batch
WriteBatch b;
@@ -2201,8 +2269,8 @@ TEST(DBTest, Randomized) {
b.Delete(k);
}
}
- ASSERT_OK(model.Write(WriteOptions(), &b));
- ASSERT_OK(db_->Write(WriteOptions(), &b));
+ ASSERT_LEVELDB_OK(model.Write(WriteOptions(), &b));
+ ASSERT_LEVELDB_OK(db_->Write(WriteOptions(), &b));
}
if ((step % 100) == 0) {
@@ -2226,74 +2294,4 @@ TEST(DBTest, Randomized) {
} while (ChangeOptions());
}
-std::string MakeKey(unsigned int num) {
- char buf[30];
- snprintf(buf, sizeof(buf), "%016u", num);
- return std::string(buf);
-}
-
-void BM_LogAndApply(int iters, int num_base_files) {
- std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";
- DestroyDB(dbname, Options());
-
- DB* db = nullptr;
- Options opts;
- opts.create_if_missing = true;
- Status s = DB::Open(opts, dbname, &db);
- ASSERT_OK(s);
- ASSERT_TRUE(db != nullptr);
-
- delete db;
- db = nullptr;
-
- Env* env = Env::Default();
-
- port::Mutex mu;
- MutexLock l(&mu);
-
- InternalKeyComparator cmp(BytewiseComparator());
- Options options;
- VersionSet vset(dbname, &options, nullptr, &cmp);
- bool save_manifest;
- ASSERT_OK(vset.Recover(&save_manifest));
- VersionEdit vbase;
- uint64_t fnum = 1;
- for (int i = 0; i < num_base_files; i++) {
- InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);
- InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);
- vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);
- }
- ASSERT_OK(vset.LogAndApply(&vbase, &mu));
-
- uint64_t start_micros = env->NowMicros();
-
- for (int i = 0; i < iters; i++) {
- VersionEdit vedit;
- vedit.DeleteFile(2, fnum);
- InternalKey start(MakeKey(2 * fnum), 1, kTypeValue);
- InternalKey limit(MakeKey(2 * fnum + 1), 1, kTypeDeletion);
- vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);
- vset.LogAndApply(&vedit, &mu);
- }
- uint64_t stop_micros = env->NowMicros();
- unsigned int us = stop_micros - start_micros;
- char buf[16];
- snprintf(buf, sizeof(buf), "%d", num_base_files);
- fprintf(stderr,
- "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n", buf,
- iters, us, ((float)us) / iters);
-}
-
} // namespace leveldb
-
-int main(int argc, char** argv) {
- if (argc > 1 && std::string(argv[1]) == "--benchmark") {
- leveldb::BM_LogAndApply(1000, 1);
- leveldb::BM_LogAndApply(1000, 100);
- leveldb::BM_LogAndApply(1000, 10000);
- leveldb::BM_LogAndApply(100, 100000);
- return 0;
- }
-
- return leveldb::test::RunAllTests();
-}
diff --git a/db/dbformat.cc b/db/dbformat.cc
index 459eddf..2a5749f 100644
--- a/db/dbformat.cc
+++ b/db/dbformat.cc
@@ -4,8 +4,7 @@
#include "db/dbformat.h"
-#include
-
+#include
#include
#include "port/port.h"
@@ -127,7 +126,7 @@ LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
start_ = dst;
dst = EncodeVarint32(dst, usize + 8);
kstart_ = dst;
- memcpy(dst, user_key.data(), usize);
+ std::memcpy(dst, user_key.data(), usize);
dst += usize;
EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
dst += 8;
diff --git a/db/dbformat_test.cc b/db/dbformat_test.cc
index 1209369..7f3f81a 100644
--- a/db/dbformat_test.cc
+++ b/db/dbformat_test.cc
@@ -3,8 +3,9 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "db/dbformat.h"
+
+#include "gtest/gtest.h"
#include "util/logging.h"
-#include "util/testharness.h"
namespace leveldb {
@@ -41,8 +42,6 @@ static void TestKey(const std::string& key, uint64_t seq, ValueType vt) {
ASSERT_TRUE(!ParseInternalKey(Slice("bar"), &decoded));
}
-class FormatTest {};
-
TEST(FormatTest, InternalKey_EncodeDecode) {
const char* keys[] = {"", "k", "hello", "longggggggggggggggggggggg"};
const uint64_t seq[] = {1,
@@ -127,5 +126,3 @@ TEST(FormatTest, InternalKeyDebugString) {
}
} // namespace leveldb
-
-int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
diff --git a/db/dumpfile.cc b/db/dumpfile.cc
index 77d5900..6085475 100644
--- a/db/dumpfile.cc
+++ b/db/dumpfile.cc
@@ -4,7 +4,7 @@
#include "leveldb/dumpfile.h"
-#include
+#include
#include "db/dbformat.h"
#include "db/filename.h"
diff --git a/db/fault_injection_test.cc b/db/fault_injection_test.cc
index 5b31bb8..ef864a4 100644
--- a/db/fault_injection_test.cc
+++ b/db/fault_injection_test.cc
@@ -9,6 +9,7 @@
#include
Note about Ext4 Filesystems
-The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.
+The preceding numbers are for an ext3 file system. Synchronous writes are much slower under ext4 (LevelDB drops to ~31 writes / second and TreeDB drops to ~5 writes / second; SQLite3's synchronous writes do not noticeably drop) due to ext4's different handling of fsync / msync calls. Even LevelDB's asynchronous write performance drops somewhat since it spreads its storage across multiple files and issues fsync calls when switching to a new file.
Acknowledgements
Jeff Dean and Sanjay Ghemawat wrote LevelDB. Kevin Tseng wrote and compiled these benchmarks. Mikio Hirabayashi, Scott Hess, and Gabor Cselle provided help and advice.
diff --git a/doc/impl.md b/doc/impl.md
index cacabb9..c9bb621 100644
--- a/doc/impl.md
+++ b/doc/impl.md
@@ -1,7 +1,7 @@
## Files
The implementation of leveldb is similar in spirit to the representation of a
-single [Bigtable tablet (section 5.3)](http://research.google.com/archive/bigtable.html).
+single [Bigtable tablet (section 5.3)](https://research.google/pubs/pub27898/).
However the organization of the files that make up the representation is
somewhat different and is explained below.
@@ -166,7 +166,7 @@ So maybe even the sharding is not necessary on modern filesystems?
## Garbage collection of files
-`DeleteObsoleteFiles()` is called at the end of every compaction and at the end
+`RemoveObsoleteFiles()` is called at the end of every compaction and at the end
of recovery. It finds the names of all files in the database. It deletes all log
files that are not the current log file. It deletes all table files that are not
referenced from some level and are not the output of an active compaction.
diff --git a/doc/index.md b/doc/index.md
index 3d9a258..0f6d649 100644
--- a/doc/index.md
+++ b/doc/index.md
@@ -369,6 +369,7 @@ leveldb::Iterator* it = db->NewIterator(options);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
...
}
+delete it;
```
### Key Layout
@@ -424,21 +425,21 @@ spaces. For example:
```c++
class CustomFilterPolicy : public leveldb::FilterPolicy {
private:
- FilterPolicy* builtin_policy_;
+ leveldb::FilterPolicy* builtin_policy_;
public:
- CustomFilterPolicy() : builtin_policy_(NewBloomFilterPolicy(10)) {}
+ CustomFilterPolicy() : builtin_policy_(leveldb::NewBloomFilterPolicy(10)) {}
~CustomFilterPolicy() { delete builtin_policy_; }
const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
- void CreateFilter(const Slice* keys, int n, std::string* dst) const {
+ void CreateFilter(const leveldb::Slice* keys, int n, std::string* dst) const {
// Use builtin bloom filter code after removing trailing spaces
- std::vector trimmed(n);
+ std::vector trimmed(n);
for (int i = 0; i < n; i++) {
trimmed[i] = RemoveTrailingSpaces(keys[i]);
}
- return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
+ builtin_policy_->CreateFilter(trimmed.data(), n, dst);
}
};
```
@@ -478,7 +479,7 @@ leveldb::Range ranges[2];
ranges[0] = leveldb::Range("a", "c");
ranges[1] = leveldb::Range("x", "z");
uint64_t sizes[2];
-leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
+db->GetApproximateSizes(ranges, 2, sizes);
```
The preceding call will set `sizes[0]` to the approximate number of bytes of
diff --git a/helpers/memenv/memenv.cc b/helpers/memenv/memenv.cc
index 31d2bc0..e476613 100644
--- a/helpers/memenv/memenv.cc
+++ b/helpers/memenv/memenv.cc
@@ -4,8 +4,7 @@
#include "helpers/memenv/memenv.h"
-#include
-
+#include
#include
#include