Showing preview only (1,015K chars total). Download the full file or copy to clipboard to get everything.
Repository: google/leveldb
Branch: main
Commit: 7ee830d02b62
Files: 152
Total size: 969.1 KB
Directory structure:
gitextract_rc7lvmbf/
├── .clang-format
├── .github/
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .gitmodules
├── AUTHORS
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── NEWS
├── README.md
├── TODO
├── benchmarks/
│ ├── db_bench.cc
│ ├── db_bench_log.cc
│ ├── db_bench_sqlite3.cc
│ └── db_bench_tree_db.cc
├── cmake/
│ └── leveldbConfig.cmake.in
├── db/
│ ├── autocompact_test.cc
│ ├── builder.cc
│ ├── builder.h
│ ├── c.cc
│ ├── c_test.c
│ ├── corruption_test.cc
│ ├── db_impl.cc
│ ├── db_impl.h
│ ├── db_iter.cc
│ ├── db_iter.h
│ ├── db_test.cc
│ ├── dbformat.cc
│ ├── dbformat.h
│ ├── dbformat_test.cc
│ ├── dumpfile.cc
│ ├── fault_injection_test.cc
│ ├── filename.cc
│ ├── filename.h
│ ├── filename_test.cc
│ ├── leveldbutil.cc
│ ├── log_format.h
│ ├── log_reader.cc
│ ├── log_reader.h
│ ├── log_test.cc
│ ├── log_writer.cc
│ ├── log_writer.h
│ ├── memtable.cc
│ ├── memtable.h
│ ├── recovery_test.cc
│ ├── repair.cc
│ ├── skiplist.h
│ ├── skiplist_test.cc
│ ├── snapshot.h
│ ├── table_cache.cc
│ ├── table_cache.h
│ ├── version_edit.cc
│ ├── version_edit.h
│ ├── version_edit_test.cc
│ ├── version_set.cc
│ ├── version_set.h
│ ├── version_set_test.cc
│ ├── write_batch.cc
│ ├── write_batch_internal.h
│ └── write_batch_test.cc
├── doc/
│ ├── benchmark.html
│ ├── impl.md
│ ├── index.md
│ ├── log_format.md
│ └── table_format.md
├── helpers/
│ └── memenv/
│ ├── memenv.cc
│ ├── memenv.h
│ └── memenv_test.cc
├── include/
│ └── leveldb/
│ ├── c.h
│ ├── cache.h
│ ├── comparator.h
│ ├── db.h
│ ├── dumpfile.h
│ ├── env.h
│ ├── export.h
│ ├── filter_policy.h
│ ├── iterator.h
│ ├── options.h
│ ├── slice.h
│ ├── status.h
│ ├── table.h
│ ├── table_builder.h
│ └── write_batch.h
├── issues/
│ ├── issue178_test.cc
│ ├── issue200_test.cc
│ └── issue320_test.cc
├── port/
│ ├── README.md
│ ├── port.h
│ ├── port_config.h.in
│ ├── port_example.h
│ ├── port_stdcxx.h
│ └── thread_annotations.h
├── table/
│ ├── block.cc
│ ├── block.h
│ ├── block_builder.cc
│ ├── block_builder.h
│ ├── filter_block.cc
│ ├── filter_block.h
│ ├── filter_block_test.cc
│ ├── format.cc
│ ├── format.h
│ ├── iterator.cc
│ ├── iterator_wrapper.h
│ ├── merger.cc
│ ├── merger.h
│ ├── table.cc
│ ├── table_builder.cc
│ ├── table_test.cc
│ ├── two_level_iterator.cc
│ └── two_level_iterator.h
└── util/
├── arena.cc
├── arena.h
├── arena_test.cc
├── bloom.cc
├── bloom_test.cc
├── cache.cc
├── cache_test.cc
├── coding.cc
├── coding.h
├── coding_test.cc
├── comparator.cc
├── crc32c.cc
├── crc32c.h
├── crc32c_test.cc
├── env.cc
├── env_posix.cc
├── env_posix_test.cc
├── env_posix_test_helper.h
├── env_test.cc
├── env_windows.cc
├── env_windows_test.cc
├── env_windows_test_helper.h
├── filter_policy.cc
├── hash.cc
├── hash.h
├── hash_test.cc
├── histogram.cc
├── histogram.h
├── logging.cc
├── logging.h
├── logging_test.cc
├── mutexlock.h
├── no_destructor.h
├── no_destructor_test.cc
├── options.cc
├── posix_logger.h
├── random.h
├── status.cc
├── status_test.cc
├── testutil.cc
├── testutil.h
└── windows_logger.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .clang-format
================================================
# Run manually to reformat a file:
# clang-format -i --style=file <file>
# find . -iname '*.cc' -o -iname '*.h' -o -iname '*.h.in' | xargs clang-format -i --style=file
BasedOnStyle: Google
DerivePointerAlignment: false
# Public headers are in a different location in the internal Google repository.
# Order them so that when imported to the authoritative repository they will be
# in correct alphabetical order.
IncludeCategories:
- Regex: '^(<|"(benchmarks|db|helpers)/)'
Priority: 1
- Regex: '^"(leveldb)/'
Priority: 2
- Regex: '^(<|"(issues|port|table|third_party|util)/)'
Priority: 3
- Regex: '.*'
Priority: 4
================================================
FILE: .github/workflows/build.yml
================================================
# 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' }}
# libgoogle-perftools-dev is temporarily removed from the package list
# because it is currently broken on GitHub's Ubuntu 22.04.
run: |
sudo apt-get update
sudo apt-get install 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
================================================
FILE: .gitignore
================================================
# Editors.
*.sw*
.vscode
.DS_Store
# Build directory.
build/
out/
================================================
FILE: .gitmodules
================================================
[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
================================================
FILE: AUTHORS
================================================
# Names should be added to this file like so:
# Name or Organization <email address>
Google Inc.
# Initial version authors:
Jeffrey Dean <jeff@google.com>
Sanjay Ghemawat <sanjay@google.com>
# Partial list of contributors:
Kevin Regan <kevin.d.regan@gmail.com>
Johan Bilien <jobi@litl.com>
================================================
FILE: CMakeLists.txt
================================================
# Copyright 2017 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.
cmake_minimum_required(VERSION 3.22)
# Keep the version below in sync with the one in db.h
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++17.
set(CMAKE_CXX_STANDARD 17)
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)
# TODO(cmumford): Make UNICODE configurable for Windows.
add_definitions(-D_UNICODE -DUNICODE)
else (WIN32)
set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_POSIX)
endif (WIN32)
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(CheckIncludeFile)
check_include_file("unistd.h" HAVE_UNISTD_H)
include(CheckLibraryExists)
check_library_exists(crc32c crc32c_value "" HAVE_CRC32C)
check_library_exists(snappy snappy_compress "" HAVE_SNAPPY)
check_library_exists(zstd zstd_compress "" HAVE_ZSTD)
check_library_exists(tcmalloc malloc "" HAVE_TCMALLOC)
include(CheckCXXSymbolExists)
# Using check_cxx_symbol_exists() instead of check_c_symbol_exists() because
# we're including the header from C++, and feature detection should use the same
# compiler language that the project will use later. Principles aside, some
# versions of do not expose fdatasync() in <unistd.h> in standard C mode
# (-std=c11), but do expose the function in standard C++ mode (-std=c++11).
check_cxx_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC)
check_cxx_symbol_exists(F_FULLFSYNC "fcntl.h" HAVE_FULLFSYNC)
check_cxx_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Disable C++ exceptions.
string(REGEX REPLACE "/EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHs-c-")
add_definitions(-D_HAS_EXCEPTIONS=0)
# Disable RTTI.
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Enable strict prototype warnings for C code in clang and gcc.
if(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
endif(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")
# Disable C++ exceptions.
string(REGEX REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
# Disable RTTI.
string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Test whether -Wthread-safety is available. See
# https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
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.
check_cxx_source_compiles("
#if defined(__has_include) && __has_include(<string>)
#include <string>
#endif
int main() { std::string str; return 0; }
" HAVE_CXX17_HAS_INCLUDE)
set(LEVELDB_PUBLIC_INCLUDE_DIR "include/leveldb")
set(LEVELDB_PORT_CONFIG_DIR "include/port")
configure_file(
"port/port_config.h.in"
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
)
include_directories(
"${PROJECT_BINARY_DIR}/include"
"."
)
if(BUILD_SHARED_LIBS)
# Only export LEVELDB_EXPORT symbols from the shared library.
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"
"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".
$<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC>
"${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"
)
if (WIN32)
target_sources(leveldb
PRIVATE
"util/env_windows.cc"
"util/windows_logger.h"
)
else (WIN32)
target_sources(leveldb
PRIVATE
"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
"helpers/memenv/memenv.cc"
"helpers/memenv/memenv.h"
)
target_include_directories(leveldb
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties(leveldb
PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
target_compile_definitions(leveldb
PRIVATE
# Used by include/export.h when building shared libraries.
LEVELDB_COMPILE_LIBRARY
# Used by port/port.h.
${LEVELDB_PLATFORM_NAME}=1
)
if (NOT HAVE_CXX17_HAS_INCLUDE)
target_compile_definitions(leveldb
PRIVATE
LEVELDB_HAS_PORT_CONFIG_H=1
)
endif(NOT HAVE_CXX17_HAS_INCLUDE)
if(BUILD_SHARED_LIBS)
target_compile_definitions(leveldb
PUBLIC
# Used by include/export.h.
LEVELDB_SHARED_LIBRARY
)
endif(BUILD_SHARED_LIBS)
if(HAVE_CLANG_THREAD_SAFETY)
target_compile_options(leveldb
PUBLIC
-Werror -Wthread-safety)
endif(HAVE_CLANG_THREAD_SAFETY)
if(HAVE_CRC32C)
target_link_libraries(leveldb crc32c)
endif(HAVE_CRC32C)
if(HAVE_SNAPPY)
target_link_libraries(leveldb snappy)
endif(HAVE_SNAPPY)
if(HAVE_ZSTD)
target_link_libraries(leveldb zstd)
endif(HAVE_ZSTD)
if(HAVE_TCMALLOC)
target_link_libraries(leveldb tcmalloc)
endif(HAVE_TCMALLOC)
# Needed by port_stdcxx.h
find_package(Threads REQUIRED)
target_link_libraries(leveldb Threads::Threads)
add_executable(leveldbutil
"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)
add_executable("${test_target_name}" "")
target_sources("${test_target_name}"
PRIVATE
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
"util/testutil.cc"
"util/testutil.h"
"${test_file}"
)
target_link_libraries("${test_target_name}" leveldb gmock gtest)
target_compile_definitions("${test_target_name}"
PRIVATE
${LEVELDB_PLATFORM_NAME}=1
)
if (NOT HAVE_CXX17_HAS_INCLUDE)
target_compile_definitions("${test_target_name}"
PRIVATE
LEVELDB_HAS_PORT_CONFIG_H=1
)
endif(NOT HAVE_CXX17_HAS_INCLUDE)
add_test(NAME "${test_target_name}" COMMAND "${test_target_name}")
endfunction(leveldb_test)
leveldb_test("db/c_test.c")
if(NOT BUILD_SHARED_LIBS)
# TODO(costan): This test also uses
# "util/env_{posix|windows}_test_helper.h"
if (WIN32)
leveldb_test("util/env_windows_test.cc")
else (WIN32)
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)
add_executable("${bench_target_name}" "")
target_sources("${bench_target_name}"
PRIVATE
"${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
"util/histogram.cc"
"util/histogram.h"
"util/testutil.cc"
"util/testutil.h"
"${bench_file}"
)
target_link_libraries("${bench_target_name}" leveldb gmock gtest benchmark)
target_compile_definitions("${bench_target_name}"
PRIVATE
${LEVELDB_PLATFORM_NAME}=1
)
if (NOT HAVE_CXX17_HAS_INCLUDE)
target_compile_definitions("${bench_target_name}"
PRIVATE
LEVELDB_HAS_PORT_CONFIG_H=1
)
endif(NOT HAVE_CXX17_HAS_INCLUDE)
endfunction(leveldb_benchmark)
if(NOT BUILD_SHARED_LIBS)
leveldb_benchmark("benchmarks/db_bench.cc")
endif(NOT BUILD_SHARED_LIBS)
check_library_exists(sqlite3 sqlite3_open "" HAVE_SQLITE3)
if(HAVE_SQLITE3)
leveldb_benchmark("benchmarks/db_bench_sqlite3.cc")
target_link_libraries(db_bench_sqlite3 sqlite3)
endif(HAVE_SQLITE3)
# check_library_exists is insufficient here because the library names have
# different manglings when compiled with clang or gcc, at least when installed
# with Homebrew on Mac.
set(OLD_CMAKE_REQURED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
list(APPEND CMAKE_REQUIRED_LIBRARIES kyotocabinet)
check_cxx_source_compiles("
#include <kcpolydb.h>
int main() {
kyotocabinet::TreeDB* db = new kyotocabinet::TreeDB();
delete db;
return 0;
}
" HAVE_KYOTOCABINET)
set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQURED_LIBRARIES})
if(HAVE_KYOTOCABINET)
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)
install(TARGETS leveldb
EXPORT leveldbTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(
FILES
"${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}/cmake/${PROJECT_NAME}ConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
)
install(
EXPORT leveldbTargets
NAMESPACE leveldb::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
install(
FILES
"${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)
================================================
FILE: CONTRIBUTING.md
================================================
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code Reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
See [the README](README.md#contributing-to-the-leveldb-project) for areas
where we are likely to accept external contributions.
## Community Guidelines
This project follows [Google's Open Source Community
Guidelines](https://opensource.google/conduct/).
================================================
FILE: LICENSE
================================================
Copyright (c) 2011 The LevelDB Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: NEWS
================================================
Release 1.2 2011-05-16
----------------------
Fixes for larger databases (tested up to one billion 100-byte entries,
i.e., ~100GB).
(1) Place hard limit on number of level-0 files. This fixes errors
of the form "too many open files".
(2) Fixed memtable management. Before the fix, a heavy write burst
could cause unbounded memory usage.
A fix for a logging bug where the reader would incorrectly complain
about corruption.
Allow public access to WriteBatch contents so that users can easily
wrap a DB.
================================================
FILE: README.md
================================================
LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.
> **This repository is receiving very limited maintenance. We will only review the following types of changes.**
>
> * Fixes for critical bugs, such as data loss or memory corruption
> * Changes absolutely needed by internally supported leveldb clients. These typically fix breakage introduced by a language/standard library/OS update
[](https://github.com/google/leveldb/actions/workflows/build.yml)
Authors: Sanjay Ghemawat (sanjay@google.com) and Jeff Dean (jeff@google.com)
# Features
* Keys and values are arbitrary byte arrays.
* Data is stored sorted by key.
* Callers can provide a custom comparison function to override the sort order.
* The basic operations are `Put(key,value)`, `Get(key)`, `Delete(key)`.
* 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](https://google.github.io/snappy/), but [Zstd compression](https://facebook.github.io/zstd/) is also supported.
* External activity (file system operations etc.) is relayed through a virtual interface so users can customize the operating system interactions.
# Documentation
[LevelDB library documentation](https://github.com/google/leveldb/blob/main/doc/index.md) is online and bundled with the source code.
# Limitations
* This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes.
* 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.
### Build for POSIX
Quick start:
```bash
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
```
### Building for Windows
First generate the Visual Studio 2017 project/solution files:
```cmd
mkdir build
cd build
cmake -G "Visual Studio 15" ..
```
The default default will build for x86. For 64-bit run:
```cmd
cmake -G "Visual Studio 15 Win64" ..
```
To compile the Windows solution from the command-line:
```cmd
devenv /build Debug leveldb.sln
```
or open leveldb.sln in Visual Studio and build from within.
Please see the CMake documentation and `CMakeLists.txt` for more advanced usage.
# Contributing to the leveldb Project
> **This repository is receiving very limited maintenance. We will only review the following types of changes.**
>
> * Bug fixes
> * Changes absolutely needed by internally supported leveldb clients. These typically fix breakage introduced by a language/standard library/OS update
The leveldb project welcomes contributions. leveldb's primary goal is to be
a reliable and fast key/value store. Changes that are in line with the
features/limitations outlined above, and meet the requirements below,
will be considered.
Contribution requirements:
1. **Tested platforms only**. We _generally_ will only accept changes for
platforms that are compiled and tested. This means POSIX (for Linux and
macOS) or Windows. Very small changes will sometimes be accepted, but
consider that more of an exception than the rule.
2. **Stable API**. We strive very hard to maintain a stable API. Changes that
require changes for projects using leveldb _might_ be rejected without
sufficient benefit to the project.
3. **Tests**: All changes must be accompanied by a new (or changed) test, or
a sufficient explanation as to why a new (or changed) test is not required.
4. **Consistent Style**: This project conforms to the
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
To ensure your changes are properly formatted please run:
```
clang-format -i --style=file <file>
```
We are unlikely to accept contributions to the build configuration files, such
as `CMakeLists.txt`. We are focused on maintaining a build configuration that
allows us to test that the project works in a few supported configurations
inside Google. We are not currently interested in supporting other requirements,
such as different operating systems, compilers, or build systems.
## Submitting a Pull Request
Before any pull request will be accepted the author must first sign a
Contributor License Agreement (CLA) at https://cla.developers.google.com/.
In order to keep the commit timeline linear
[squash](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits)
your changes down to a single commit and [rebase](https://git-scm.com/docs/git-rebase)
on google/leveldb/main. This keeps the commit timeline linear and more easily sync'ed
with the internal repository at Google. More information at GitHub's
[About Git rebase](https://help.github.com/articles/about-git-rebase/) page.
# Performance
Here is a performance report (with explanations) from the run of the
included db_bench program. The results are somewhat noisy, but should
be enough to get a ballpark performance estimate.
## Setup
We use a database with a million entries. Each entry has a 16 byte
key, and a 100 byte value. Values used by the benchmark compress to
about half their original size.
LevelDB: version 1.1
Date: Sun May 1 12:11:26 2011
CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
CPUCache: 4096 KB
Keys: 16 bytes each
Values: 100 bytes each (50 bytes after compression)
Entries: 1000000
Raw Size: 110.6 MB (estimated)
File Size: 62.9 MB (estimated)
## Write performance
The "fill" benchmarks create a brand new database, in either
sequential, or random order. The "fillsync" benchmark flushes data
from the operating system to the disk after every operation; the other
write operations leave the data sitting in the operating system buffer
cache for a while. The "overwrite" benchmark does random writes that
update existing keys in the database.
fillseq : 1.765 micros/op; 62.7 MB/s
fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops)
fillrandom : 2.460 micros/op; 45.0 MB/s
overwrite : 2.380 micros/op; 46.5 MB/s
Each "op" above corresponds to a write of a single key/value pair.
I.e., a random write benchmark goes at approximately 400,000 writes per second.
Each "fillsync" operation costs much less (0.3 millisecond)
than a disk seek (typically 10 milliseconds). We suspect that this is
because the hard disk itself is buffering the update in its memory and
responding before the data has been written to the platter. This may
or may not be safe based on whether or not the hard disk has enough
power to save its memory in the event of a power failure.
## Read performance
We list the performance of reading sequentially in both the forward
and reverse direction, and also the performance of a random lookup.
Note that the database created by the benchmark is quite small.
Therefore the report characterizes the performance of leveldb when the
working set fits in memory. The cost of reading a piece of data that
is not present in the operating system buffer cache will be dominated
by the one or two disk seeks needed to fetch the data from disk.
Write performance will be mostly unaffected by whether or not the
working set fits in memory.
readrandom : 16.677 micros/op; (approximately 60,000 reads per second)
readseq : 0.476 micros/op; 232.3 MB/s
readreverse : 0.724 micros/op; 152.9 MB/s
LevelDB compacts its underlying storage data in the background to
improve read performance. The results listed above were done
immediately after a lot of random writes. The results after
compactions (which are usually triggered automatically) are better.
readrandom : 11.602 micros/op; (approximately 85,000 reads per second)
readseq : 0.423 micros/op; 261.8 MB/s
readreverse : 0.663 micros/op; 166.9 MB/s
Some of the high cost of reads comes from repeated decompression of blocks
read from disk. If we supply enough cache to the leveldb so it can hold the
uncompressed blocks in memory, the read performance improves again:
readrandom : 9.775 micros/op; (approximately 100,000 reads per second before compaction)
readrandom : 5.215 micros/op; (approximately 190,000 reads per second after compaction)
## Repository contents
See [doc/index.md](doc/index.md) for more explanation. See
[doc/impl.md](doc/impl.md) for a brief overview of the implementation.
The public interface is in include/leveldb/*.h. Callers should not include or
rely on the details of any other header files in this package. Those
internal APIs may be changed without warning.
Guide to header files:
* **include/leveldb/db.h**: Main interface to the DB: Start here.
* **include/leveldb/options.h**: Control over the behavior of an entire database,
and also control over the behavior of individual reads and writes.
* **include/leveldb/comparator.h**: Abstraction for user-specified comparison function.
If you want just bytewise comparison of keys, you can use the default
comparator, but clients can write their own comparator implementations if they
want custom ordering (e.g. to handle different character encodings, etc.).
* **include/leveldb/iterator.h**: Interface for iterating over data. You can get
an iterator from a DB object.
* **include/leveldb/write_batch.h**: Interface for atomically applying multiple
updates to a database.
* **include/leveldb/slice.h**: A simple module for maintaining a pointer and a
length into some other byte array.
* **include/leveldb/status.h**: Status is returned from many of the public interfaces
and is used to report success and various kinds of errors.
* **include/leveldb/env.h**:
Abstraction of the OS environment. A posix implementation of this interface is
in util/env_posix.cc.
* **include/leveldb/table.h, include/leveldb/table_builder.h**: Lower-level modules that most
clients probably won't use directly.
================================================
FILE: TODO
================================================
ss
- Stats
db
- Maybe implement DB::BulkDeleteForRange(start_key, end_key)
that would blow away files whose ranges are entirely contained
within [start_key..end_key]? For Chrome, deletion of obsolete
object stores, etc. can be done in the background anyway, so
probably not that important.
- There have been requests for MultiGet.
After a range is completely deleted, what gets rid of the
corresponding files if we do no future changes to that range. Make
the conditions for triggering compactions fire in more situations?
================================================
FILE: benchmarks/db_bench.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <sys/types.h>
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include "leveldb/cache.h"
#include "leveldb/comparator.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/filter_policy.h"
#include "leveldb/write_batch.h"
#include "port/port.h"
#include "util/crc32c.h"
#include "util/histogram.h"
#include "util/mutexlock.h"
#include "util/random.h"
#include "util/testutil.h"
// Comma-separated list of operations to run in the specified order
// Actual benchmarks:
// fillseq -- write N values in sequential key order in async mode
// fillrandom -- write N values in random key order in async mode
// overwrite -- overwrite N values in random key order in async mode
// fillsync -- write N/100 values in random key order in sync mode
// fill100K -- write N/1000 100K values in random order in async mode
// deleteseq -- delete N keys in sequential order
// deleterandom -- delete N keys in random order
// readseq -- read N times sequentially
// readreverse -- read N times in reverse order
// readrandom -- read N times in random order
// 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:
// compact -- Compact the entire DB
// stats -- Print DB stats
// sstables -- Print sstable info
// heapprofile -- Dump a heap profile (if supported by this port)
static const char* FLAGS_benchmarks =
"fillseq,"
"fillsync,"
"fillrandom,"
"overwrite,"
"readrandom,"
"readrandom," // Extra run to allow previous compactions to quiesce
"readseq,"
"readreverse,"
"compact,"
"readrandom,"
"readseq,"
"readreverse,"
"fill100K,"
"crc32c,"
"snappycomp,"
"snappyuncomp,"
"zstdcomp,"
"zstduncomp,";
// Number of key/values to place in database
static int FLAGS_num = 1000000;
// Number of read operations to do. If negative, do FLAGS_num reads.
static int FLAGS_reads = -1;
// Number of concurrent threads to run.
static int FLAGS_threads = 1;
// Size of each value
static int FLAGS_value_size = 100;
// Arrange to generate values that shrink to this fraction of
// their original size after compression
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;
// Number of bytes written to each file.
// (initialized to default value by "main")
static int FLAGS_max_file_size = 0;
// Approximate size of user data packed per block (before compression.
// (initialized to default value by "main")
static int FLAGS_block_size = 0;
// Number of bytes to use as a cache of uncompressed data.
// Negative means use default settings.
static int FLAGS_cache_size = -1;
// Maximum number of files to keep open at the same time (use default if == 0)
static int FLAGS_open_files = 0;
// Bloom filter bits per key.
// 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.
static bool FLAGS_use_existing_db = false;
// If true, reuse existing log/MANIFEST files when re-opening a database.
static bool FLAGS_reuse_logs = false;
// If true, use compression.
static bool FLAGS_compression = true;
// Use the db with the following name.
static const char* FLAGS_db = nullptr;
// ZSTD compression level to try out
static int FLAGS_zstd_compression_level = 1;
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<size_t> count_{0};
const Comparator* const wrapped_;
};
// Helper for quickly generating random data.
class RandomGenerator {
private:
std::string data_;
int pos_;
public:
RandomGenerator() {
// We use a limited amount of data over and over again and ensure
// that it is larger than the compression window (32KB), and also
// large enough to serve all typical value sizes we want to write.
Random rnd(301);
std::string piece;
while (data_.size() < 1048576) {
// Add a short fragment that is as compressible as specified
// by FLAGS_compression_ratio.
test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
data_.append(piece);
}
pos_ = 0;
}
Slice Generate(size_t len) {
if (pos_ + len > data_.size()) {
pos_ = 0;
assert(len < data_.size());
}
pos_ += len;
return Slice(data_.data() + pos_ - len, len);
}
};
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;
while (start < s.size() && isspace(s[start])) {
start++;
}
size_t limit = s.size();
while (limit > start && isspace(s[limit - 1])) {
limit--;
}
return Slice(s.data() + start, limit - start);
}
#endif
static void AppendWithSpace(std::string* str, Slice msg) {
if (msg.empty()) return;
if (!str->empty()) {
str->push_back(' ');
}
str->append(msg.data(), msg.size());
}
class Stats {
private:
double start_;
double finish_;
double seconds_;
int done_;
int next_report_;
int64_t bytes_;
double last_op_finish_;
Histogram hist_;
std::string message_;
public:
Stats() { Start(); }
void Start() {
next_report_ = 100;
hist_.Clear();
done_ = 0;
bytes_ = 0;
seconds_ = 0;
message_.clear();
start_ = finish_ = last_op_finish_ = g_env->NowMicros();
}
void Merge(const Stats& other) {
hist_.Merge(other.hist_);
done_ += other.done_;
bytes_ += other.bytes_;
seconds_ += other.seconds_;
if (other.start_ < start_) start_ = other.start_;
if (other.finish_ > finish_) finish_ = other.finish_;
// Just keep the messages from one thread
if (message_.empty()) message_ = other.message_;
}
void Stop() {
finish_ = g_env->NowMicros();
seconds_ = (finish_ - start_) * 1e-6;
}
void AddMessage(Slice msg) { AppendWithSpace(&message_, msg); }
void FinishedSingleOp() {
if (FLAGS_histogram) {
double now = g_env->NowMicros();
double micros = now - last_op_finish_;
hist_.Add(micros);
if (micros > 20000) {
std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
std::fflush(stderr);
}
last_op_finish_ = now;
}
done_++;
if (done_ >= next_report_) {
if (next_report_ < 1000)
next_report_ += 100;
else if (next_report_ < 5000)
next_report_ += 500;
else if (next_report_ < 10000)
next_report_ += 1000;
else if (next_report_ < 50000)
next_report_ += 5000;
else if (next_report_ < 100000)
next_report_ += 10000;
else if (next_report_ < 500000)
next_report_ += 50000;
else
next_report_ += 100000;
std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
std::fflush(stderr);
}
}
void AddBytes(int64_t n) { bytes_ += n; }
void Report(const Slice& name) {
// Pretend at least one op was done in case we are running a benchmark
// that does not call FinishedSingleOp().
if (done_ < 1) done_ = 1;
std::string extra;
if (bytes_ > 0) {
// Rate is computed on actual elapsed time, not the sum of per-thread
// elapsed times.
double elapsed = (finish_ - start_) * 1e-6;
char rate[100];
std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
(bytes_ / 1048576.0) / elapsed);
extra = rate;
}
AppendWithSpace(&extra, message_);
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) {
std::fprintf(stdout, "Microseconds per op:\n%s\n",
hist_.ToString().c_str());
}
std::fflush(stdout);
}
};
// State shared by all concurrent executions of the same benchmark.
struct SharedState {
port::Mutex mu;
port::CondVar cv GUARDED_BY(mu);
int total GUARDED_BY(mu);
// Each thread goes through the following states:
// (1) initializing
// (2) waiting for others to be initialized
// (3) running
// (4) done
int num_initialized GUARDED_BY(mu);
int num_done GUARDED_BY(mu);
bool start GUARDED_BY(mu);
SharedState(int total)
: cv(&mu), total(total), num_initialized(0), num_done(0), start(false) {}
};
// Per-thread state for concurrent executions of the same benchmark.
struct ThreadState {
int tid; // 0..n-1 when running in n threads
Random rand; // Has different seeds for different threads
Stats stats;
SharedState* shared;
ThreadState(int index, int seed) : tid(index), rand(seed), shared(nullptr) {}
};
void Compress(
ThreadState* thread, std::string name,
std::function<bool(const char*, size_t, std::string*)> compress_func) {
RandomGenerator gen;
Slice input = gen.Generate(Options().block_size);
int64_t bytes = 0;
int64_t produced = 0;
bool ok = true;
std::string compressed;
while (ok && bytes < 1024 * 1048576) { // Compress 1G
ok = compress_func(input.data(), input.size(), &compressed);
produced += compressed.size();
bytes += input.size();
thread->stats.FinishedSingleOp();
}
if (!ok) {
thread->stats.AddMessage("(" + name + " failure)");
} else {
char buf[100];
std::snprintf(buf, sizeof(buf), "(output: %.1f%%)",
(produced * 100.0) / bytes);
thread->stats.AddMessage(buf);
thread->stats.AddBytes(bytes);
}
}
void Uncompress(
ThreadState* thread, std::string name,
std::function<bool(const char*, size_t, std::string*)> compress_func,
std::function<bool(const char*, size_t, char*)> uncompress_func) {
RandomGenerator gen;
Slice input = gen.Generate(Options().block_size);
std::string compressed;
bool ok = compress_func(input.data(), input.size(), &compressed);
int64_t bytes = 0;
char* uncompressed = new char[input.size()];
while (ok && bytes < 1024 * 1048576) { // Compress 1G
ok = uncompress_func(compressed.data(), compressed.size(), uncompressed);
bytes += input.size();
thread->stats.FinishedSingleOp();
}
delete[] uncompressed;
if (!ok) {
thread->stats.AddMessage("(" + name + " failure)");
} else {
thread->stats.AddBytes(bytes);
}
}
} // namespace
class Benchmark {
private:
Cache* cache_;
const FilterPolicy* filter_policy_;
DB* db_;
int num_;
int value_size_;
int entries_per_batch_;
WriteOptions write_options_;
int reads_;
int heap_counter_;
CountComparator count_comparator_;
int total_thread_count_;
void PrintHeader() {
const int kKeySize = 16 + FLAGS_key_prefix;
PrintEnvironment();
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<int>(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<int64_t>(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();
std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
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)) {
std::fprintf(stdout, "WARNING: Snappy compression is not enabled\n");
} else if (compressed.size() >= sizeof(text)) {
std::fprintf(stdout, "WARNING: Snappy compression is not effective\n");
}
}
void PrintEnvironment() {
std::fprintf(stderr, "LevelDB: version %d.%d\n", kMajorVersion,
kMinorVersion);
#if defined(__linux)
time_t now = time(nullptr);
std::fprintf(stderr, "Date: %s",
ctime(&now)); // ctime() adds newline
FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
std::string cpu_type;
std::string cache_size;
while (fgets(line, sizeof(line), cpuinfo) != nullptr) {
const char* sep = strchr(line, ':');
if (sep == nullptr) {
continue;
}
Slice key = TrimSpace(Slice(line, sep - 1 - line));
Slice val = TrimSpace(Slice(sep + 1));
if (key == "model name") {
++num_cpus;
cpu_type = val.ToString();
} else if (key == "cache size") {
cache_size = val.ToString();
}
}
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
}
public:
Benchmark()
: cache_(FLAGS_cache_size >= 0 ? NewLRUCache(FLAGS_cache_size) : nullptr),
filter_policy_(FLAGS_bloom_bits >= 0
? NewBloomFilterPolicy(FLAGS_bloom_bits)
: nullptr),
db_(nullptr),
num_(FLAGS_num),
value_size_(FLAGS_value_size),
entries_per_batch_(1),
reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
heap_counter_(0),
count_comparator_(BytewiseComparator()),
total_thread_count_(0) {
std::vector<std::string> 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->RemoveFile(std::string(FLAGS_db) + "/" + files[i]);
}
}
if (!FLAGS_use_existing_db) {
DestroyDB(FLAGS_db, Options());
}
}
~Benchmark() {
delete db_;
delete cache_;
delete filter_policy_;
}
void Run() {
PrintHeader();
Open();
const char* benchmarks = FLAGS_benchmarks;
while (benchmarks != nullptr) {
const char* sep = strchr(benchmarks, ',');
Slice name;
if (sep == nullptr) {
name = benchmarks;
benchmarks = nullptr;
} else {
name = Slice(benchmarks, sep - benchmarks);
benchmarks = sep + 1;
}
// Reset parameters that may be overridden below
num_ = FLAGS_num;
reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);
value_size_ = FLAGS_value_size;
entries_per_batch_ = 1;
write_options_ = WriteOptions();
void (Benchmark::*method)(ThreadState*) = nullptr;
bool fresh_db = false;
int num_threads = FLAGS_threads;
if (name == Slice("open")) {
method = &Benchmark::OpenBench;
num_ /= 10000;
if (num_ < 1) num_ = 1;
} else if (name == Slice("fillseq")) {
fresh_db = true;
method = &Benchmark::WriteSeq;
} else if (name == Slice("fillbatch")) {
fresh_db = true;
entries_per_batch_ = 1000;
method = &Benchmark::WriteSeq;
} else if (name == Slice("fillrandom")) {
fresh_db = true;
method = &Benchmark::WriteRandom;
} else if (name == Slice("overwrite")) {
fresh_db = false;
method = &Benchmark::WriteRandom;
} else if (name == Slice("fillsync")) {
fresh_db = true;
num_ /= 1000;
write_options_.sync = true;
method = &Benchmark::WriteRandom;
} else if (name == Slice("fill100K")) {
fresh_db = true;
num_ /= 1000;
value_size_ = 100 * 1000;
method = &Benchmark::WriteRandom;
} else if (name == Slice("readseq")) {
method = &Benchmark::ReadSequential;
} else if (name == Slice("readreverse")) {
method = &Benchmark::ReadReverse;
} else if (name == Slice("readrandom")) {
method = &Benchmark::ReadRandom;
} else if (name == Slice("readmissing")) {
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")) {
reads_ /= 1000;
method = &Benchmark::ReadRandom;
} else if (name == Slice("deleteseq")) {
method = &Benchmark::DeleteSeq;
} else if (name == Slice("deleterandom")) {
method = &Benchmark::DeleteRandom;
} else if (name == Slice("readwhilewriting")) {
num_threads++; // Add extra thread for writing
method = &Benchmark::ReadWhileWriting;
} else if (name == Slice("compact")) {
method = &Benchmark::Compact;
} else if (name == Slice("crc32c")) {
method = &Benchmark::Crc32c;
} else if (name == Slice("snappycomp")) {
method = &Benchmark::SnappyCompress;
} else if (name == Slice("snappyuncomp")) {
method = &Benchmark::SnappyUncompress;
} else if (name == Slice("zstdcomp")) {
method = &Benchmark::ZstdCompress;
} else if (name == Slice("zstduncomp")) {
method = &Benchmark::ZstdUncompress;
} else if (name == Slice("heapprofile")) {
HeapProfile();
} else if (name == Slice("stats")) {
PrintStats("leveldb.stats");
} else if (name == Slice("sstables")) {
PrintStats("leveldb.sstables");
} else {
if (!name.empty()) { // No error message for empty name
std::fprintf(stderr, "unknown benchmark '%s'\n",
name.ToString().c_str());
}
}
if (fresh_db) {
if (FLAGS_use_existing_db) {
std::fprintf(stdout, "%-12s : skipped (--use_existing_db is true)\n",
name.ToString().c_str());
method = nullptr;
} else {
delete db_;
db_ = nullptr;
DestroyDB(FLAGS_db, Options());
Open();
}
}
if (method != nullptr) {
RunBenchmark(num_threads, name, method);
}
}
}
private:
struct ThreadArg {
Benchmark* bm;
SharedState* shared;
ThreadState* thread;
void (Benchmark::*method)(ThreadState*);
};
static void ThreadBody(void* v) {
ThreadArg* arg = reinterpret_cast<ThreadArg*>(v);
SharedState* shared = arg->shared;
ThreadState* thread = arg->thread;
{
MutexLock l(&shared->mu);
shared->num_initialized++;
if (shared->num_initialized >= shared->total) {
shared->cv.SignalAll();
}
while (!shared->start) {
shared->cv.Wait();
}
}
thread->stats.Start();
(arg->bm->*(arg->method))(thread);
thread->stats.Stop();
{
MutexLock l(&shared->mu);
shared->num_done++;
if (shared->num_done >= shared->total) {
shared->cv.SignalAll();
}
}
}
void RunBenchmark(int n, Slice name,
void (Benchmark::*method)(ThreadState*)) {
SharedState shared(n);
ThreadArg* arg = new ThreadArg[n];
for (int i = 0; i < n; i++) {
arg[i].bm = this;
arg[i].method = method;
arg[i].shared = &shared;
++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]);
}
shared.mu.Lock();
while (shared.num_initialized < n) {
shared.cv.Wait();
}
shared.start = true;
shared.cv.SignalAll();
while (shared.num_done < n) {
shared.cv.Wait();
}
shared.mu.Unlock();
for (int i = 1; i < n; i++) {
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;
}
delete[] arg;
}
void Crc32c(ThreadState* thread) {
// Checksum about 500MB of data total
const int size = 4096;
const char* label = "(4K per op)";
std::string data(size, 'x');
int64_t bytes = 0;
uint32_t crc = 0;
while (bytes < 500 * 1048576) {
crc = crc32c::Value(data.data(), size);
thread->stats.FinishedSingleOp();
bytes += size;
}
// Print so result is not dead
std::fprintf(stderr, "... crc=0x%x\r", static_cast<unsigned int>(crc));
thread->stats.AddBytes(bytes);
thread->stats.AddMessage(label);
}
void SnappyCompress(ThreadState* thread) {
Compress(thread, "snappy", &port::Snappy_Compress);
}
void SnappyUncompress(ThreadState* thread) {
Uncompress(thread, "snappy", &port::Snappy_Compress,
&port::Snappy_Uncompress);
}
void ZstdCompress(ThreadState* thread) {
Compress(thread, "zstd",
[](const char* input, size_t length, std::string* output) {
return port::Zstd_Compress(FLAGS_zstd_compression_level, input,
length, output);
});
}
void ZstdUncompress(ThreadState* thread) {
Uncompress(
thread, "zstd",
[](const char* input, size_t length, std::string* output) {
return port::Zstd_Compress(FLAGS_zstd_compression_level, input,
length, output);
},
&port::Zstd_Uncompress);
}
void Open() {
assert(db_ == nullptr);
Options options;
options.env = g_env;
options.create_if_missing = !FLAGS_use_existing_db;
options.block_cache = cache_;
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;
options.compression =
FLAGS_compression ? kSnappyCompression : kNoCompression;
Status s = DB::Open(options, FLAGS_db, &db_);
if (!s.ok()) {
std::fprintf(stderr, "open error: %s\n", s.ToString().c_str());
std::exit(1);
}
}
void OpenBench(ThreadState* thread) {
for (int i = 0; i < num_; i++) {
delete db_;
Open();
thread->stats.FinishedSingleOp();
}
}
void WriteSeq(ThreadState* thread) { DoWrite(thread, true); }
void WriteRandom(ThreadState* thread) { DoWrite(thread, false); }
void DoWrite(ThreadState* thread, bool seq) {
if (num_ != FLAGS_num) {
char msg[100];
std::snprintf(msg, sizeof(msg), "(%d ops)", num_);
thread->stats.AddMessage(msg);
}
RandomGenerator gen;
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.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()) {
std::fprintf(stderr, "put error: %s\n", s.ToString().c_str());
std::exit(1);
}
}
thread->stats.AddBytes(bytes);
}
void ReadSequential(ThreadState* thread) {
Iterator* iter = db_->NewIterator(ReadOptions());
int i = 0;
int64_t bytes = 0;
for (iter->SeekToFirst(); i < reads_ && iter->Valid(); iter->Next()) {
bytes += iter->key().size() + iter->value().size();
thread->stats.FinishedSingleOp();
++i;
}
delete iter;
thread->stats.AddBytes(bytes);
}
void ReadReverse(ThreadState* thread) {
Iterator* iter = db_->NewIterator(ReadOptions());
int i = 0;
int64_t bytes = 0;
for (iter->SeekToLast(); i < reads_ && iter->Valid(); iter->Prev()) {
bytes += iter->key().size() + iter->value().size();
thread->stats.FinishedSingleOp();
++i;
}
delete iter;
thread->stats.AddBytes(bytes);
}
void ReadRandom(ThreadState* thread) {
ReadOptions options;
std::string value;
int found = 0;
KeyBuffer key;
for (int i = 0; i < reads_; i++) {
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];
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++) {
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();
}
}
void ReadHot(ThreadState* thread) {
ReadOptions options;
std::string value;
const int range = (FLAGS_num + 99) / 100;
KeyBuffer key;
for (int i = 0; i < reads_; i++) {
const int k = thread->rand.Uniform(range);
key.Set(k);
db_->Get(options, key.slice(), &value);
thread->stats.FinishedSingleOp();
}
}
void SeekRandom(ThreadState* thread) {
ReadOptions options;
int found = 0;
KeyBuffer key;
for (int i = 0; i < reads_; i++) {
Iterator* iter = db_->NewIterator(options);
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();
}
char msg[100];
snprintf(msg, sizeof(msg), "(%d of %d found)", found, num_);
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.Uniform(FLAGS_num));
key.Set(k);
batch.Delete(key.slice());
thread->stats.FinishedSingleOp();
}
s = db_->Write(write_options_, &batch);
if (!s.ok()) {
std::fprintf(stderr, "del error: %s\n", s.ToString().c_str());
std::exit(1);
}
}
}
void DeleteSeq(ThreadState* thread) { DoDelete(thread, true); }
void DeleteRandom(ThreadState* thread) { DoDelete(thread, false); }
void ReadWhileWriting(ThreadState* thread) {
if (thread->tid > 0) {
ReadRandom(thread);
} else {
// Special thread that keeps writing until other threads are done.
RandomGenerator gen;
KeyBuffer key;
while (true) {
{
MutexLock l(&thread->shared->mu);
if (thread->shared->num_done + 1 >= thread->shared->num_initialized) {
// Other threads have finished
break;
}
}
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()) {
std::fprintf(stderr, "put error: %s\n", s.ToString().c_str());
std::exit(1);
}
}
// Do not count any of the preceding work/delay in stats.
thread->stats.Start();
}
}
void Compact(ThreadState* thread) { db_->CompactRange(nullptr, nullptr); }
void PrintStats(const char* key) {
std::string stats;
if (!db_->GetProperty(key, &stats)) {
stats = "(failed)";
}
std::fprintf(stdout, "\n%s\n", stats.c_str());
}
static void WriteToFile(void* arg, const char* buf, int n) {
reinterpret_cast<WritableFile*>(arg)->Append(Slice(buf, n));
}
void HeapProfile() {
char fname[100];
std::snprintf(fname, sizeof(fname), "%s/heap-%04d", FLAGS_db,
++heap_counter_);
WritableFile* file;
Status s = g_env->NewWritableFile(fname, &file);
if (!s.ok()) {
std::fprintf(stderr, "%s\n", s.ToString().c_str());
return;
}
bool ok = port::GetHeapProfile(WriteToFile, file);
delete file;
if (!ok) {
std::fprintf(stderr, "heap profiling not supported\n");
g_env->RemoveFile(fname);
}
}
};
} // namespace leveldb
int main(int argc, char** argv) {
FLAGS_write_buffer_size = leveldb::Options().write_buffer_size;
FLAGS_max_file_size = leveldb::Options().max_file_size;
FLAGS_block_size = leveldb::Options().block_size;
FLAGS_open_files = leveldb::Options().max_open_files;
std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
int n;
char junk;
if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
} else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
FLAGS_compression_ratio = d;
} 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;
} else if (sscanf(argv[i], "--reuse_logs=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_reuse_logs = n;
} else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_compression = 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) {
FLAGS_reads = n;
} else if (sscanf(argv[i], "--threads=%d%c", &n, &junk) == 1) {
FLAGS_threads = n;
} else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
FLAGS_value_size = n;
} else if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) {
FLAGS_write_buffer_size = n;
} else if (sscanf(argv[i], "--max_file_size=%d%c", &n, &junk) == 1) {
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) {
FLAGS_bloom_bits = n;
} else if (sscanf(argv[i], "--open_files=%d%c", &n, &junk) == 1) {
FLAGS_open_files = n;
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
std::exit(1);
}
}
leveldb::g_env = leveldb::Env::Default();
// Choose a location for the test database if none given with --db=<path>
if (FLAGS_db == nullptr) {
leveldb::g_env->GetTestDirectory(&default_db_path);
default_db_path += "/dbbench";
FLAGS_db = default_db_path.c_str();
}
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
}
================================================
FILE: benchmarks/db_bench_log.cc
================================================
// 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 <cinttypes>
#include <cstdio>
#include <string>
#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();
================================================
FILE: benchmarks/db_bench_sqlite3.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <sqlite3.h>
#include <cstdio>
#include <cstdlib>
#include "util/histogram.h"
#include "util/random.h"
#include "util/testutil.h"
// Comma-separated list of operations to run in the specified order
// Actual benchmarks:
//
// fillseq -- write N values in sequential key order in async mode
// fillseqsync -- write N/100 values in sequential key order in sync mode
// fillseqbatch -- batch write N values in sequential key order in async mode
// fillrandom -- write N values in random key order in async mode
// fillrandsync -- write N/100 values in random key order in sync mode
// fillrandbatch -- batch write N values in sequential key order in async mode
// overwrite -- overwrite N values in random key order in async mode
// fillrand100K -- write N/1000 100K values in random order in async mode
// fillseq100K -- write N/1000 100K values in sequential order in async mode
// readseq -- read N times sequentially
// readrandom -- read N times in random order
// readrand100K -- read N/1000 100K values in sequential order in async mode
static const char* FLAGS_benchmarks =
"fillseq,"
"fillseqsync,"
"fillseqbatch,"
"fillrandom,"
"fillrandsync,"
"fillrandbatch,"
"overwrite,"
"overwritebatch,"
"readrandom,"
"readseq,"
"fillrand100K,"
"fillseq100K,"
"readseq,"
"readrand100K,";
// Number of key/values to place in database
static int FLAGS_num = 1000000;
// Number of read operations to do. If negative, do FLAGS_num reads.
static int FLAGS_reads = -1;
// Size of each value
static int FLAGS_value_size = 100;
// Print histogram of operation timings
static bool FLAGS_histogram = false;
// Arrange to generate values that shrink to this fraction of
// their original size after compression
static double FLAGS_compression_ratio = 0.5;
// Page size. Default 1 KB.
static int FLAGS_page_size = 1024;
// Number of pages.
// Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB.
static int FLAGS_num_pages = 4096;
// 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.
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;
// If true, we enable Write-Ahead Logging
static bool FLAGS_WAL_enabled = true;
// Use the db with the following name.
static const char* FLAGS_db = nullptr;
inline static void ExecErrorCheck(int status, char* err_msg) {
if (status != SQLITE_OK) {
std::fprintf(stderr, "SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
std::exit(1);
}
}
inline static void StepErrorCheck(int status) {
if (status != SQLITE_DONE) {
std::fprintf(stderr, "SQL step error: status = %d\n", status);
std::exit(1);
}
}
inline static void ErrorCheck(int status) {
if (status != SQLITE_OK) {
std::fprintf(stderr, "sqlite3 error: status = %d\n", status);
std::exit(1);
}
}
inline static void WalCheckpoint(sqlite3* db_) {
// Flush all writes to disk
if (FLAGS_WAL_enabled) {
sqlite3_wal_checkpoint_v2(db_, nullptr, SQLITE_CHECKPOINT_FULL, nullptr,
nullptr);
}
}
namespace leveldb {
// Helper for quickly generating random data.
namespace {
class RandomGenerator {
private:
std::string data_;
int pos_;
public:
RandomGenerator() {
// We use a limited amount of data over and over again and ensure
// that it is larger than the compression window (32KB), and also
// large enough to serve all typical value sizes we want to write.
Random rnd(301);
std::string piece;
while (data_.size() < 1048576) {
// Add a short fragment that is as compressible as specified
// by FLAGS_compression_ratio.
test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
data_.append(piece);
}
pos_ = 0;
}
Slice Generate(int len) {
if (pos_ + len > data_.size()) {
pos_ = 0;
assert(len < data_.size());
}
pos_ += len;
return Slice(data_.data() + pos_ - len, len);
}
};
static Slice TrimSpace(Slice s) {
int start = 0;
while (start < s.size() && isspace(s[start])) {
start++;
}
int limit = s.size();
while (limit > start && isspace(s[limit - 1])) {
limit--;
}
return Slice(s.data() + start, limit - start);
}
} // namespace
class Benchmark {
private:
sqlite3* db_;
int db_num_;
int num_;
int reads_;
double start_;
double last_op_finish_;
int64_t bytes_;
std::string message_;
Histogram hist_;
RandomGenerator gen_;
Random rand_;
// State kept for progress messages
int done_;
int next_report_; // When to report next
void PrintHeader() {
const int kKeySize = 16;
PrintEnvironment();
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<int64_t>(kKeySize + FLAGS_value_size) * num_) /
1048576.0));
PrintWarnings();
std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
std::fprintf(
stdout,
"WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
}
void PrintEnvironment() {
std::fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION);
#if defined(__linux)
time_t now = time(nullptr);
std::fprintf(stderr, "Date: %s",
ctime(&now)); // ctime() adds newline
FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
std::string cpu_type;
std::string cache_size;
while (fgets(line, sizeof(line), cpuinfo) != nullptr) {
const char* sep = strchr(line, ':');
if (sep == nullptr) {
continue;
}
Slice key = TrimSpace(Slice(line, sep - 1 - line));
Slice val = TrimSpace(Slice(sep + 1));
if (key == "model name") {
++num_cpus;
cpu_type = val.ToString();
} else if (key == "cache size") {
cache_size = val.ToString();
}
}
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
}
void Start() {
start_ = Env::Default()->NowMicros() * 1e-6;
bytes_ = 0;
message_.clear();
last_op_finish_ = start_;
hist_.Clear();
done_ = 0;
next_report_ = 100;
}
void FinishedSingleOp() {
if (FLAGS_histogram) {
double now = Env::Default()->NowMicros() * 1e-6;
double micros = (now - last_op_finish_) * 1e6;
hist_.Add(micros);
if (micros > 20000) {
std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
std::fflush(stderr);
}
last_op_finish_ = now;
}
done_++;
if (done_ >= next_report_) {
if (next_report_ < 1000)
next_report_ += 100;
else if (next_report_ < 5000)
next_report_ += 500;
else if (next_report_ < 10000)
next_report_ += 1000;
else if (next_report_ < 50000)
next_report_ += 5000;
else if (next_report_ < 100000)
next_report_ += 10000;
else if (next_report_ < 500000)
next_report_ += 50000;
else
next_report_ += 100000;
std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
std::fflush(stderr);
}
}
void Stop(const Slice& name) {
double finish = Env::Default()->NowMicros() * 1e-6;
// Pretend at least one op was done in case we are running a benchmark
// that does not call FinishedSingleOp().
if (done_ < 1) done_ = 1;
if (bytes_ > 0) {
char rate[100];
std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
(bytes_ / 1048576.0) / (finish - start_));
if (!message_.empty()) {
message_ = std::string(rate) + " " + message_;
} else {
message_ = rate;
}
}
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) {
std::fprintf(stdout, "Microseconds per op:\n%s\n",
hist_.ToString().c_str());
}
std::fflush(stdout);
}
public:
enum Order { SEQUENTIAL, RANDOM };
enum DBState { FRESH, EXISTING };
Benchmark()
: db_(nullptr),
db_num_(0),
num_(FLAGS_num),
reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
bytes_(0),
rand_(301) {
std::vector<std::string> files;
std::string test_dir;
Env::Default()->GetTestDirectory(&test_dir);
Env::Default()->GetChildren(test_dir, &files);
if (!FLAGS_use_existing_db) {
for (int i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("dbbench_sqlite3")) {
std::string file_name(test_dir);
file_name += "/";
file_name += files[i];
Env::Default()->RemoveFile(file_name.c_str());
}
}
}
}
~Benchmark() {
int status = sqlite3_close(db_);
ErrorCheck(status);
}
void Run() {
PrintHeader();
Open();
const char* benchmarks = FLAGS_benchmarks;
while (benchmarks != nullptr) {
const char* sep = strchr(benchmarks, ',');
Slice name;
if (sep == nullptr) {
name = benchmarks;
benchmarks = nullptr;
} else {
name = Slice(benchmarks, sep - benchmarks);
benchmarks = sep + 1;
}
bytes_ = 0;
Start();
bool known = true;
bool write_sync = false;
if (name == Slice("fillseq")) {
Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);
WalCheckpoint(db_);
} else if (name == Slice("fillseqbatch")) {
Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000);
WalCheckpoint(db_);
} else if (name == Slice("fillrandom")) {
Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);
WalCheckpoint(db_);
} else if (name == Slice("fillrandbatch")) {
Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000);
WalCheckpoint(db_);
} else if (name == Slice("overwrite")) {
Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1);
WalCheckpoint(db_);
} else if (name == Slice("overwritebatch")) {
Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000);
WalCheckpoint(db_);
} else if (name == Slice("fillrandsync")) {
write_sync = true;
Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1);
WalCheckpoint(db_);
} else if (name == Slice("fillseqsync")) {
write_sync = true;
Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1);
WalCheckpoint(db_);
} else if (name == Slice("fillrand100K")) {
Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1);
WalCheckpoint(db_);
} else if (name == Slice("fillseq100K")) {
Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1);
WalCheckpoint(db_);
} else if (name == Slice("readseq")) {
ReadSequential();
} else if (name == Slice("readrandom")) {
Read(RANDOM, 1);
} else if (name == Slice("readrand100K")) {
int n = reads_;
reads_ /= 1000;
Read(RANDOM, 1);
reads_ = n;
} else {
known = false;
if (name != Slice()) { // No error message for empty name
std::fprintf(stderr, "unknown benchmark '%s'\n",
name.ToString().c_str());
}
}
if (known) {
Stop(name);
}
}
}
void Open() {
assert(db_ == nullptr);
int status;
char file_name[100];
char* err_msg = nullptr;
db_num_++;
// Open database
std::string tmp_dir;
Env::Default()->GetTestDirectory(&tmp_dir);
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) {
std::fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_));
std::exit(1);
}
// Change SQLite cache size
char cache_size[100];
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];
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);
}
// Change journal mode to WAL if WAL enabled flag is on
if (FLAGS_WAL_enabled) {
std::string WAL_stmt = "PRAGMA journal_mode = WAL";
// LevelDB's default cache size is a combined 4 MB
std::string WAL_checkpoint = "PRAGMA wal_autocheckpoint = 4096";
status = sqlite3_exec(db_, WAL_stmt.c_str(), nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
status =
sqlite3_exec(db_, WAL_checkpoint.c_str(), nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
}
// Change locking mode to exclusive and create tables/index for database
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++) {
status =
sqlite3_exec(db_, stmt_array[i].c_str(), nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
}
}
void Write(bool write_sync, Order order, DBState state, int num_entries,
int value_size, int entries_per_batch) {
// Create new database if state == FRESH
if (state == FRESH) {
if (FLAGS_use_existing_db) {
message_ = "skipping (--use_existing_db is true)";
return;
}
sqlite3_close(db_);
db_ = nullptr;
Open();
Start();
}
if (num_entries != num_) {
char msg[100];
std::snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
message_ = msg;
}
char* err_msg = nullptr;
int status;
sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt;
std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)";
std::string begin_trans_str = "BEGIN TRANSACTION;";
std::string end_trans_str = "END TRANSACTION;";
// Check for synchronous flag in options
std::string sync_stmt =
(write_sync) ? "PRAGMA synchronous = FULL" : "PRAGMA synchronous = OFF";
status = sqlite3_exec(db_, sync_stmt.c_str(), nullptr, nullptr, &err_msg);
ExecErrorCheck(status, err_msg);
// Preparing sqlite3 statements
status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1, &replace_stmt,
nullptr);
ErrorCheck(status);
status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,
&begin_trans_stmt, nullptr);
ErrorCheck(status);
status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, &end_trans_stmt,
nullptr);
ErrorCheck(status);
bool transaction = (entries_per_batch > 1);
for (int i = 0; i < num_entries; i += entries_per_batch) {
// Begin write transaction
if (FLAGS_transaction && transaction) {
status = sqlite3_step(begin_trans_stmt);
StepErrorCheck(status);
status = sqlite3_reset(begin_trans_stmt);
ErrorCheck(status);
}
// Create and execute SQL statements
for (int j = 0; j < entries_per_batch; j++) {
const char* value = gen_.Generate(value_size).data();
// Create values for key-value pair
const int k =
(order == SEQUENTIAL) ? i + j : (rand_.Next() % num_entries);
char key[100];
std::snprintf(key, sizeof(key), "%016d", k);
// Bind KV values into replace_stmt
status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC);
ErrorCheck(status);
status = sqlite3_bind_blob(replace_stmt, 2, value, value_size,
SQLITE_STATIC);
ErrorCheck(status);
// Execute replace_stmt
bytes_ += value_size + strlen(key);
status = sqlite3_step(replace_stmt);
StepErrorCheck(status);
// Reset SQLite statement for another use
status = sqlite3_clear_bindings(replace_stmt);
ErrorCheck(status);
status = sqlite3_reset(replace_stmt);
ErrorCheck(status);
FinishedSingleOp();
}
// End write transaction
if (FLAGS_transaction && transaction) {
status = sqlite3_step(end_trans_stmt);
StepErrorCheck(status);
status = sqlite3_reset(end_trans_stmt);
ErrorCheck(status);
}
}
status = sqlite3_finalize(replace_stmt);
ErrorCheck(status);
status = sqlite3_finalize(begin_trans_stmt);
ErrorCheck(status);
status = sqlite3_finalize(end_trans_stmt);
ErrorCheck(status);
}
void Read(Order order, int entries_per_batch) {
int status;
sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt;
std::string read_str = "SELECT * FROM test WHERE key = ?";
std::string begin_trans_str = "BEGIN TRANSACTION;";
std::string end_trans_str = "END TRANSACTION;";
// Preparing sqlite3 statements
status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,
&begin_trans_stmt, nullptr);
ErrorCheck(status);
status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1, &end_trans_stmt,
nullptr);
ErrorCheck(status);
status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, nullptr);
ErrorCheck(status);
bool transaction = (entries_per_batch > 1);
for (int i = 0; i < reads_; i += entries_per_batch) {
// Begin read transaction
if (FLAGS_transaction && transaction) {
status = sqlite3_step(begin_trans_stmt);
StepErrorCheck(status);
status = sqlite3_reset(begin_trans_stmt);
ErrorCheck(status);
}
// Create and execute SQL statements
for (int j = 0; j < entries_per_batch; j++) {
// Create key value
char key[100];
int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_);
std::snprintf(key, sizeof(key), "%016d", k);
// Bind key value into read_stmt
status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC);
ErrorCheck(status);
// Execute read statement
while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW) {
}
StepErrorCheck(status);
// Reset SQLite statement for another use
status = sqlite3_clear_bindings(read_stmt);
ErrorCheck(status);
status = sqlite3_reset(read_stmt);
ErrorCheck(status);
FinishedSingleOp();
}
// End read transaction
if (FLAGS_transaction && transaction) {
status = sqlite3_step(end_trans_stmt);
StepErrorCheck(status);
status = sqlite3_reset(end_trans_stmt);
ErrorCheck(status);
}
}
status = sqlite3_finalize(read_stmt);
ErrorCheck(status);
status = sqlite3_finalize(begin_trans_stmt);
ErrorCheck(status);
status = sqlite3_finalize(end_trans_stmt);
ErrorCheck(status);
}
void ReadSequential() {
int status;
sqlite3_stmt* pStmt;
std::string read_str = "SELECT * FROM test ORDER BY key";
status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &pStmt, nullptr);
ErrorCheck(status);
for (int i = 0; i < reads_ && SQLITE_ROW == sqlite3_step(pStmt); i++) {
bytes_ += sqlite3_column_bytes(pStmt, 1) + sqlite3_column_bytes(pStmt, 2);
FinishedSingleOp();
}
status = sqlite3_finalize(pStmt);
ErrorCheck(status);
}
};
} // namespace leveldb
int main(int argc, char** argv) {
std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
int n;
char junk;
if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
} else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_histogram = n;
} else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
FLAGS_compression_ratio = d;
} 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) {
FLAGS_reads = n;
} else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
FLAGS_value_size = n;
} else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) {
FLAGS_transaction = false;
} else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) {
FLAGS_page_size = n;
} else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) {
FLAGS_num_pages = n;
} else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_WAL_enabled = n;
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
std::exit(1);
}
}
// Choose a location for the test database if none given with --db=<path>
if (FLAGS_db == nullptr) {
leveldb::Env::Default()->GetTestDirectory(&default_db_path);
default_db_path += "/dbbench";
FLAGS_db = default_db_path.c_str();
}
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
}
================================================
FILE: benchmarks/db_bench_tree_db.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <kcpolydb.h>
#include <cstdio>
#include <cstdlib>
#include "util/histogram.h"
#include "util/random.h"
#include "util/testutil.h"
// Comma-separated list of operations to run in the specified order
// Actual benchmarks:
//
// fillseq -- write N values in sequential key order in async mode
// fillrandom -- write N values in random key order in async mode
// overwrite -- overwrite N values in random key order in async mode
// fillseqsync -- write N/100 values in sequential key order in sync mode
// fillrandsync -- write N/100 values in random key order in sync mode
// fillrand100K -- write N/1000 100K values in random order in async mode
// fillseq100K -- write N/1000 100K values in seq order in async mode
// readseq -- read N times sequentially
// readseq100K -- read N/1000 100K values in sequential order in async mode
// readrand100K -- read N/1000 100K values in sequential order in async mode
// readrandom -- read N times in random order
static const char* FLAGS_benchmarks =
"fillseq,"
"fillseqsync,"
"fillrandsync,"
"fillrandom,"
"overwrite,"
"readrandom,"
"readseq,"
"fillrand100K,"
"fillseq100K,"
"readseq100K,"
"readrand100K,";
// Number of key/values to place in database
static int FLAGS_num = 1000000;
// Number of read operations to do. If negative, do FLAGS_num reads.
static int FLAGS_reads = -1;
// Size of each value
static int FLAGS_value_size = 100;
// Arrange to generate values that shrink to this fraction of
// their original size after compression
static double FLAGS_compression_ratio = 0.5;
// Print histogram of operation timings
static bool FLAGS_histogram = false;
// Cache size. Default 4 MB
static int FLAGS_cache_size = 4194304;
// Page size. Default 1 KB
static int FLAGS_page_size = 1024;
// 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.
static bool FLAGS_use_existing_db = false;
// Compression flag. If true, compression is on. If false, compression
// is off.
static bool FLAGS_compression = true;
// Use the db with the following name.
static const char* FLAGS_db = nullptr;
inline static void DBSynchronize(kyotocabinet::TreeDB* db_) {
// Synchronize will flush writes to disk
if (!db_->synchronize()) {
std::fprintf(stderr, "synchronize error: %s\n", db_->error().name());
}
}
namespace leveldb {
// Helper for quickly generating random data.
namespace {
class RandomGenerator {
private:
std::string data_;
int pos_;
public:
RandomGenerator() {
// We use a limited amount of data over and over again and ensure
// that it is larger than the compression window (32KB), and also
// large enough to serve all typical value sizes we want to write.
Random rnd(301);
std::string piece;
while (data_.size() < 1048576) {
// Add a short fragment that is as compressible as specified
// by FLAGS_compression_ratio.
test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
data_.append(piece);
}
pos_ = 0;
}
Slice Generate(int len) {
if (pos_ + len > data_.size()) {
pos_ = 0;
assert(len < data_.size());
}
pos_ += len;
return Slice(data_.data() + pos_ - len, len);
}
};
static Slice TrimSpace(Slice s) {
int start = 0;
while (start < s.size() && isspace(s[start])) {
start++;
}
int limit = s.size();
while (limit > start && isspace(s[limit - 1])) {
limit--;
}
return Slice(s.data() + start, limit - start);
}
} // namespace
class Benchmark {
private:
kyotocabinet::TreeDB* db_;
int db_num_;
int num_;
int reads_;
double start_;
double last_op_finish_;
int64_t bytes_;
std::string message_;
Histogram hist_;
RandomGenerator gen_;
Random rand_;
kyotocabinet::LZOCompressor<kyotocabinet::LZO::RAW> comp_;
// State kept for progress messages
int done_;
int next_report_; // When to report next
void PrintHeader() {
const int kKeySize = 16;
PrintEnvironment();
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<int>(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<int64_t>(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();
std::fprintf(stdout, "------------------------------------------------\n");
}
void PrintWarnings() {
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
std::fprintf(
stdout,
"WARNING: Optimization is disabled: benchmarks unnecessarily slow\n");
#endif
#ifndef NDEBUG
std::fprintf(
stdout,
"WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
#endif
}
void PrintEnvironment() {
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);
std::fprintf(stderr, "Date: %s",
ctime(&now)); // ctime() adds newline
FILE* cpuinfo = std::fopen("/proc/cpuinfo", "r");
if (cpuinfo != nullptr) {
char line[1000];
int num_cpus = 0;
std::string cpu_type;
std::string cache_size;
while (fgets(line, sizeof(line), cpuinfo) != nullptr) {
const char* sep = strchr(line, ':');
if (sep == nullptr) {
continue;
}
Slice key = TrimSpace(Slice(line, sep - 1 - line));
Slice val = TrimSpace(Slice(sep + 1));
if (key == "model name") {
++num_cpus;
cpu_type = val.ToString();
} else if (key == "cache size") {
cache_size = val.ToString();
}
}
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
}
void Start() {
start_ = Env::Default()->NowMicros() * 1e-6;
bytes_ = 0;
message_.clear();
last_op_finish_ = start_;
hist_.Clear();
done_ = 0;
next_report_ = 100;
}
void FinishedSingleOp() {
if (FLAGS_histogram) {
double now = Env::Default()->NowMicros() * 1e-6;
double micros = (now - last_op_finish_) * 1e6;
hist_.Add(micros);
if (micros > 20000) {
std::fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
std::fflush(stderr);
}
last_op_finish_ = now;
}
done_++;
if (done_ >= next_report_) {
if (next_report_ < 1000)
next_report_ += 100;
else if (next_report_ < 5000)
next_report_ += 500;
else if (next_report_ < 10000)
next_report_ += 1000;
else if (next_report_ < 50000)
next_report_ += 5000;
else if (next_report_ < 100000)
next_report_ += 10000;
else if (next_report_ < 500000)
next_report_ += 50000;
else
next_report_ += 100000;
std::fprintf(stderr, "... finished %d ops%30s\r", done_, "");
std::fflush(stderr);
}
}
void Stop(const Slice& name) {
double finish = Env::Default()->NowMicros() * 1e-6;
// Pretend at least one op was done in case we are running a benchmark
// that does not call FinishedSingleOp().
if (done_ < 1) done_ = 1;
if (bytes_ > 0) {
char rate[100];
std::snprintf(rate, sizeof(rate), "%6.1f MB/s",
(bytes_ / 1048576.0) / (finish - start_));
if (!message_.empty()) {
message_ = std::string(rate) + " " + message_;
} else {
message_ = rate;
}
}
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) {
std::fprintf(stdout, "Microseconds per op:\n%s\n",
hist_.ToString().c_str());
}
std::fflush(stdout);
}
public:
enum Order { SEQUENTIAL, RANDOM };
enum DBState { FRESH, EXISTING };
Benchmark()
: db_(nullptr),
num_(FLAGS_num),
reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
bytes_(0),
rand_(301) {
std::vector<std::string> files;
std::string test_dir;
Env::Default()->GetTestDirectory(&test_dir);
Env::Default()->GetChildren(test_dir.c_str(), &files);
if (!FLAGS_use_existing_db) {
for (int i = 0; i < files.size(); i++) {
if (Slice(files[i]).starts_with("dbbench_polyDB")) {
std::string file_name(test_dir);
file_name += "/";
file_name += files[i];
Env::Default()->RemoveFile(file_name.c_str());
}
}
}
}
~Benchmark() {
if (!db_->close()) {
std::fprintf(stderr, "close error: %s\n", db_->error().name());
}
}
void Run() {
PrintHeader();
Open(false);
const char* benchmarks = FLAGS_benchmarks;
while (benchmarks != nullptr) {
const char* sep = strchr(benchmarks, ',');
Slice name;
if (sep == nullptr) {
name = benchmarks;
benchmarks = nullptr;
} else {
name = Slice(benchmarks, sep - benchmarks);
benchmarks = sep + 1;
}
Start();
bool known = true;
bool write_sync = false;
if (name == Slice("fillseq")) {
Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);
DBSynchronize(db_);
} else if (name == Slice("fillrandom")) {
Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);
DBSynchronize(db_);
} else if (name == Slice("overwrite")) {
Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1);
DBSynchronize(db_);
} else if (name == Slice("fillrandsync")) {
write_sync = true;
Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1);
DBSynchronize(db_);
} else if (name == Slice("fillseqsync")) {
write_sync = true;
Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1);
DBSynchronize(db_);
} else if (name == Slice("fillrand100K")) {
Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1);
DBSynchronize(db_);
} else if (name == Slice("fillseq100K")) {
Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1);
DBSynchronize(db_);
} else if (name == Slice("readseq")) {
ReadSequential();
} else if (name == Slice("readrandom")) {
ReadRandom();
} else if (name == Slice("readrand100K")) {
int n = reads_;
reads_ /= 1000;
ReadRandom();
reads_ = n;
} else if (name == Slice("readseq100K")) {
int n = reads_;
reads_ /= 1000;
ReadSequential();
reads_ = n;
} else {
known = false;
if (name != Slice()) { // No error message for empty name
std::fprintf(stderr, "unknown benchmark '%s'\n",
name.ToString().c_str());
}
}
if (known) {
Stop(name);
}
}
}
private:
void Open(bool sync) {
assert(db_ == nullptr);
// Initialize db_
db_ = new kyotocabinet::TreeDB();
char file_name[100];
db_num_++;
std::string test_dir;
Env::Default()->GetTestDirectory(&test_dir);
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 =
kyotocabinet::PolyDB::OWRITER | kyotocabinet::PolyDB::OCREATE;
int tune_options =
kyotocabinet::TreeDB::TSMALL | kyotocabinet::TreeDB::TLINEAR;
if (FLAGS_compression) {
tune_options |= kyotocabinet::TreeDB::TCOMPRESS;
db_->tune_compressor(&comp_);
}
db_->tune_options(tune_options);
db_->tune_page_cache(FLAGS_cache_size);
db_->tune_page(FLAGS_page_size);
db_->tune_map(256LL << 20);
if (sync) {
open_options |= kyotocabinet::PolyDB::OAUTOSYNC;
}
if (!db_->open(file_name, open_options)) {
std::fprintf(stderr, "open error: %s\n", db_->error().name());
}
}
void Write(bool sync, Order order, DBState state, int num_entries,
int value_size, int entries_per_batch) {
// Create new database if state == FRESH
if (state == FRESH) {
if (FLAGS_use_existing_db) {
message_ = "skipping (--use_existing_db is true)";
return;
}
delete db_;
db_ = nullptr;
Open(sync);
Start(); // Do not count time taken to destroy/open
}
if (num_entries != num_) {
char msg[100];
std::snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
message_ = msg;
}
// Write to database
for (int i = 0; i < num_entries; i++) {
const int k = (order == SEQUENTIAL) ? i : (rand_.Next() % num_entries);
char key[100];
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())) {
std::fprintf(stderr, "set error: %s\n", db_->error().name());
}
FinishedSingleOp();
}
}
void ReadSequential() {
kyotocabinet::DB::Cursor* cur = db_->cursor();
cur->jump();
std::string ckey, cvalue;
while (cur->get(&ckey, &cvalue, true)) {
bytes_ += ckey.size() + cvalue.size();
FinishedSingleOp();
}
delete cur;
}
void ReadRandom() {
std::string value;
for (int i = 0; i < reads_; i++) {
char key[100];
const int k = rand_.Next() % reads_;
std::snprintf(key, sizeof(key), "%016d", k);
db_->get(key, &value);
FinishedSingleOp();
}
}
};
} // namespace leveldb
int main(int argc, char** argv) {
std::string default_db_path;
for (int i = 1; i < argc; i++) {
double d;
int n;
char junk;
if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
} else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
FLAGS_compression_ratio = d;
} else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_histogram = 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) {
FLAGS_reads = n;
} else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
FLAGS_value_size = n;
} else if (sscanf(argv[i], "--cache_size=%d%c", &n, &junk) == 1) {
FLAGS_cache_size = n;
} else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) {
FLAGS_page_size = n;
} else if (sscanf(argv[i], "--compression=%d%c", &n, &junk) == 1 &&
(n == 0 || n == 1)) {
FLAGS_compression = (n == 1) ? true : false;
} else if (strncmp(argv[i], "--db=", 5) == 0) {
FLAGS_db = argv[i] + 5;
} else {
std::fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
std::exit(1);
}
}
// Choose a location for the test database if none given with --db=<path>
if (FLAGS_db == nullptr) {
leveldb::Env::Default()->GetTestDirectory(&default_db_path);
default_db_path += "/dbbench";
FLAGS_db = default_db_path.c_str();
}
leveldb::Benchmark benchmark;
benchmark.Run();
return 0;
}
================================================
FILE: cmake/leveldbConfig.cmake.in
================================================
# 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)
================================================
FILE: db/autocompact_test.cc
================================================
// Copyright (c) 2013 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 "gtest/gtest.h"
#include "db/db_impl.h"
#include "leveldb/cache.h"
#include "leveldb/db.h"
#include "util/testutil.h"
namespace leveldb {
class AutoCompactTest : public testing::Test {
public:
AutoCompactTest() {
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;
EXPECT_LEVELDB_OK(DB::Open(options_, dbname_, &db_));
}
~AutoCompactTest() {
delete db_;
DestroyDB(dbname_, Options());
delete tiny_cache_;
}
std::string Key(int i) {
char buf[100];
std::snprintf(buf, sizeof(buf), "key%06d", i);
return std::string(buf);
}
uint64_t Size(const Slice& start, const Slice& limit) {
Range r(start, limit);
uint64_t size;
db_->GetApproximateSizes(&r, 1, &size);
return size;
}
void DoReads(int n);
private:
std::string dbname_;
Cache* tiny_cache_;
Options options_;
DB* db_;
};
static const int kValueSize = 200 * 1024;
static const int kTotalSize = 100 * 1024 * 1024;
static const int kCount = kTotalSize / kValueSize;
// Read through the first n keys repeatedly and check that they get
// compacted (verified by checking the size of the key space).
void AutoCompactTest::DoReads(int n) {
std::string value(kValueSize, 'x');
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
// Fill database
for (int i = 0; i < kCount; i++) {
ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), Key(i), value));
}
ASSERT_LEVELDB_OK(dbi->TEST_CompactMemTable());
// Delete everything
for (int i = 0; i < kCount; i++) {
ASSERT_LEVELDB_OK(db_->Delete(WriteOptions(), Key(i)));
}
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));
const int64_t initial_other_size = Size(Key(n), Key(kCount));
// Read until size drops significantly.
std::string limit_key = Key(n);
for (int read = 0; true; read++) {
ASSERT_LT(read, 100) << "Taking too long to compact";
Iterator* iter = db_->NewIterator(ReadOptions());
for (iter->SeekToFirst();
iter->Valid() && iter->key().ToString() < limit_key; iter->Next()) {
// Drop data
}
delete iter;
// Wait a little bit to allow any triggered compactions to complete.
Env::Default()->SleepForMicroseconds(1000000);
uint64_t size = Size(Key(0), Key(n));
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;
}
}
// Verify that the size of the key space not touched by the reads
// is pretty much unchanged.
const int64_t final_other_size = Size(Key(n), Key(kCount));
ASSERT_LE(final_other_size, initial_other_size + 1048576);
ASSERT_GE(final_other_size, initial_other_size / 5 - 1048576);
}
TEST_F(AutoCompactTest, ReadAll) { DoReads(kCount); }
TEST_F(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); }
} // namespace leveldb
================================================
FILE: db/builder.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "db/builder.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include "db/table_cache.h"
#include "db/version_edit.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/iterator.h"
namespace leveldb {
Status BuildTable(const std::string& dbname, Env* env, const Options& options,
TableCache* table_cache, Iterator* iter, FileMetaData* meta) {
Status s;
meta->file_size = 0;
iter->SeekToFirst();
std::string fname = TableFileName(dbname, meta->number);
if (iter->Valid()) {
WritableFile* file;
s = env->NewWritableFile(fname, &file);
if (!s.ok()) {
return s;
}
TableBuilder* builder = new TableBuilder(options, file);
meta->smallest.DecodeFrom(iter->key());
Slice key;
for (; iter->Valid(); iter->Next()) {
key = iter->key();
builder->Add(key, iter->value());
}
if (!key.empty()) {
meta->largest.DecodeFrom(key);
}
// Finish and check for builder errors
s = builder->Finish();
if (s.ok()) {
meta->file_size = builder->FileSize();
assert(meta->file_size > 0);
}
delete builder;
// Finish and check for file errors
if (s.ok()) {
s = file->Sync();
}
if (s.ok()) {
s = file->Close();
}
delete file;
file = nullptr;
if (s.ok()) {
// Verify that the table is usable
Iterator* it = table_cache->NewIterator(ReadOptions(), meta->number,
meta->file_size);
s = it->status();
delete it;
}
}
// Check for input iterator errors
if (!iter->status().ok()) {
s = iter->status();
}
if (s.ok() && meta->file_size > 0) {
// Keep it
} else {
env->RemoveFile(fname);
}
return s;
}
} // namespace leveldb
================================================
FILE: db/builder.h
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#ifndef STORAGE_LEVELDB_DB_BUILDER_H_
#define STORAGE_LEVELDB_DB_BUILDER_H_
#include "leveldb/status.h"
namespace leveldb {
struct Options;
struct FileMetaData;
class Env;
class Iterator;
class TableCache;
class VersionEdit;
// Build a Table file from the contents of *iter. The generated file
// will be named according to meta->number. On success, the rest of
// *meta will be filled with metadata about the generated table.
// If no data is present in *iter, meta->file_size will be set to
// zero, and no Table file will be produced.
Status BuildTable(const std::string& dbname, Env* env, const Options& options,
TableCache* table_cache, Iterator* iter, FileMetaData* meta);
} // namespace leveldb
#endif // STORAGE_LEVELDB_DB_BUILDER_H_
================================================
FILE: db/c.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "leveldb/c.h"
#include <string.h>
#include <cstdint>
#include <cstdlib>
#include "leveldb/cache.h"
#include "leveldb/comparator.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/filter_policy.h"
#include "leveldb/iterator.h"
#include "leveldb/options.h"
#include "leveldb/status.h"
#include "leveldb/write_batch.h"
using leveldb::Cache;
using leveldb::Comparator;
using leveldb::CompressionType;
using leveldb::DB;
using leveldb::Env;
using leveldb::FileLock;
using leveldb::FilterPolicy;
using leveldb::Iterator;
using leveldb::kMajorVersion;
using leveldb::kMinorVersion;
using leveldb::Logger;
using leveldb::NewBloomFilterPolicy;
using leveldb::NewLRUCache;
using leveldb::Options;
using leveldb::RandomAccessFile;
using leveldb::Range;
using leveldb::ReadOptions;
using leveldb::SequentialFile;
using leveldb::Slice;
using leveldb::Snapshot;
using leveldb::Status;
using leveldb::WritableFile;
using leveldb::WriteBatch;
using leveldb::WriteOptions;
extern "C" {
struct leveldb_t {
DB* rep;
};
struct leveldb_iterator_t {
Iterator* rep;
};
struct leveldb_writebatch_t {
WriteBatch rep;
};
struct leveldb_snapshot_t {
const Snapshot* rep;
};
struct leveldb_readoptions_t {
ReadOptions rep;
};
struct leveldb_writeoptions_t {
WriteOptions rep;
};
struct leveldb_options_t {
Options rep;
};
struct leveldb_cache_t {
Cache* rep;
};
struct leveldb_seqfile_t {
SequentialFile* rep;
};
struct leveldb_randomfile_t {
RandomAccessFile* rep;
};
struct leveldb_writablefile_t {
WritableFile* rep;
};
struct leveldb_logger_t {
Logger* rep;
};
struct leveldb_filelock_t {
FileLock* rep;
};
struct leveldb_comparator_t : public Comparator {
~leveldb_comparator_t() override { (*destructor_)(state_); }
int Compare(const Slice& a, const Slice& b) const override {
return (*compare_)(state_, a.data(), a.size(), b.data(), b.size());
}
const char* Name() const override { return (*name_)(state_); }
// No-ops since the C binding does not support key shortening methods.
void FindShortestSeparator(std::string*, const Slice&) const override {}
void FindShortSuccessor(std::string* key) const override {}
void* state_;
void (*destructor_)(void*);
int (*compare_)(void*, const char* a, size_t alen, const char* b,
size_t blen);
const char* (*name_)(void*);
};
struct leveldb_filterpolicy_t : public FilterPolicy {
~leveldb_filterpolicy_t() override { (*destructor_)(state_); }
const char* Name() const override { return (*name_)(state_); }
void CreateFilter(const Slice* keys, int n, std::string* dst) const override {
std::vector<const char*> key_pointers(n);
std::vector<size_t> key_sizes(n);
for (int i = 0; i < n; i++) {
key_pointers[i] = keys[i].data();
key_sizes[i] = keys[i].size();
}
size_t len;
char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len);
dst->append(filter, len);
std::free(filter);
}
bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
return (*key_match_)(state_, key.data(), key.size(), filter.data(),
filter.size());
}
void* state_;
void (*destructor_)(void*);
const char* (*name_)(void*);
char* (*create_)(void*, const char* const* key_array,
const size_t* key_length_array, int num_keys,
size_t* filter_length);
uint8_t (*key_match_)(void*, const char* key, size_t length,
const char* filter, size_t filter_length);
};
struct leveldb_env_t {
Env* rep;
bool is_default;
};
static bool SaveError(char** errptr, const Status& s) {
assert(errptr != nullptr);
if (s.ok()) {
return false;
} else if (*errptr == nullptr) {
*errptr = strdup(s.ToString().c_str());
} else {
// TODO(sanjay): Merge with existing error?
std::free(*errptr);
*errptr = strdup(s.ToString().c_str());
}
return true;
}
static char* CopyString(const std::string& str) {
char* result =
reinterpret_cast<char*>(std::malloc(sizeof(char) * str.size()));
std::memcpy(result, str.data(), sizeof(char) * str.size());
return result;
}
leveldb_t* leveldb_open(const leveldb_options_t* options, const char* name,
char** errptr) {
DB* db;
if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) {
return nullptr;
}
leveldb_t* result = new leveldb_t;
result->rep = db;
return result;
}
void leveldb_close(leveldb_t* db) {
delete db->rep;
delete db;
}
void leveldb_put(leveldb_t* db, const leveldb_writeoptions_t* options,
const char* key, size_t keylen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr,
db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen)));
}
void leveldb_delete(leveldb_t* db, const leveldb_writeoptions_t* options,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen)));
}
void leveldb_write(leveldb_t* db, const leveldb_writeoptions_t* options,
leveldb_writebatch_t* batch, char** errptr) {
SaveError(errptr, db->rep->Write(options->rep, &batch->rep));
}
char* leveldb_get(leveldb_t* db, const leveldb_readoptions_t* options,
const char* key, size_t keylen, size_t* vallen,
char** errptr) {
char* result = nullptr;
std::string tmp;
Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp);
if (s.ok()) {
*vallen = tmp.size();
result = CopyString(tmp);
} else {
*vallen = 0;
if (!s.IsNotFound()) {
SaveError(errptr, s);
}
}
return result;
}
leveldb_iterator_t* leveldb_create_iterator(
leveldb_t* db, const leveldb_readoptions_t* options) {
leveldb_iterator_t* result = new leveldb_iterator_t;
result->rep = db->rep->NewIterator(options->rep);
return result;
}
const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db) {
leveldb_snapshot_t* result = new leveldb_snapshot_t;
result->rep = db->rep->GetSnapshot();
return result;
}
void leveldb_release_snapshot(leveldb_t* db,
const leveldb_snapshot_t* snapshot) {
db->rep->ReleaseSnapshot(snapshot->rep);
delete snapshot;
}
char* leveldb_property_value(leveldb_t* db, const char* propname) {
std::string tmp;
if (db->rep->GetProperty(Slice(propname), &tmp)) {
// We use strdup() since we expect human readable output.
return strdup(tmp.c_str());
} else {
return nullptr;
}
}
void leveldb_approximate_sizes(leveldb_t* db, int num_ranges,
const char* const* range_start_key,
const size_t* range_start_key_len,
const char* const* range_limit_key,
const size_t* range_limit_key_len,
uint64_t* sizes) {
Range* ranges = new Range[num_ranges];
for (int i = 0; i < num_ranges; i++) {
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
}
db->rep->GetApproximateSizes(ranges, num_ranges, sizes);
delete[] ranges;
}
void leveldb_compact_range(leveldb_t* db, const char* start_key,
size_t start_key_len, const char* limit_key,
size_t limit_key_len) {
Slice a, b;
db->rep->CompactRange(
// Pass null Slice if corresponding "const char*" is null
(start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr),
(limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr));
}
void leveldb_destroy_db(const leveldb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, DestroyDB(name, options->rep));
}
void leveldb_repair_db(const leveldb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, RepairDB(name, options->rep));
}
void leveldb_iter_destroy(leveldb_iterator_t* iter) {
delete iter->rep;
delete iter;
}
uint8_t leveldb_iter_valid(const leveldb_iterator_t* iter) {
return iter->rep->Valid();
}
void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) {
iter->rep->SeekToFirst();
}
void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) {
iter->rep->SeekToLast();
}
void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) {
iter->rep->Seek(Slice(k, klen));
}
void leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); }
void leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); }
const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) {
Slice s = iter->rep->key();
*klen = s.size();
return s.data();
}
const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) {
Slice s = iter->rep->value();
*vlen = s.size();
return s.data();
}
void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) {
SaveError(errptr, iter->rep->status());
}
leveldb_writebatch_t* leveldb_writebatch_create() {
return new leveldb_writebatch_t;
}
void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; }
void leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); }
void leveldb_writebatch_put(leveldb_writebatch_t* b, const char* key,
size_t klen, const char* val, size_t vlen) {
b->rep.Put(Slice(key, klen), Slice(val, vlen));
}
void leveldb_writebatch_delete(leveldb_writebatch_t* b, const char* key,
size_t klen) {
b->rep.Delete(Slice(key, klen));
}
void leveldb_writebatch_iterate(const leveldb_writebatch_t* b, void* state,
void (*put)(void*, const char* k, size_t klen,
const char* v, size_t vlen),
void (*deleted)(void*, const char* k,
size_t klen)) {
class H : public WriteBatch::Handler {
public:
void* state_;
void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen);
void (*deleted_)(void*, const char* k, size_t klen);
void Put(const Slice& key, const Slice& value) override {
(*put_)(state_, key.data(), key.size(), value.data(), value.size());
}
void Delete(const Slice& key) override {
(*deleted_)(state_, key.data(), key.size());
}
};
H handler;
handler.state_ = state;
handler.put_ = put;
handler.deleted_ = deleted;
b->rep.Iterate(&handler);
}
void leveldb_writebatch_append(leveldb_writebatch_t* destination,
const leveldb_writebatch_t* source) {
destination->rep.Append(source->rep);
}
leveldb_options_t* leveldb_options_create() { return new leveldb_options_t; }
void leveldb_options_destroy(leveldb_options_t* options) { delete options; }
void leveldb_options_set_comparator(leveldb_options_t* opt,
leveldb_comparator_t* cmp) {
opt->rep.comparator = cmp;
}
void leveldb_options_set_filter_policy(leveldb_options_t* opt,
leveldb_filterpolicy_t* policy) {
opt->rep.filter_policy = policy;
}
void leveldb_options_set_create_if_missing(leveldb_options_t* opt, uint8_t v) {
opt->rep.create_if_missing = v;
}
void leveldb_options_set_error_if_exists(leveldb_options_t* opt, uint8_t v) {
opt->rep.error_if_exists = v;
}
void leveldb_options_set_paranoid_checks(leveldb_options_t* opt, uint8_t v) {
opt->rep.paranoid_checks = v;
}
void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) {
opt->rep.env = (env ? env->rep : nullptr);
}
void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) {
opt->rep.info_log = (l ? l->rep : nullptr);
}
void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) {
opt->rep.write_buffer_size = s;
}
void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) {
opt->rep.max_open_files = n;
}
void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) {
opt->rep.block_cache = c->rep;
}
void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) {
opt->rep.block_size = s;
}
void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) {
opt->rep.block_restart_interval = n;
}
void leveldb_options_set_max_file_size(leveldb_options_t* opt, size_t s) {
opt->rep.max_file_size = s;
}
void leveldb_options_set_compression(leveldb_options_t* opt, int t) {
opt->rep.compression = static_cast<CompressionType>(t);
}
leveldb_comparator_t* leveldb_comparator_create(
void* state, void (*destructor)(void*),
int (*compare)(void*, const char* a, size_t alen, const char* b,
size_t blen),
const char* (*name)(void*)) {
leveldb_comparator_t* result = new leveldb_comparator_t;
result->state_ = state;
result->destructor_ = destructor;
result->compare_ = compare;
result->name_ = name;
return result;
}
void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; }
leveldb_filterpolicy_t* leveldb_filterpolicy_create(
void* state, void (*destructor)(void*),
char* (*create_filter)(void*, const char* const* key_array,
const size_t* key_length_array, int num_keys,
size_t* filter_length),
uint8_t (*key_may_match)(void*, const char* key, size_t length,
const char* filter, size_t filter_length),
const char* (*name)(void*)) {
leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t;
result->state_ = state;
result->destructor_ = destructor;
result->create_ = create_filter;
result->key_match_ = key_may_match;
result->name_ = name;
return result;
}
void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) {
delete filter;
}
leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) {
// Make a leveldb_filterpolicy_t, but override all of its methods so
// they delegate to a NewBloomFilterPolicy() instead of user
// supplied C functions.
struct Wrapper : public leveldb_filterpolicy_t {
static void DoNothing(void*) {}
~Wrapper() { delete rep_; }
const char* Name() const { return rep_->Name(); }
void CreateFilter(const Slice* keys, int n, std::string* dst) const {
return rep_->CreateFilter(keys, n, dst);
}
bool KeyMayMatch(const Slice& key, const Slice& filter) const {
return rep_->KeyMayMatch(key, filter);
}
const FilterPolicy* rep_;
};
Wrapper* wrapper = new Wrapper;
wrapper->rep_ = NewBloomFilterPolicy(bits_per_key);
wrapper->state_ = nullptr;
wrapper->destructor_ = &Wrapper::DoNothing;
return wrapper;
}
leveldb_readoptions_t* leveldb_readoptions_create() {
return new leveldb_readoptions_t;
}
void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete opt; }
void leveldb_readoptions_set_verify_checksums(leveldb_readoptions_t* opt,
uint8_t v) {
opt->rep.verify_checksums = v;
}
void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t* opt, uint8_t v) {
opt->rep.fill_cache = v;
}
void leveldb_readoptions_set_snapshot(leveldb_readoptions_t* opt,
const leveldb_snapshot_t* snap) {
opt->rep.snapshot = (snap ? snap->rep : nullptr);
}
leveldb_writeoptions_t* leveldb_writeoptions_create() {
return new leveldb_writeoptions_t;
}
void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete opt; }
void leveldb_writeoptions_set_sync(leveldb_writeoptions_t* opt, uint8_t v) {
opt->rep.sync = v;
}
leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) {
leveldb_cache_t* c = new leveldb_cache_t;
c->rep = NewLRUCache(capacity);
return c;
}
void leveldb_cache_destroy(leveldb_cache_t* cache) {
delete cache->rep;
delete cache;
}
leveldb_env_t* leveldb_create_default_env() {
leveldb_env_t* result = new leveldb_env_t;
result->rep = Env::Default();
result->is_default = true;
return result;
}
void leveldb_env_destroy(leveldb_env_t* env) {
if (!env->is_default) delete env->rep;
delete env;
}
char* leveldb_env_get_test_directory(leveldb_env_t* env) {
std::string result;
if (!env->rep->GetTestDirectory(&result).ok()) {
return nullptr;
}
char* buffer = static_cast<char*>(std::malloc(result.size() + 1));
std::memcpy(buffer, result.data(), result.size());
buffer[result.size()] = '\0';
return buffer;
}
void leveldb_free(void* ptr) { std::free(ptr); }
int leveldb_major_version() { return kMajorVersion; }
int leveldb_minor_version() { return kMinorVersion; }
} // end extern "C"
================================================
FILE: db/c_test.c
================================================
/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. See the AUTHORS file for names of contributors. */
#include "leveldb/c.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* phase = "";
static void StartPhase(const char* name) {
fprintf(stderr, "=== Test %s\n", name);
phase = name;
}
#define CheckNoError(err) \
if ((err) != NULL) { \
fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
abort(); \
}
#define CheckCondition(cond) \
if (!(cond)) { \
fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \
abort(); \
}
static void CheckEqual(const char* expected, const char* v, size_t n) {
if (expected == NULL && v == NULL) {
// ok
} else if (expected != NULL && v != NULL && n == strlen(expected) &&
memcmp(expected, v, n) == 0) {
// ok
return;
} else {
fprintf(stderr, "%s: expected '%s', got '%s'\n",
phase,
(expected ? expected : "(null)"),
(v ? v : "(null"));
abort();
}
}
static void Free(char** ptr) {
if (*ptr) {
free(*ptr);
*ptr = NULL;
}
}
static void CheckGet(
leveldb_t* db,
const leveldb_readoptions_t* options,
const char* key,
const char* expected) {
char* err = NULL;
size_t val_len;
char* val;
val = leveldb_get(db, options, key, strlen(key), &val_len, &err);
CheckNoError(err);
CheckEqual(expected, val, val_len);
Free(&val);
}
static void CheckIter(leveldb_iterator_t* iter,
const char* key, const char* val) {
size_t len;
const char* str;
str = leveldb_iter_key(iter, &len);
CheckEqual(key, str, len);
str = leveldb_iter_value(iter, &len);
CheckEqual(val, str, len);
}
// Callback from leveldb_writebatch_iterate()
static void CheckPut(void* ptr,
const char* k, size_t klen,
const char* v, size_t vlen) {
int* state = (int*) ptr;
CheckCondition(*state < 2);
switch (*state) {
case 0:
CheckEqual("bar", k, klen);
CheckEqual("b", v, vlen);
break;
case 1:
CheckEqual("box", k, klen);
CheckEqual("c", v, vlen);
break;
}
(*state)++;
}
// Callback from leveldb_writebatch_iterate()
static void CheckDel(void* ptr, const char* k, size_t klen) {
int* state = (int*) ptr;
CheckCondition(*state == 2);
CheckEqual("bar", k, klen);
(*state)++;
}
static void CmpDestroy(void* arg) { }
static int CmpCompare(void* arg, const char* a, size_t alen,
const char* b, size_t blen) {
int n = (alen < blen) ? alen : blen;
int r = memcmp(a, b, n);
if (r == 0) {
if (alen < blen) r = -1;
else if (alen > blen) r = +1;
}
return r;
}
static const char* CmpName(void* arg) {
return "foo";
}
// Custom filter policy
static uint8_t fake_filter_result = 1;
static void FilterDestroy(void* arg) { }
static const char* FilterName(void* arg) {
return "TestFilter";
}
static char* FilterCreate(
void* arg,
const char* const* key_array, const size_t* key_length_array,
int num_keys,
size_t* filter_length) {
*filter_length = 4;
char* result = malloc(4);
memcpy(result, "fake", 4);
return result;
}
uint8_t FilterKeyMatch(void* arg, const char* key, size_t length,
const char* filter, size_t filter_length) {
CheckCondition(filter_length == 4);
CheckCondition(memcmp(filter, "fake", 4) == 0);
return fake_filter_result;
}
int main(int argc, char** argv) {
leveldb_t* db;
leveldb_comparator_t* cmp;
leveldb_cache_t* cache;
leveldb_env_t* env;
leveldb_options_t* options;
leveldb_readoptions_t* roptions;
leveldb_writeoptions_t* woptions;
char* dbname;
char* err = NULL;
int run = -1;
CheckCondition(leveldb_major_version() >= 1);
CheckCondition(leveldb_minor_version() >= 1);
StartPhase("create_objects");
cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);
env = leveldb_create_default_env();
cache = leveldb_cache_create_lru(100000);
dbname = leveldb_env_get_test_directory(env);
CheckCondition(dbname != NULL);
options = leveldb_options_create();
leveldb_options_set_comparator(options, cmp);
leveldb_options_set_error_if_exists(options, 1);
leveldb_options_set_cache(options, cache);
leveldb_options_set_env(options, env);
leveldb_options_set_info_log(options, NULL);
leveldb_options_set_write_buffer_size(options, 100000);
leveldb_options_set_paranoid_checks(options, 1);
leveldb_options_set_max_open_files(options, 10);
leveldb_options_set_block_size(options, 1024);
leveldb_options_set_block_restart_interval(options, 8);
leveldb_options_set_max_file_size(options, 3 << 20);
leveldb_options_set_compression(options, leveldb_no_compression);
roptions = leveldb_readoptions_create();
leveldb_readoptions_set_verify_checksums(roptions, 1);
leveldb_readoptions_set_fill_cache(roptions, 0);
woptions = leveldb_writeoptions_create();
leveldb_writeoptions_set_sync(woptions, 1);
StartPhase("destroy");
leveldb_destroy_db(options, dbname, &err);
Free(&err);
StartPhase("open_error");
db = leveldb_open(options, dbname, &err);
CheckCondition(err != NULL);
Free(&err);
StartPhase("leveldb_free");
db = leveldb_open(options, dbname, &err);
CheckCondition(err != NULL);
leveldb_free(err);
err = NULL;
StartPhase("open");
leveldb_options_set_create_if_missing(options, 1);
db = leveldb_open(options, dbname, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", NULL);
StartPhase("put");
leveldb_put(db, woptions, "foo", 3, "hello", 5, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", "hello");
StartPhase("compactall");
leveldb_compact_range(db, NULL, 0, NULL, 0);
CheckGet(db, roptions, "foo", "hello");
StartPhase("compactrange");
leveldb_compact_range(db, "a", 1, "z", 1);
CheckGet(db, roptions, "foo", "hello");
StartPhase("writebatch");
{
leveldb_writebatch_t* wb = leveldb_writebatch_create();
leveldb_writebatch_put(wb, "foo", 3, "a", 1);
leveldb_writebatch_clear(wb);
leveldb_writebatch_put(wb, "bar", 3, "b", 1);
leveldb_writebatch_put(wb, "box", 3, "c", 1);
leveldb_writebatch_t* wb2 = leveldb_writebatch_create();
leveldb_writebatch_delete(wb2, "bar", 3);
leveldb_writebatch_append(wb, wb2);
leveldb_writebatch_destroy(wb2);
leveldb_write(db, woptions, wb, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", "hello");
CheckGet(db, roptions, "bar", NULL);
CheckGet(db, roptions, "box", "c");
int pos = 0;
leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel);
CheckCondition(pos == 3);
leveldb_writebatch_destroy(wb);
}
StartPhase("iter");
{
leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions);
CheckCondition(!leveldb_iter_valid(iter));
leveldb_iter_seek_to_first(iter);
CheckCondition(leveldb_iter_valid(iter));
CheckIter(iter, "box", "c");
leveldb_iter_next(iter);
CheckIter(iter, "foo", "hello");
leveldb_iter_prev(iter);
CheckIter(iter, "box", "c");
leveldb_iter_prev(iter);
CheckCondition(!leveldb_iter_valid(iter));
leveldb_iter_seek_to_last(iter);
CheckIter(iter, "foo", "hello");
leveldb_iter_seek(iter, "b", 1);
CheckIter(iter, "box", "c");
leveldb_iter_get_error(iter, &err);
CheckNoError(err);
leveldb_iter_destroy(iter);
}
StartPhase("approximate_sizes");
{
int i;
int n = 20000;
char keybuf[100];
char valbuf[100];
uint64_t sizes[2];
const char* start[2] = { "a", "k00000000000000010000" };
size_t start_len[2] = { 1, 21 };
const char* limit[2] = { "k00000000000000010000", "z" };
size_t limit_len[2] = { 21, 1 };
leveldb_writeoptions_set_sync(woptions, 0);
for (i = 0; i < n; i++) {
snprintf(keybuf, sizeof(keybuf), "k%020d", i);
snprintf(valbuf, sizeof(valbuf), "v%020d", i);
leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf),
&err);
CheckNoError(err);
}
leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
CheckCondition(sizes[0] > 0);
CheckCondition(sizes[1] > 0);
}
StartPhase("property");
{
char* prop = leveldb_property_value(db, "nosuchprop");
CheckCondition(prop == NULL);
prop = leveldb_property_value(db, "leveldb.stats");
CheckCondition(prop != NULL);
Free(&prop);
}
StartPhase("snapshot");
{
const leveldb_snapshot_t* snap;
snap = leveldb_create_snapshot(db);
leveldb_delete(db, woptions, "foo", 3, &err);
CheckNoError(err);
leveldb_readoptions_set_snapshot(roptions, snap);
CheckGet(db, roptions, "foo", "hello");
leveldb_readoptions_set_snapshot(roptions, NULL);
CheckGet(db, roptions, "foo", NULL);
leveldb_release_snapshot(db, snap);
}
StartPhase("repair");
{
leveldb_close(db);
leveldb_options_set_create_if_missing(options, 0);
leveldb_options_set_error_if_exists(options, 0);
leveldb_repair_db(options, dbname, &err);
CheckNoError(err);
db = leveldb_open(options, dbname, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", NULL);
CheckGet(db, roptions, "bar", NULL);
CheckGet(db, roptions, "box", "c");
leveldb_options_set_create_if_missing(options, 1);
leveldb_options_set_error_if_exists(options, 1);
}
StartPhase("filter");
for (run = 0; run < 2; run++) {
// First run uses custom filter, second run uses bloom filter
CheckNoError(err);
leveldb_filterpolicy_t* policy;
if (run == 0) {
policy = leveldb_filterpolicy_create(
NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName);
} else {
policy = leveldb_filterpolicy_create_bloom(10);
}
// Create new database
leveldb_close(db);
leveldb_destroy_db(options, dbname, &err);
leveldb_options_set_filter_policy(options, policy);
db = leveldb_open(options, dbname, &err);
CheckNoError(err);
leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
CheckNoError(err);
leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
CheckNoError(err);
leveldb_compact_range(db, NULL, 0, NULL, 0);
fake_filter_result = 1;
CheckGet(db, roptions, "foo", "foovalue");
CheckGet(db, roptions, "bar", "barvalue");
if (phase == 0) {
// Must not find value when custom filter returns false
fake_filter_result = 0;
CheckGet(db, roptions, "foo", NULL);
CheckGet(db, roptions, "bar", NULL);
fake_filter_result = 1;
CheckGet(db, roptions, "foo", "foovalue");
CheckGet(db, roptions, "bar", "barvalue");
}
leveldb_options_set_filter_policy(options, NULL);
leveldb_filterpolicy_destroy(policy);
}
StartPhase("cleanup");
leveldb_close(db);
leveldb_options_destroy(options);
leveldb_readoptions_destroy(roptions);
leveldb_writeoptions_destroy(woptions);
leveldb_free(dbname);
leveldb_cache_destroy(cache);
leveldb_comparator_destroy(cmp);
leveldb_env_destroy(env);
fprintf(stderr, "PASS\n");
return 0;
}
================================================
FILE: db/corruption_test.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <sys/types.h>
#include "gtest/gtest.h"
#include "db/db_impl.h"
#include "db/filename.h"
#include "db/log_format.h"
#include "db/version_set.h"
#include "leveldb/cache.h"
#include "leveldb/db.h"
#include "leveldb/table.h"
#include "leveldb/write_batch.h"
#include "util/logging.h"
#include "util/testutil.h"
namespace leveldb {
static const int kValueSize = 1000;
class CorruptionTest : public testing::Test {
public:
CorruptionTest()
: db_(nullptr),
dbname_("/memenv/corruption_test"),
tiny_cache_(NewLRUCache(100)) {
options_.env = &env_;
options_.block_cache = tiny_cache_;
DestroyDB(dbname_, options_);
options_.create_if_missing = true;
Reopen();
options_.create_if_missing = false;
}
~CorruptionTest() {
delete db_;
delete tiny_cache_;
}
Status TryReopen() {
delete db_;
db_ = nullptr;
return DB::Open(options_, dbname_, &db_);
}
void Reopen() { ASSERT_LEVELDB_OK(TryReopen()); }
void RepairDB() {
delete db_;
db_ = nullptr;
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) std::fprintf(stderr, "@ %d of %d\n", i, n);
Slice key = Key(i, &key_space);
batch.Clear();
batch.Put(key, Value(i, &value_space));
WriteOptions options;
// Corrupt() doesn't work without this sync on windows; stat reports 0 for
// the file size.
if (i == n - 1) {
options.sync = true;
}
ASSERT_LEVELDB_OK(db_->Write(options, &batch));
}
}
void Check(int min_expected, int max_expected) {
int next_expected = 0;
int missed = 0;
int bad_keys = 0;
int bad_values = 0;
int correct = 0;
std::string value_space;
Iterator* iter = db_->NewIterator(ReadOptions());
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
uint64_t key;
Slice in(iter->key());
if (in == "" || in == "~") {
// Ignore boundary keys.
continue;
}
if (!ConsumeDecimalNumber(&in, &key) || !in.empty() ||
key < next_expected) {
bad_keys++;
continue;
}
missed += (key - next_expected);
next_expected = key + 1;
if (iter->value() != Value(key, &value_space)) {
bad_values++;
} else {
correct++;
}
}
delete iter;
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);
}
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
// Pick file to corrupt
std::vector<std::string> filenames;
ASSERT_LEVELDB_OK(env_.target()->GetChildren(dbname_, &filenames));
uint64_t number;
FileType type;
std::string fname;
int picked_number = -1;
for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type) && type == filetype &&
int(number) > picked_number) { // Pick latest file
fname = dbname_ + "/" + filenames[i];
picked_number = number;
}
}
ASSERT_TRUE(!fname.empty()) << filetype;
uint64_t file_size;
ASSERT_LEVELDB_OK(env_.target()->GetFileSize(fname, &file_size));
if (offset < 0) {
// Relative to end of file; make it absolute
if (-offset > file_size) {
offset = 0;
} else {
offset = file_size + offset;
}
}
if (offset > file_size) {
offset = file_size;
}
if (offset + bytes_to_corrupt > file_size) {
bytes_to_corrupt = file_size - offset;
}
// Do it
std::string contents;
Status s = ReadFileToString(env_.target(), fname, &contents);
ASSERT_TRUE(s.ok()) << s.ToString();
for (int i = 0; i < bytes_to_corrupt; i++) {
contents[i + offset] ^= 0x80;
}
s = WriteStringToFile(env_.target(), contents, fname);
ASSERT_TRUE(s.ok()) << s.ToString();
}
int Property(const std::string& name) {
std::string property;
int result;
if (db_->GetProperty(name, &property) &&
sscanf(property.c_str(), "%d", &result) == 1) {
return result;
} else {
return -1;
}
}
// Return the ith key
Slice Key(int i, std::string* storage) {
char buf[100];
std::snprintf(buf, sizeof(buf), "%016d", i);
storage->assign(buf, strlen(buf));
return Slice(*storage);
}
// Return the value to associate with the specified key
Slice Value(int k, std::string* storage) {
Random r(k);
return test::RandomString(&r, kValueSize, storage);
}
test::ErrorEnv env_;
Options options_;
DB* db_;
private:
std::string dbname_;
Cache* tiny_cache_;
};
TEST_F(CorruptionTest, Recovery) {
Build(100);
Check(100, 100);
Corrupt(kLogFile, 19, 1); // WriteBatch tag for first record
Corrupt(kLogFile, log::kBlockSize + 1000, 1); // Somewhere in second block
Reopen();
// The 64 records in the first two log blocks are completely lost.
Check(36, 36);
}
TEST_F(CorruptionTest, RecoverWriteError) {
env_.writable_file_error_ = true;
Status s = TryReopen();
ASSERT_TRUE(!s.ok());
}
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);
std::string value_storage;
Status s;
for (int i = 0; s.ok() && i < num; i++) {
WriteBatch batch;
batch.Put("a", Value(100, &value_storage));
s = db_->Write(WriteOptions(), &batch);
}
ASSERT_TRUE(!s.ok());
ASSERT_GE(env_.num_writable_file_errors_, 1);
env_.writable_file_error_ = false;
Reopen();
}
TEST_F(CorruptionTest, TableFile) {
Build(100);
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
dbi->TEST_CompactRange(0, nullptr, nullptr);
dbi->TEST_CompactRange(1, nullptr, nullptr);
Corrupt(kTableFile, 100, 1);
Check(90, 99);
}
TEST_F(CorruptionTest, TableFileRepair) {
options_.block_size = 2 * kValueSize; // Limit scope of corruption
options_.paranoid_checks = true;
Reopen();
Build(100);
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
dbi->TEST_CompactRange(0, nullptr, nullptr);
dbi->TEST_CompactRange(1, nullptr, nullptr);
Corrupt(kTableFile, 100, 1);
RepairDB();
Reopen();
Check(95, 99);
}
TEST_F(CorruptionTest, TableFileIndexData) {
Build(10000); // Enough to build multiple Tables
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
Corrupt(kTableFile, -2000, 500);
Reopen();
Check(5000, 9999);
}
TEST_F(CorruptionTest, MissingDescriptor) {
Build(1000);
RepairDB();
Reopen();
Check(1000, 1000);
}
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_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_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "v6"));
ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("v6", v);
Reopen();
ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("v6", v);
}
TEST_F(CorruptionTest, CorruptedDescriptor) {
ASSERT_LEVELDB_OK(db_->Put(WriteOptions(), "foo", "hello"));
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
dbi->TEST_CompactRange(0, nullptr, nullptr);
Corrupt(kDescriptorFile, 0, 1000);
Status s = TryReopen();
ASSERT_TRUE(!s.ok());
RepairDB();
Reopen();
std::string v;
ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("hello", v);
}
TEST_F(CorruptionTest, CompactionInputError) {
Build(10);
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
const int last = config::kMaxMemCompactLevel;
ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last)));
Corrupt(kTableFile, 100, 1);
Check(5, 9);
// Force compactions by writing lots of values
Build(10000);
Check(10000, 10000);
}
TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
options_.paranoid_checks = true;
options_.write_buffer_size = 512 << 10;
Reopen();
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
// Make multiple inputs so we need to compact.
for (int i = 0; i < 2; i++) {
Build(10);
dbi->TEST_CompactMemTable();
Corrupt(kTableFile, 100, 1);
env_.SleepForMicroseconds(100000);
}
dbi->CompactRange(nullptr, nullptr);
// Write must fail because of corrupted table
std::string tmp1, tmp2;
Status s = db_->Put(WriteOptions(), Key(5, &tmp1), Value(5, &tmp2));
ASSERT_TRUE(!s.ok()) << "write did not fail in corrupted paranoid db";
}
TEST_F(CorruptionTest, UnrelatedKeys) {
Build(10);
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
dbi->TEST_CompactMemTable();
Corrupt(kTableFile, 100, 1);
std::string tmp1, tmp2;
ASSERT_LEVELDB_OK(
db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
std::string v;
ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
dbi->TEST_CompactMemTable();
ASSERT_LEVELDB_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
}
} // namespace leveldb
================================================
FILE: db/db_impl.cc
================================================
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "db/db_impl.h"
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <cstdio>
#include <set>
#include <string>
#include <vector>
#include "db/builder.h"
#include "db/db_iter.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include "db/log_reader.h"
#include "db/log_writer.h"
#include "db/memtable.h"
#include "db/table_cache.h"
#include "db/version_set.h"
#include "db/write_batch_internal.h"
#include "leveldb/db.h"
#include "leveldb/env.h"
#include "leveldb/status.h"
#include "leveldb/table.h"
#include "leveldb/table_builder.h"
#include "port/port.h"
#include "table/block.h"
#include "table/merger.h"
#include "table/two_level_iterator.h"
#include "util/coding.h"
#include "util/logging.h"
#include "util/mutexlock.h"
namespace leveldb {
const int kNumNonTableCacheFiles = 10;
// Information kept for every waiting writer
struct DBImpl::Writer {
explicit Writer(port::Mutex* mu)
: batch(nullptr), sync(false), done(false), cv(mu) {}
Status status;
WriteBatch* batch;
bool sync;
bool done;
port::CondVar cv;
};
struct DBImpl::CompactionState {
// Files produced by compaction
struct Output {
uint64_t number;
uint64_t file_size;
InternalKey smallest, largest;
};
Output* current_output() { return &outputs[outputs.size() - 1]; }
explicit CompactionState(Compaction* c)
: compaction(c),
smallest_snapshot(0),
outfile(nullptr),
builder(nullptr),
total_bytes(0) {}
Compaction* const compaction;
// Sequence numbers < smallest_snapshot are not significant since we
// will never have to service a snapshot below smallest_snapshot.
// Therefore if we have seen a sequence number S <= smallest_snapshot,
// we can drop all entries for the same key with sequence numbers < S.
SequenceNumber smallest_snapshot;
std::vector<Output> outputs;
// State kept for output being generated
WritableFile* outfile;
TableBuilder* builder;
uint64_t total_bytes;
};
// Fix user-supplied options to be reasonable
template <class T, class V>
static void ClipToRange(T* ptr, V minvalue, V maxvalue) {
if (static_cast<V>(*ptr) > maxvalue) *ptr = maxvalue;
if (static_cast<V>(*ptr) < minvalue) *ptr = minvalue;
}
Options SanitizeOptions(const std::string& dbname,
const InternalKeyComparator* icmp,
const InternalFilterPolicy* ipolicy,
const Options& src) {
Options result = src;
result.comparator = icmp;
result.filter_policy = (src.filter_policy != nullptr) ? ipolicy : nullptr;
ClipToRange(&result.max_open_files, 64 + kNumNonTableCacheFiles, 50000);
ClipToRange(&result.write_buffer_size, 64 << 10, 1 << 30);
ClipToRange(&result.max_file_size, 1 << 20, 1 << 30);
ClipToRange(&result.block_size, 1 << 10, 4 << 20);
if (result.info_log == nullptr) {
// Open a log file in the same directory as the db
src.env->CreateDir(dbname); // In case it does not exist
src.env->RenameFile(InfoLogFileName(dbname), OldInfoLogFileName(dbname));
Status s = src.env->NewLogger(InfoLogFileName(dbname), &result.info_log);
if (!s.ok()) {
// No place suitable for logging
result.info_log = nullptr;
}
}
if (result.block_cache == nullptr) {
result.block_cache = NewLRUCache(8 << 20);
}
return result;
}
static int TableCacheSize(const Options& sanitized_options) {
// Reserve ten files or so for other uses and give the rest to TableCache.
return sanitized_options.max_open_files - kNumNonTableCacheFiles;
}
DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
: env_(raw_options.env),
internal_comparator_(raw_options.comparator),
internal_filter_policy_(raw_options.filter_policy),
options_(SanitizeOptions(dbname, &internal_comparator_,
&internal_filter_policy_, raw_options)),
owns_info_log_(options_.info_log != raw_options.info_log),
owns_cache_(options_.block_cache != raw_options.block_cache),
dbname_(dbname),
table_cache_(new TableCache(dbname_, options_, TableCacheSize(options_))),
db_lock_(nullptr),
shutting_down_(false),
background_work_finished_signal_(&mutex_),
mem_(nullptr),
imm_(nullptr),
has_imm_(false),
logfile_(nullptr),
logfile_number_(0),
log_(nullptr),
seed_(0),
tmp_batch_(new WriteBatch),
background_compaction_scheduled_(false),
manual_compaction_(nullptr),
versions_(new VersionSet(dbname_, &options_, table_cache_,
&internal_comparator_)) {}
DBImpl::~DBImpl() {
// Wait for background work to finish.
mutex_.Lock();
shutting_down_.store(true, std::memory_order_release);
while (background_compaction_scheduled_) {
background_work_finished_signal_.Wait();
}
mutex_.Unlock();
if (db_lock_ != nullptr) {
env_->UnlockFile(db_lock_);
}
delete versions_;
if (mem_ != nullptr) mem_->Unref();
if (imm_ != nullptr) imm_->Unref();
delete tmp_batch_;
delete log_;
delete logfile_;
delete table_cache_;
if (owns_info_log_) {
delete options_.info_log;
}
if (owns_cache_) {
delete options_.block_cache;
}
}
Status DBImpl::NewDB() {
VersionEdit new_db;
new_db.SetComparatorName(user_comparator()->Name());
new_db.SetLogNumber(0);
new_db.SetNextFile(2);
new_db.SetLastSequence(0);
const std::string manifest = DescriptorFileName(dbname_, 1);
WritableFile* file;
Status s = env_->NewWritableFile(manifest, &file);
if (!s.ok()) {
return s;
}
{
log::Writer log(file);
std::string record;
new_db.EncodeTo(&record);
s = log.AddRecord(record);
if (s.ok()) {
s = file->Sync();
}
if (s.ok()) {
s = file->Close();
}
}
delete file;
if (s.ok()) {
// Make "CURRENT" file that points to the new manifest file.
s = SetCurrentFile(env_, dbname_, 1);
} else {
env_->RemoveFile(manifest);
}
return s;
}
void DBImpl::MaybeIgnoreError(Status* s) const {
if (s->ok() || options_.paranoid_checks) {
// No change needed
} else {
Log(options_.info_log, "Ignoring error %s", s->ToString().c_str());
*s = Status::OK();
}
}
void DBImpl::RemoveObsoleteFiles() {
mutex_.AssertHeld();
if (!bg_error_.ok()) {
// After a background error, we don't know whether a new version may
// or may not have been committed, so we cannot safely garbage collect.
return;
}
// Make a set of all of the live files
std::set<uint64_t> live = pending_outputs_;
versions_->AddLiveFiles(&live);
std::vector<std::string> filenames;
env_->GetChildren(dbname_, &filenames); // Ignoring errors on purpose
uint64_t number;
FileType type;
std::vector<std::string> files_to_delete;
for (std::string& filename : filenames) {
if (ParseFileName(filename, &number, &type)) {
bool keep = true;
switch (type) {
case kLogFile:
keep = ((number >= versions_->LogNumber()) ||
(number == versions_->PrevLogNumber()));
break;
case kDescriptorFile:
// Keep my manifest file, and any newer incarnations'
// (in case there is a race that allows other incarnations)
keep = (number >= versions_->ManifestFileNumber());
break;
case kTableFile:
keep = (live.find(number) != live.end());
break;
case kTempFile:
// Any temp files that are currently being written to must
// be recorded in pending_outputs_, which is inserted into "live"
keep = (live.find(number) != live.end());
break;
case kCurrentFile:
case kDBLockFile:
case kInfoLogFile:
keep = true;
break;
}
if (!keep) {
files_to_delete.push_back(std::move(filename));
if (type == kTableFile) {
table_cache_->Evict(number);
}
Log(options_.info_log, "Delete type=%d #%lld\n", static_cast<int>(type),
static_cast<unsigned long long>(number));
}
}
}
// While deleting all files unblock other threads. All files being deleted
// have unique names which will not collide with newly created files and
// are therefore safe to delete while allowing other threads to proceed.
mutex_.Unlock();
for (const std::string& filename : files_to_delete) {
env_->RemoveFile(dbname_ + "/" + filename);
}
mutex_.Lock();
}
Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
mutex_.AssertHeld();
// Ignore error from CreateDir since the creation of the DB is
// committed only when the descriptor is created, and this directory
// may already exist from a previous failed creation attempt.
env_->CreateDir(dbname_);
assert(db_lock_ == nullptr);
Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
if (!s.ok()) {
return s;
}
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;
}
} else {
return Status::InvalidArgument(
dbname_, "does not exist (create_if_missing is false)");
}
} else {
if (options_.error_if_exists) {
return Status::InvalidArgument(dbname_,
"exists (error_if_exists is true)");
}
}
s = versions_->Recover(save_manifest);
if (!s.ok()) {
return s;
}
SequenceNumber max_sequence(0);
// Recover from all newer log files than the ones named in the
// descriptor (new log files may have been added by the previous
// incarnation without registering them in the descriptor).
//
// Note that PrevLogNumber() is no longer used, but we pay
// attention to it in case we are recovering a database
// produced by an older version of leveldb.
const uint64_t min_log = versions_->LogNumber();
const uint64_t prev_log = versions_->PrevLogNumber();
std::vector<std::string> filenames;
s = env_->GetChildren(dbname_, &filenames);
if (!s.ok()) {
return s;
}
std::set<uint64_t> expected;
versions_->AddLiveFiles(&expected);
uint64_t number;
FileType type;
std::vector<uint64_t> logs;
for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type)) {
expected.erase(number);
if (type == kLogFile && ((number >= min_log) || (number == prev_log)))
logs.push_back(number);
}
}
if (!expected.empty()) {
char buf[50];
std::snprintf(buf, sizeof(buf), "%d missing files; e.g.",
static_cast<int>(expected.size()));
return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));
}
// Recover in the order in which the logs were generated
std::sort(logs.begin(), logs.end());
for (size_t i = 0; i < logs.size(); i++) {
s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit,
&max_sequence);
if (!s.ok()) {
return s;
}
// The previous incarnation may not have written any MANIFEST
// records after allocating this log number. So we manually
// update the file number allocation counter in VersionSet.
versions_->MarkFileNumberUsed(logs[i]);
}
if (versions_->LastSequence() < max_sequence) {
versions_->SetLastSequence(max_sequence);
}
return Status::OK();
}
Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log,
bool* save_manifest, VersionEdit* edit,
SequenceNumber* max_sequence) {
struct LogReporter : public log::Reader::Reporter {
Env* env;
Logger* info_log;
const char* fname;
Status* status; // null if options_.paranoid_checks==false
void Corruption(size_t bytes, const Status& s) override {
Log(info_log, "%s%s: dropping %d bytes; %s",
(this->status == nullptr ? "(ignoring error) " : ""), fname,
static_cast<int>(bytes), s.ToString().c_str());
if (this->status != nullptr && this->status->ok()) *this->status = s;
}
};
mutex_.AssertHeld();
// Open the log file
std::string fname = LogFileName(dbname_, log_number);
SequentialFile* file;
Status status = env_->NewSequentialFile(fname, &file);
if (!status.ok()) {
MaybeIgnoreError(&status);
return status;
}
// Create the log reader.
LogReporter reporter;
reporter.env = env_;
reporter.info_log = options_.info_log;
reporter.fname = fname.c_str();
reporter.status = (options_.paranoid_checks ? &status : nullptr);
// We intentionally make log::Reader do checksumming even if
// paranoid_checks==false so that corruptions cause entire commits
// to be skipped instead of propagating bad information (like overly
// large sequence numbers).
log::Reader reader(file, &reporter, true /*checksum*/, 0 /*initial_offset*/);
Log(options_.info_log, "Recovering log #%llu",
(unsigned long long)log_number);
// Read all the records and add to a memtable
std::string scratch;
Slice record;
WriteBatch batch;
int compactions = 0;
MemTable* mem = nullptr;
while (reader.ReadRecord(&record, &scratch) && status.ok()) {
if (record.size() < 12) {
reporter.Corruption(record.size(),
Status::Corruption("log record too small"));
continue;
}
WriteBatchInternal::SetContents(&batch, record);
if (mem == nullptr) {
mem = new MemTable(internal_comparator_);
mem->Ref();
}
status = WriteBatchInternal::InsertInto(&batch, mem);
MaybeIgnoreError(&status);
if (!status.ok()) {
break;
}
const SequenceNumber last_seq = WriteBatchInternal::Sequence(&batch) +
WriteBatchInternal::Count(&batch) - 1;
if (last_seq > *max_sequence) {
*max_sequence = last_seq;
}
if (mem->ApproximateMemoryUsage() > options_.write_buffer_size) {
compactions++;
*save_manifest = true;
status = WriteLevel0Table(mem, edit, nullptr);
mem->Unref();
mem = nullptr;
if (!status.ok()) {
// Reflect errors immediately so that conditions like full
// file-systems cause the DB::Open() to fail.
break;
}
}
}
delete file;
// See if we should keep reusing the last log file.
if (status.ok() && options_.reuse_logs && last_log && compactions == 0) {
assert(logfile_ == nullptr);
assert(log_ == nullptr);
assert(mem_ == nullptr);
uint64_t lfile_size;
if (env_->GetFileSize(fname, &lfile_size).ok() &&
env_->NewAppendableFile(fname, &logfile_).ok()) {
Log(options_.info_log, "Reusing old log %s \n", fname.c_str());
log_ = new log::Writer(logfile_, lfile_size);
logfile_number_ = log_number;
if (mem != nullptr) {
mem_ = mem;
mem = nullptr;
} else {
// mem can be nullptr if lognum exists but was empty.
mem_ = new MemTable(internal_comparator_);
mem_->Ref();
}
}
}
if (mem != nullptr) {
// mem did not get reused; compact it.
if (status.ok()) {
*save_manifest = true;
status = WriteLevel0Table(mem, edit, nullptr);
}
mem->Unref();
}
return status;
}
Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit,
Version* base) {
mutex_.AssertHeld();
const uint64_t start_micros = env_->NowMicros();
FileMetaData meta;
meta.number = versions_->NewFileNumber();
pending_outputs_.insert(meta.number);
Iterator* iter = mem->NewIterator();
Log(options_.info_log, "Level-0 table #%llu: started",
(unsigned long long)meta.number);
Status s;
{
mutex_.Unlock();
s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);
mutex_.Lock();
}
Log(options_.info_log, "Level-0 table #%llu: %lld bytes %s",
(unsigned long long)meta.number, (unsigned long long)meta.file_size,
s.ToString().c_str());
delete iter;
pending_outputs_.erase(meta.number);
// Note that if file_size is zero, the file has been deleted and
// should not be added to the manifest.
int level = 0;
if (s.ok() && meta.file_size > 0) {
const Slice min_user_key = meta.smallest.user_key();
const Slice max_user_key = meta.largest.user_key();
if (base != nullptr) {
level = base->PickLevelForMemTableOutput(min_user_key, max_user_key);
}
edit->AddFile(level, meta.number, meta.file_size, meta.smallest,
meta.largest);
}
CompactionStats stats;
stats.micros = env_->NowMicros() - start_micros;
stats.bytes_written = meta.file_size;
stats_[level].Add(stats);
return s;
}
void DBImpl::CompactMemTable() {
mutex_.AssertHeld();
assert(imm_ != nullptr);
// Save the contents of the memtable as a new Table
VersionEdit edit;
Version* base = versions_->current();
base->Ref();
Status s = WriteLevel0Table(imm_, &edit, base);
base->Unref();
if (s.ok() && shutting_down_.load(std::memory_order_acquire)) {
s = Status::IOError("Deleting DB during memtable compaction");
}
// Replace immutable memtable with the generated Table
if (s.ok()) {
edit.SetPrevLogNumber(0);
edit.SetLogNumber(logfile_number_); // Earlier logs no longer needed
s = versions_->LogAndApply(&edit, &mutex_);
}
if (s.ok()) {
// Commit to the new state
imm_->Unref();
imm_ = nullptr;
has_imm_.store(false, std::memory_order_release);
RemoveObsoleteFiles();
} else {
RecordBackgroundError(s);
}
}
void DBImpl::CompactRange(const Slice* begin, const Slice* end) {
int max_level_with_files = 1;
{
MutexLock l(&mutex_);
Version* base = versions_->current();
for (int level = 1; level < config::kNumLevels; level++) {
if (base->OverlapInLevel(level, begin, end)) {
max_level_with_files = level;
}
}
}
TEST_CompactMemTable(); // TODO(sanjay): Skip if memtable does not overlap
for (int level = 0; level < max_level_with_files; level++) {
TEST_CompactRange(level, begin, end);
}
}
void DBImpl::TEST_CompactRange(int level, const Slice* begin,
const Slice* end) {
assert(level >= 0);
assert(level + 1 < config::kNumLevels);
InternalKey begin_storage, end_storage;
ManualCompaction manual;
manual.level = level;
manual.done = false;
if (begin == nullptr) {
manual.begin = nullptr;
} else {
begin_storage = InternalKey(*begin, kMaxSequenceNumber, kValueTypeForSeek);
manual.begin = &begin_storage;
}
if (end == nullptr) {
manual.end = nullptr;
} else {
end_storage = InternalKey(*end, 0, static_cast<ValueType>(0));
manual.end = &end_storage;
}
MutexLock l(&mutex_);
while (!manual.done && !shutting_down_.load(std::memory_order_acquire) &&
bg_error_.ok()) {
if (manual_compaction_ == nullptr) { // Idle
manual_compaction_ = &manual;
MaybeScheduleCompaction();
} else { // Running either my compaction or another compaction.
background_work_finished_signal_.Wait();
}
}
// Finish current background compaction in the case where
// `background_work_finished_signal_` was signalled due to an error.
while (background_compaction_scheduled_) {
background_work_finished_signal_.Wait();
}
if (manual_compaction_ == &manual) {
// Cancel my manual compaction since we aborted early for some reason.
manual_compaction_ = nullptr;
}
}
Status DBImpl::TEST_CompactMemTable() {
// nullptr batch means just wait for earlier writes to be done
Status s = Write(WriteOptions(), nullptr);
if (s.ok()) {
// Wait until the compaction completes
MutexLock l(&mutex_);
while (imm_ != nullptr && bg_error_.ok() &&
!shutting_down_.load(std::memory_order_acquire)) {
background_work_finished_signal_.Wait();
}
if (imm_ != nullptr) {
s = bg_error_;
}
}
return s;
}
void DBImpl::RecordBackgroundError(const Status& s) {
mutex_.AssertHeld();
if (bg_error_.ok()) {
bg_error_ = s;
background_work_finished_signal_.SignalAll();
}
}
void DBImpl::MaybeScheduleCompaction() {
mutex_.AssertHeld();
if (background_compaction_scheduled_) {
// Already scheduled
} else if (shutting_down_.load(std::memory_order_acquire)) {
// DB is being deleted; no more background compactions
} else if (!bg_error_.ok()) {
// Already got an error; no more changes
} else if (imm_ == nullptr && manual_compaction_ == nullptr &&
!versions_->NeedsCompaction()) {
// No work to be done
} else {
background_compaction_scheduled_ = true;
env_->Schedule(&DBImpl::BGWork, this);
}
}
void DBImpl::BGWork(void* db) {
reinterpret_cast<DBImpl*>(db)->BackgroundCall();
}
void DBImpl::BackgroundCall() {
MutexLock l(&mutex_);
assert(background_compaction_scheduled_);
if (shutting_down_.load(std::memory_order_acquire)) {
// No more background work when shutting down.
} else if (!bg_error_.ok()) {
// No more background work after a background error.
} else {
BackgroundCompaction();
}
background_compaction_scheduled_ = false;
// Previous compaction may have produced too many files in a level,
// so reschedule another compaction if needed.
MaybeScheduleCompaction();
background_work_finished_signal_.SignalAll();
}
void DBImpl::BackgroundCompaction() {
mutex_.AssertHeld();
if (imm_ != nullptr) {
CompactMemTable();
return;
}
Compaction* c;
bool is_manual = (manual_compaction_ != nullptr);
InternalKey manual_end;
if (is_manual) {
ManualCompaction* m = manual_compaction_;
c = versions_->CompactRange(m->level, m->begin, m->end);
m->done = (c == nullptr);
if (c != nullptr) {
manual_end = c->input(0, c->num_input_files(0) - 1)->largest;
}
Log(options_.info_log,
"Manual compaction at level-%d from %s .. %s; will stop at %s\n",
m->level, (m->begin ? m->begin->DebugString().c_str() : "(begin)"),
(m->end ? m->end->DebugString().c_str() : "(end)"),
(m->done ? "(end)" : manual_end.DebugString().c_str()));
} else {
c = versions_->PickCompaction();
}
Status status;
if (c == nullptr) {
// Nothing to do
} else if (!is_manual && c->IsTrivialMove()) {
// Move file to next level
assert(c->num_input_files(0) == 1);
FileMetaData* f = c->input(0, 0);
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_);
if (!status.ok()) {
RecordBackgroundError(status);
}
VersionSet::LevelSummaryStorage tmp;
Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n",
static_cast<unsigned long long>(f->number), c->level() + 1,
static_cast<unsigned long long>(f->file_size),
status.ToString().c_str(), versions_->LevelSummary(&tmp));
} else {
CompactionState* compact = new CompactionState(c);
status = DoCompactionWork(compact);
if (!status.ok()) {
RecordBackgroundError(status);
}
CleanupCompaction(compact);
c->ReleaseInputs();
RemoveObsoleteFiles();
}
delete c;
if (status.ok()) {
// Done
} else if (shutting_down_.load(std::memory_order_acquire)) {
// Ignore compaction errors found during shutting down
} else {
Log(options_.info_log, "Compaction error: %s", status.ToString().c_str());
}
if (is_manual) {
ManualCompaction* m = manual_compaction_;
if (!status.ok()) {
m->done = true;
}
if (!m->done) {
// We only compacted part of the requested range. Update *m
// to the range that is left to be compacted.
m->tmp_storage = manual_end;
m->begin = &m->tmp_storage;
}
manual_compaction_ = nullptr;
}
}
void DBImpl::CleanupCompaction(CompactionState* compact) {
mutex_.AssertHeld();
if (compact->builder != nullptr) {
// May happen if we get a shutdown call in the middle of compaction
compact->builder->Abandon();
delete compact->builder;
} else {
assert(compact->outfile == nullptr);
}
delete compact->outfile;
for (size_t i = 0; i < compact->outputs.size(); i++) {
const CompactionState::Output& out = compact->outputs[i];
pending_outputs_.erase(out.number);
}
delete compact;
}
Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) {
assert(compact != nullptr);
assert(compact->builder == nullptr);
uint64_t file_number;
{
mutex_.Lock();
file_number = versions_->NewFileNumber();
pending_outputs_.insert(file_number);
CompactionState::Output out;
out.number = file_number;
out.smallest.Clear();
out.largest.Clear();
compact->outputs.push_back(out);
mutex_.Unlock();
}
// Make the output file
std::string fname = TableFileName(dbname_, file_number);
Status s = env_->NewWritableFile(fname, &compact->outfile);
if (s.ok()) {
compact->builder = new TableBuilder(options_, compact->outfile);
}
return s;
}
Status DBImpl::FinishCompactionOutputFile(CompactionState* compact,
Iterator* input) {
assert(compact != nullptr);
assert(compact->outfile != nullptr);
assert(compact->builder != nullptr);
const uint64_t output_number = compact->current_output()->number;
assert(output_number != 0);
// Check for iterator errors
Status s = input->status();
const uint64_t current_entries = compact->builder->NumEntries();
if (s.ok()) {
s = compact->builder->Finish();
} else {
compact->builder->Abandon();
}
const uint64_t current_bytes = compact->builder->FileSize();
compact->current_output()->file_size = current_bytes;
compact->total_bytes += current_bytes;
delete compact->builder;
compact->builder = nullptr;
// Finish and check for file errors
if (s.ok()) {
s = compact->outfile->Sync();
}
if (s.ok()) {
s = compact->outfile->Close();
}
delete compact->outfile;
compact->outfile = nullptr;
if (s.ok() && current_entries > 0) {
// Verify that the table is usable
Iterator* iter =
table_cache_->NewIterator(ReadOptions(), output_number, current_bytes);
s = iter->status();
delete iter;
if (s.ok()) {
Log(options_.info_log, "Generated table #%llu@%d: %lld keys, %lld bytes",
(unsigned long long)output_number, compact->compaction->level(),
(unsigned long long)current_entries,
(unsigned long long)current_bytes);
}
}
return s;
}
Status DBImpl::InstallCompactionResults(CompactionState* compact) {
mutex_.AssertHeld();
Log(options_.info_log, "Compacted %d@%d + %d@%d files => %lld bytes",
compact->compaction->num_input_files(0), compact->compaction->level(),
compact->compaction->num_input_files(1), compact->compaction->level() + 1,
static_cast<long long>(compact->total_bytes));
// Add compaction outputs
compact->compaction->AddInputDeletions(compact->compaction->edit());
const int level = compact->compaction->level();
for (size_t i = 0; i < compact->outputs.size(); i++) {
const CompactionState::Output& out = compact->outputs[i];
compact->compaction->edit()->AddFile(level + 1, out.number, out.file_size,
out.smallest, out.largest);
}
return versions_->LogAndApply(compact->compaction->edit(), &mutex_);
}
Status DBImpl::DoCompactionWork(CompactionState* compact) {
const uint64_t start_micros = env_->NowMicros();
int64_t imm_micros = 0; // Micros spent doing imm_ compactions
Log(options_.info_log, "Compacting %d@%d + %d@%d files",
compact->compaction->num_input_files(0), compact->compaction->level(),
compact->compaction->num_input_files(1),
compact->compaction->level() + 1);
assert(versions_->NumLevelFiles(compact->compaction->level()) > 0);
assert(compact->builder == nullptr);
assert(compact->outfile == nullptr);
if (snapshots_.empty()) {
compact->smallest_snapshot = versions_->LastSequence();
} else {
compact->smallest_snapshot = snapshots_.oldest()->sequence_number();
}
Iterator* input = versions_->MakeInputIterator(compact->compaction);
// Release mutex while we're actually doing the compaction work
mutex_.Unlock();
input->SeekToFirst();
Status status;
ParsedInternalKey ikey;
std::string current_user_key;
bool has_current_user_key = false;
SequenceNumber last_sequence_for_key = kMaxSequenceNumber;
while (input->Valid() && !shutting_down_.load(std::memory_order_acquire)) {
// Prioritize immutable compaction work
if (has_imm_.load(std::memory_order_relaxed)) {
const uint64_t imm_start = env_->NowMicros();
mutex_.Lock();
if (imm_ != nullptr) {
CompactMemTable();
// Wake up MakeRoomForWrite() if necessary.
background_work_finished_signal_.SignalAll();
}
mutex_.Unlock();
imm_micros += (env_->NowMicros() - imm_start);
}
Slice key = input->key();
if (compact->compaction->ShouldStopBefore(key) &&
compact->builder != nullptr) {
status = FinishCompactionOutputFile(compact, input);
if (!status.ok()) {
break;
}
}
// Handle key/value, add to state, etc.
bool drop = false;
if (!ParseInternalKey(key, &ikey)) {
// Do not hide error keys
current_user_key.clear();
has_current_user_key = false;
last_sequence_for_key = kMaxSequenceNumber;
} else {
if (!has_current_user_key ||
user_comparator()->Compare(ikey.user_key, Slice(current_user_key)) !=
0) {
// First occurrence of this user key
current_user_key.assign(ikey.user_key.data(), ikey.user_key.size());
has_current_user_key = true;
last_sequence_for_key = kMaxSequenceNumber;
}
if (last_sequence_for_key <= compact->smallest_snapshot) {
// Hidden by an newer entry for same user key
drop = true; // (A)
} else if (ikey.type == kTypeDeletion &&
ikey.sequence <= compact->smallest_snapshot &&
compact->compaction->IsBaseLevelForKey(ikey.user_key)) {
// For this user key:
// (1) there is no data in higher levels
// (2) data in lower levels will have larger sequence numbers
// (3) data in layers that are being compacted here and have
// smaller sequence numbers will be dropped in the next
// few iterations of this loop (by rule (A) above).
// Therefore this deletion marker is obsolete and can be dropped.
drop = true;
}
last_sequence_for_key = ikey.sequence;
}
#if 0
Log(options_.info_log,
" Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, "
"%d smallest_snapshot: %d",
ikey.user_key.ToString().c_str(),
(int)ikey.sequence, ikey.type, kTypeValue, drop,
compact->compaction->IsBaseLevelForKey(ikey.user_key),
(int)last_sequence_for_key, (int)compact->smallest_snapshot);
#endif
if (!drop) {
// Open output file if necessary
if (compact->builder == nullptr) {
status = OpenCompactionOutputFile(compact);
if (!status.ok()) {
break;
}
}
if (compact->builder->NumEntries() == 0) {
compact->current_output()->smallest.DecodeFrom(key);
}
compact->current_output()->largest.DecodeFrom(key);
compact->builder->Add(key, input->value());
// Close output file if it is big enough
if (compact->builder->FileSize() >=
compact->compaction->MaxOutputFileSize()) {
status = FinishCompactionOutputFile(compact, input);
if (!status.ok()) {
break;
}
}
}
input->Next();
}
if (status.ok() && shutting_down_.load(std::memory_order_acquire)) {
status = Status::IOError("Deleting DB during compaction");
}
if (status.ok() && compact->builder != nullptr) {
status = FinishCompactionOutputFile(compact, input);
}
if (status.ok()) {
status = input->status();
}
delete input;
input = nullptr;
CompactionStats stats;
stats.micros = env_->NowMicros() - start_micros - imm_micros;
for (int which = 0; which < 2; which++) {
for (int i = 0; i < compact->compaction->num_input_files(which); i++) {
stats.bytes_read += compact->compaction->input(which, i)->file_size;
}
}
for (size_t i = 0; i < compact->outputs.size(); i++) {
stats.bytes_written += compact->outputs[i].file_size;
}
mutex_.Lock();
stats_[compact->compaction->level() + 1].Add(stats);
if (status.ok()) {
status = InstallCompactionResults(compact);
}
if (!status.ok()) {
RecordBackgroundError(status);
}
VersionSet::LevelSummaryStorage tmp;
Log(options_.info_log, "compacted to: %s", versions_->LevelSummary(&tmp));
return status;
}
namespace {
struct IterState {
port::Mutex* const mu;
Version* const version GUARDED_BY(mu);
MemTable* const mem GUARDED_BY(mu);
MemTable* const imm GUARDED_BY(mu);
IterState(port::Mutex* mutex, MemTable* mem, MemTable* imm, Version* version)
: mu(mutex), version(version), mem(mem), imm(imm) {}
};
static void CleanupIteratorState(void* arg1, void* arg2) {
IterState* state = reinterpret_cast<IterState*>(arg1);
state->mu->Lock();
state->mem->Unref();
if (state->imm != nullptr) state->imm->Unref();
state->version->Unref();
state->mu->Unlock();
delete state;
}
} // anonymous namespace
Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,
SequenceNumber* latest_snapshot,
uint32_t* seed) {
mutex_.Lock();
*latest_snapshot = versions_->LastSequence();
// Collect together all needed child iterators
std::vector<Iterator*> list;
list.push_back(mem_->NewIterator());
mem_->Ref();
if (imm_ != nullptr) {
list.push_back(imm_->NewIterator());
imm_->Ref();
}
versions_->current()->AddIterators(options, &list);
Iterator* internal_iter =
NewMergingIterator(&internal_comparator_, &list[0], list.size());
versions_->current()->Ref();
IterState* cleanup = new IterState(&mutex_, mem_, imm_, versions_->current());
internal_iter->RegisterCleanup(CleanupIteratorState, cleanup, nullptr);
*seed = ++seed_;
mutex_.Unlock();
return internal_iter;
}
Iterator* DBImpl::TEST_NewInternalIterator() {
SequenceNumber ignored;
uint32_t ignored_seed;
return NewInternalIterator(ReadOptions(), &ignored, &ignored_seed);
}
int64_t DBImpl::TEST_MaxNextLevelOverlappingBytes() {
MutexLock l(&mutex_);
return versions_->MaxNextLevelOverlappingBytes();
}
Status DBImpl::Get(const ReadOptions& options, const Slice& key,
std::string* value) {
Status s;
MutexLock l(&mutex_);
SequenceNumber snapshot;
if (options.snapshot != nullptr) {
snapshot =
static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();
} else {
snapshot = versions_->LastSequence();
}
MemTable* mem = mem_;
MemTable* imm = imm_;
Version* current = versions_->current();
mem->Ref();
if (imm != nullptr) imm->Ref();
current->Ref();
bool have_stat_update = false;
Version::GetStats stats;
// Unlock while reading from files and memtables
{
mutex_.Unlock();
// First look in the memtable, then in the immutable memtable (if any).
LookupKey lkey(key, snapshot);
if (mem->Get(lkey, value, &s)) {
// Done
} else if (imm != nullptr && imm->Get(lkey, value, &s)) {
// Done
} else {
s = current->Get(options, lkey, value, &stats);
have_stat_update = true;
}
mutex_.Lock();
}
if (have_stat_update && current->UpdateStats(stats)) {
MaybeScheduleCompaction();
}
mem->Unref();
if (imm != nullptr) imm->Unref();
current->Unref();
return s;
}
Iterator* DBImpl::NewIterator(const ReadOptions& options) {
SequenceNumber latest_snapshot;
uint32_t seed;
Iterator* iter = NewInternalIterator(options, &latest_snapshot, &seed);
return NewDBIterator(this, user_comparator(), iter,
(options.snapshot != nullptr
? static_cast<const SnapshotImpl*>(options.snapshot)
->sequence_number()
: latest_snapshot),
seed);
}
void DBImpl::RecordReadSample(Slice key) {
MutexLock l(&mutex_);
if (versions_->current()->RecordReadSample(key)) {
MaybeScheduleCompaction();
}
}
const Snapshot* DBImpl::GetSnapshot() {
MutexLock l(&mutex_);
return snapshots_.New(versions_->LastSequence());
}
void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) {
MutexLock l(&mutex_);
snapshots_.Delete(static_cast<const SnapshotImpl*>(snapshot));
}
// Convenience methods
Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) {
return DB::Put(o, key, val);
}
Status DBImpl::Delete(const WriteOptions& options, const Slice& key) {
return DB::Delete(options, key);
}
Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
Writer w(&mutex_);
w.batch = updates;
w.sync = options.sync;
w.done = false;
MutexLock l(&mutex_);
writers_.push_back(&w);
while (!w.done && &w != writers_.front()) {
w.cv.Wait();
}
if (w.done) {
return w.status;
}
// May temporarily unlock and wait.
Status status = MakeRoomForWrite(updates == nullptr);
uint64_t last_sequence = versions_->LastSequence();
Writer* last_writer = &w;
if (status.ok() && updates != nullptr) { // nullptr batch is for compactions
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
// and protects against concurrent loggers and concurrent writes
// into mem_.
{
mutex_.Unlock();
status = log_->AddRecord(WriteBatchInternal::Contents(write_batch));
bool sync_error = false;
if (status.ok() && options.sync) {
status = logfile_->Sync();
if (!status.ok()) {
sync_error = true;
}
}
if (status.ok()) {
status = WriteBatchInternal::InsertInto(write_batch, mem_);
}
mutex_.Lock();
if (sync_error) {
// The state of the log file is indeterminate: the log record we
// just added may or may not show up when the DB is re-opened.
// So we force the DB into a mode where all future writes fail.
RecordBackgroundError(status);
}
}
if (write_batch == tmp_batch_) tmp_batch_->Clear();
versions_->SetLastSequence(last_sequence);
}
while (true) {
Writer* ready = writers_.front();
writers_.pop_front();
if (ready != &w) {
ready->status = status;
ready->done = true;
ready->cv.Signal();
}
if (ready == last_writer) break;
}
// Notify new head of write queue
if (!writers_.empty()) {
writers_.front()->cv.Signal();
}
return status;
}
// REQUIRES: Writer list must be non-empty
// REQUIRES: First writer must have a non-null batch
WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {
mutex_.AssertHeld();
assert(!writers_.empty());
Writer* first = writers_.front();
WriteBatch* result = first->batch;
assert(resul
gitextract_rc7lvmbf/
├── .clang-format
├── .github/
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .gitmodules
├── AUTHORS
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── NEWS
├── README.md
├── TODO
├── benchmarks/
│ ├── db_bench.cc
│ ├── db_bench_log.cc
│ ├── db_bench_sqlite3.cc
│ └── db_bench_tree_db.cc
├── cmake/
│ └── leveldbConfig.cmake.in
├── db/
│ ├── autocompact_test.cc
│ ├── builder.cc
│ ├── builder.h
│ ├── c.cc
│ ├── c_test.c
│ ├── corruption_test.cc
│ ├── db_impl.cc
│ ├── db_impl.h
│ ├── db_iter.cc
│ ├── db_iter.h
│ ├── db_test.cc
│ ├── dbformat.cc
│ ├── dbformat.h
│ ├── dbformat_test.cc
│ ├── dumpfile.cc
│ ├── fault_injection_test.cc
│ ├── filename.cc
│ ├── filename.h
│ ├── filename_test.cc
│ ├── leveldbutil.cc
│ ├── log_format.h
│ ├── log_reader.cc
│ ├── log_reader.h
│ ├── log_test.cc
│ ├── log_writer.cc
│ ├── log_writer.h
│ ├── memtable.cc
│ ├── memtable.h
│ ├── recovery_test.cc
│ ├── repair.cc
│ ├── skiplist.h
│ ├── skiplist_test.cc
│ ├── snapshot.h
│ ├── table_cache.cc
│ ├── table_cache.h
│ ├── version_edit.cc
│ ├── version_edit.h
│ ├── version_edit_test.cc
│ ├── version_set.cc
│ ├── version_set.h
│ ├── version_set_test.cc
│ ├── write_batch.cc
│ ├── write_batch_internal.h
│ └── write_batch_test.cc
├── doc/
│ ├── benchmark.html
│ ├── impl.md
│ ├── index.md
│ ├── log_format.md
│ └── table_format.md
├── helpers/
│ └── memenv/
│ ├── memenv.cc
│ ├── memenv.h
│ └── memenv_test.cc
├── include/
│ └── leveldb/
│ ├── c.h
│ ├── cache.h
│ ├── comparator.h
│ ├── db.h
│ ├── dumpfile.h
│ ├── env.h
│ ├── export.h
│ ├── filter_policy.h
│ ├── iterator.h
│ ├── options.h
│ ├── slice.h
│ ├── status.h
│ ├── table.h
│ ├── table_builder.h
│ └── write_batch.h
├── issues/
│ ├── issue178_test.cc
│ ├── issue200_test.cc
│ └── issue320_test.cc
├── port/
│ ├── README.md
│ ├── port.h
│ ├── port_config.h.in
│ ├── port_example.h
│ ├── port_stdcxx.h
│ └── thread_annotations.h
├── table/
│ ├── block.cc
│ ├── block.h
│ ├── block_builder.cc
│ ├── block_builder.h
│ ├── filter_block.cc
│ ├── filter_block.h
│ ├── filter_block_test.cc
│ ├── format.cc
│ ├── format.h
│ ├── iterator.cc
│ ├── iterator_wrapper.h
│ ├── merger.cc
│ ├── merger.h
│ ├── table.cc
│ ├── table_builder.cc
│ ├── table_test.cc
│ ├── two_level_iterator.cc
│ └── two_level_iterator.h
└── util/
├── arena.cc
├── arena.h
├── arena_test.cc
├── bloom.cc
├── bloom_test.cc
├── cache.cc
├── cache_test.cc
├── coding.cc
├── coding.h
├── coding_test.cc
├── comparator.cc
├── crc32c.cc
├── crc32c.h
├── crc32c_test.cc
├── env.cc
├── env_posix.cc
├── env_posix_test.cc
├── env_posix_test_helper.h
├── env_test.cc
├── env_windows.cc
├── env_windows_test.cc
├── env_windows_test_helper.h
├── filter_policy.cc
├── hash.cc
├── hash.h
├── hash_test.cc
├── histogram.cc
├── histogram.h
├── logging.cc
├── logging.h
├── logging_test.cc
├── mutexlock.h
├── no_destructor.h
├── no_destructor_test.cc
├── options.cc
├── posix_logger.h
├── random.h
├── status.cc
├── status_test.cc
├── testutil.cc
├── testutil.h
└── windows_logger.h
SYMBOL INDEX (1438 symbols across 130 files)
FILE: benchmarks/db_bench.cc
type leveldb (line 132) | namespace leveldb {
class CountComparator (line 137) | class CountComparator : public Comparator {
method CountComparator (line 139) | CountComparator(const Comparator* wrapped) : wrapped_(wrapped) {}
method Compare (line 141) | int Compare(const Slice& a, const Slice& b) const override {
method FindShortestSeparator (line 146) | void FindShortestSeparator(std::string* start,
method FindShortSuccessor (line 151) | void FindShortSuccessor(std::string* key) const override {
method comparisons (line 155) | size_t comparisons() const { return count_.load(std::memory_order_re...
method reset (line 157) | void reset() { count_.store(0, std::memory_order_relaxed); }
class RandomGenerator (line 165) | class RandomGenerator {
method RandomGenerator (line 171) | RandomGenerator() {
method Slice (line 186) | Slice Generate(size_t len) {
class KeyBuffer (line 196) | class KeyBuffer {
method KeyBuffer (line 198) | KeyBuffer() {
method KeyBuffer (line 202) | KeyBuffer& operator=(KeyBuffer& other) = delete;
method KeyBuffer (line 203) | KeyBuffer(KeyBuffer& other) = delete;
method Set (line 205) | void Set(int k) {
method Slice (line 210) | Slice slice() const { return Slice(buffer_, FLAGS_key_prefix + 16); }
function Slice (line 217) | static Slice TrimSpace(Slice s) {
function AppendWithSpace (line 230) | static void AppendWithSpace(std::string* str, Slice msg) {
class Stats (line 238) | class Stats {
method Stats (line 251) | Stats() { Start(); }
method Start (line 253) | void Start() {
method Merge (line 263) | void Merge(const Stats& other) {
method Stop (line 275) | void Stop() {
method AddMessage (line 280) | void AddMessage(Slice msg) { AppendWithSpace(&message_, msg); }
method FinishedSingleOp (line 282) | void FinishedSingleOp() {
method AddBytes (line 315) | void AddBytes(int64_t n) { bytes_ += n; }
method Report (line 317) | void Report(const Slice& name) {
type SharedState (line 346) | struct SharedState {
method SharedState (line 361) | SharedState(int total)
type ThreadState (line 366) | struct ThreadState {
method ThreadState (line 372) | ThreadState(int index, int seed) : tid(index), rand(seed), shared(nu...
function Compress (line 375) | void Compress(
function Uncompress (line 402) | void Uncompress(
class Benchmark (line 428) | class Benchmark {
method PrintHeader (line 442) | void PrintHeader() {
method PrintWarnings (line 462) | void PrintWarnings() {
method PrintEnvironment (line 484) | void PrintEnvironment() {
method Benchmark (line 521) | Benchmark()
method Run (line 552) | void Run() {
type ThreadArg (line 675) | struct ThreadArg {
method ThreadBody (line 682) | static void ThreadBody(void* v) {
method RunBenchmark (line 710) | void RunBenchmark(int n, Slice name,
method Crc32c (line 756) | void Crc32c(ThreadState* thread) {
method SnappyCompress (line 775) | void SnappyCompress(ThreadState* thread) {
method SnappyUncompress (line 779) | void SnappyUncompress(ThreadState* thread) {
method ZstdCompress (line 784) | void ZstdCompress(ThreadState* thread) {
method ZstdUncompress (line 792) | void ZstdUncompress(ThreadState* thread) {
method Open (line 802) | void Open() {
method OpenBench (line 826) | void OpenBench(ThreadState* thread) {
method WriteSeq (line 834) | void WriteSeq(ThreadState* thread) { DoWrite(thread, true); }
method WriteRandom (line 836) | void WriteRandom(ThreadState* thread) { DoWrite(thread, false); }
method DoWrite (line 838) | void DoWrite(ThreadState* thread, bool seq) {
method ReadSequential (line 868) | void ReadSequential(ThreadState* thread) {
method ReadReverse (line 881) | void ReadReverse(ThreadState* thread) {
method ReadRandom (line 894) | void ReadRandom(ThreadState* thread) {
method ReadMissing (line 912) | void ReadMissing(ThreadState* thread) {
method ReadHot (line 925) | void ReadHot(ThreadState* thread) {
method SeekRandom (line 938) | void SeekRandom(ThreadState* thread) {
method SeekOrdered (line 956) | void SeekOrdered(ThreadState* thread) {
method DoDelete (line 975) | void DoDelete(ThreadState* thread, bool seq) {
method DeleteSeq (line 996) | void DeleteSeq(ThreadState* thread) { DoDelete(thread, true); }
method DeleteRandom (line 998) | void DeleteRandom(ThreadState* thread) { DoDelete(thread, false); }
method ReadWhileWriting (line 1000) | void ReadWhileWriting(ThreadState* thread) {
method Compact (line 1031) | void Compact(ThreadState* thread) { db_->CompactRange(nullptr, nullp...
method PrintStats (line 1033) | void PrintStats(const char* key) {
method WriteToFile (line 1041) | static void WriteToFile(void* arg, const char* buf, int n) {
method HeapProfile (line 1045) | void HeapProfile() {
function main (line 1066) | int main(int argc, char** argv) {
FILE: benchmarks/db_bench_log.cc
type leveldb (line 20) | namespace leveldb {
function MakeKey (line 24) | std::string MakeKey(unsigned int num) {
function BM_LogAndApply (line 30) | void BM_LogAndApply(benchmark::State& state) {
FILE: benchmarks/db_bench_sqlite3.cc
function ExecErrorCheck (line 85) | inline static void ExecErrorCheck(int status, char* err_msg) {
function StepErrorCheck (line 93) | inline static void StepErrorCheck(int status) {
function ErrorCheck (line 100) | inline static void ErrorCheck(int status) {
function WalCheckpoint (line 107) | inline static void WalCheckpoint(sqlite3* db_) {
type leveldb (line 115) | namespace leveldb {
class RandomGenerator (line 119) | class RandomGenerator {
method RandomGenerator (line 125) | RandomGenerator() {
method Slice (line 140) | Slice Generate(int len) {
function Slice (line 150) | static Slice TrimSpace(Slice s) {
class Benchmark (line 164) | class Benchmark {
method PrintHeader (line 182) | void PrintHeader() {
method PrintWarnings (line 195) | void PrintWarnings() {
method PrintEnvironment (line 208) | void PrintEnvironment() {
method Start (line 243) | void Start() {
method FinishedSingleOp (line 253) | void FinishedSingleOp() {
method Stop (line 286) | void Stop(const Slice& name) {
type Order (line 315) | enum Order { SEQUENTIAL, RANDOM }
type DBState (line 316) | enum DBState { FRESH, EXISTING }
method Benchmark (line 318) | Benchmark()
method Run (line 346) | void Run() {
method Open (line 421) | void Open() {
method Write (line 483) | void Write(bool write_sync, Order order, DBState state, int num_entr...
method Read (line 586) | void Read(Order order, int entries_per_batch) {
method ReadSequential (line 655) | void ReadSequential() {
function main (line 674) | int main(int argc, char** argv) {
FILE: benchmarks/db_bench_tree_db.cc
function DBSynchronize (line 75) | inline static void DBSynchronize(kyotocabinet::TreeDB* db_) {
type leveldb (line 82) | namespace leveldb {
class RandomGenerator (line 86) | class RandomGenerator {
method RandomGenerator (line 92) | RandomGenerator() {
method Slice (line 107) | Slice Generate(int len) {
function Slice (line 117) | static Slice TrimSpace(Slice s) {
class Benchmark (line 131) | class Benchmark {
method PrintHeader (line 150) | void PrintHeader() {
method PrintWarnings (line 170) | void PrintWarnings() {
method PrintEnvironment (line 183) | void PrintEnvironment() {
method Start (line 221) | void Start() {
method FinishedSingleOp (line 231) | void FinishedSingleOp() {
method Stop (line 264) | void Stop(const Slice& name) {
type Order (line 293) | enum Order { SEQUENTIAL, RANDOM }
type DBState (line 294) | enum DBState { FRESH, EXISTING }
method Benchmark (line 296) | Benchmark()
method Run (line 324) | void Run() {
method Open (line 395) | void Open(bool sync) {
method Write (line 428) | void Write(bool sync, Order order, DBState state, int num_entries,
method ReadSequential (line 462) | void ReadSequential() {
method ReadRandom (line 473) | void ReadRandom() {
function main (line 487) | int main(int argc, char** argv) {
FILE: db/autocompact_test.cc
type leveldb (line 11) | namespace leveldb {
class AutoCompactTest (line 13) | class AutoCompactTest : public testing::Test {
method AutoCompactTest (line 15) | AutoCompactTest() {
method Key (line 31) | std::string Key(int i) {
method Size (line 37) | uint64_t Size(const Slice& start, const Slice& limit) {
function TEST_F (line 106) | TEST_F(AutoCompactTest, ReadAll) { DoReads(kCount); }
function TEST_F (line 108) | TEST_F(AutoCompactTest, ReadHalf) { DoReads(kCount / 2); }
FILE: db/builder.cc
type leveldb (line 15) | namespace leveldb {
function Status (line 17) | Status BuildTable(const std::string& dbname, Env* env, const Options& ...
FILE: db/builder.h
function namespace (line 10) | namespace leveldb {
FILE: db/c.cc
type leveldb_t (line 49) | struct leveldb_t {
type leveldb_iterator_t (line 52) | struct leveldb_iterator_t {
type leveldb_writebatch_t (line 55) | struct leveldb_writebatch_t {
type leveldb_snapshot_t (line 58) | struct leveldb_snapshot_t {
type leveldb_readoptions_t (line 61) | struct leveldb_readoptions_t {
type leveldb_writeoptions_t (line 64) | struct leveldb_writeoptions_t {
type leveldb_options_t (line 67) | struct leveldb_options_t {
type leveldb_cache_t (line 70) | struct leveldb_cache_t {
type leveldb_seqfile_t (line 73) | struct leveldb_seqfile_t {
type leveldb_randomfile_t (line 76) | struct leveldb_randomfile_t {
type leveldb_writablefile_t (line 79) | struct leveldb_writablefile_t {
type leveldb_logger_t (line 82) | struct leveldb_logger_t {
type leveldb_filelock_t (line 85) | struct leveldb_filelock_t {
type leveldb_comparator_t (line 89) | struct leveldb_comparator_t : public Comparator {
method Compare (line 92) | int Compare(const Slice& a, const Slice& b) const override {
method FindShortestSeparator (line 99) | void FindShortestSeparator(std::string*, const Slice&) const override {}
method FindShortSuccessor (line 100) | void FindShortSuccessor(std::string* key) const override {}
type leveldb_filterpolicy_t (line 109) | struct leveldb_filterpolicy_t : public FilterPolicy {
method CreateFilter (line 114) | void CreateFilter(const Slice* keys, int n, std::string* dst) const ov...
method KeyMayMatch (line 127) | bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
type leveldb_env_t (line 142) | struct leveldb_env_t {
function SaveError (line 147) | static bool SaveError(char** errptr, const Status& s) {
function leveldb_t (line 168) | leveldb_t* leveldb_open(const leveldb_options_t* options, const char* name,
function leveldb_close (line 179) | void leveldb_close(leveldb_t* db) {
function leveldb_put (line 184) | void leveldb_put(leveldb_t* db, const leveldb_writeoptions_t* options,
function leveldb_delete (line 191) | void leveldb_delete(leveldb_t* db, const leveldb_writeoptions_t* options,
function leveldb_write (line 196) | void leveldb_write(leveldb_t* db, const leveldb_writeoptions_t* options,
function leveldb_iterator_t (line 219) | leveldb_iterator_t* leveldb_create_iterator(
function leveldb_snapshot_t (line 226) | const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db) {
function leveldb_release_snapshot (line 232) | void leveldb_release_snapshot(leveldb_t* db,
function leveldb_approximate_sizes (line 248) | void leveldb_approximate_sizes(leveldb_t* db, int num_ranges,
function leveldb_compact_range (line 263) | void leveldb_compact_range(leveldb_t* db, const char* start_key,
function leveldb_destroy_db (line 273) | void leveldb_destroy_db(const leveldb_options_t* options, const char* name,
function leveldb_repair_db (line 278) | void leveldb_repair_db(const leveldb_options_t* options, const char* name,
function leveldb_iter_destroy (line 283) | void leveldb_iter_destroy(leveldb_iterator_t* iter) {
function leveldb_iter_valid (line 288) | uint8_t leveldb_iter_valid(const leveldb_iterator_t* iter) {
function leveldb_iter_seek_to_first (line 292) | void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) {
function leveldb_iter_seek_to_last (line 296) | void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) {
function leveldb_iter_seek (line 300) | void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t k...
function leveldb_iter_next (line 304) | void leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); }
function leveldb_iter_prev (line 306) | void leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); }
function leveldb_iter_get_error (line 320) | void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errpt...
function leveldb_writebatch_t (line 324) | leveldb_writebatch_t* leveldb_writebatch_create() {
function leveldb_writebatch_destroy (line 328) | void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; }
function leveldb_writebatch_clear (line 330) | void leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); }
function leveldb_writebatch_put (line 332) | void leveldb_writebatch_put(leveldb_writebatch_t* b, const char* key,
function leveldb_writebatch_delete (line 337) | void leveldb_writebatch_delete(leveldb_writebatch_t* b, const char* key,
function leveldb_writebatch_iterate (line 342) | void leveldb_writebatch_iterate(const leveldb_writebatch_t* b, void* state,
function leveldb_writebatch_append (line 366) | void leveldb_writebatch_append(leveldb_writebatch_t* destination,
function leveldb_options_t (line 371) | leveldb_options_t* leveldb_options_create() { return new leveldb_options...
function leveldb_options_destroy (line 373) | void leveldb_options_destroy(leveldb_options_t* options) { delete option...
function leveldb_options_set_comparator (line 375) | void leveldb_options_set_comparator(leveldb_options_t* opt,
function leveldb_options_set_filter_policy (line 380) | void leveldb_options_set_filter_policy(leveldb_options_t* opt,
function leveldb_options_set_create_if_missing (line 385) | void leveldb_options_set_create_if_missing(leveldb_options_t* opt, uint8...
function leveldb_options_set_error_if_exists (line 389) | void leveldb_options_set_error_if_exists(leveldb_options_t* opt, uint8_t...
function leveldb_options_set_paranoid_checks (line 393) | void leveldb_options_set_paranoid_checks(leveldb_options_t* opt, uint8_t...
function leveldb_options_set_env (line 397) | void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) {
function leveldb_options_set_info_log (line 401) | void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger...
function leveldb_options_set_write_buffer_size (line 405) | void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_...
function leveldb_options_set_max_open_files (line 409) | void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) {
function leveldb_options_set_cache (line 413) | void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* ...
function leveldb_options_set_block_size (line 417) | void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) {
function leveldb_options_set_block_restart_interval (line 421) | void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, ...
function leveldb_options_set_max_file_size (line 425) | void leveldb_options_set_max_file_size(leveldb_options_t* opt, size_t s) {
function leveldb_options_set_compression (line 429) | void leveldb_options_set_compression(leveldb_options_t* opt, int t) {
function leveldb_comparator_t (line 433) | leveldb_comparator_t* leveldb_comparator_create(
method Compare (line 92) | int Compare(const Slice& a, const Slice& b) const override {
method FindShortestSeparator (line 99) | void FindShortestSeparator(std::string*, const Slice&) const override {}
method FindShortSuccessor (line 100) | void FindShortSuccessor(std::string* key) const override {}
function leveldb_comparator_destroy (line 446) | void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; }
function leveldb_filterpolicy_t (line 448) | leveldb_filterpolicy_t* leveldb_filterpolicy_create(
method CreateFilter (line 114) | void CreateFilter(const Slice* keys, int n, std::string* dst) const ov...
method KeyMayMatch (line 127) | bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
function leveldb_filterpolicy_destroy (line 465) | void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) {
function leveldb_filterpolicy_t (line 469) | leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_k...
method CreateFilter (line 114) | void CreateFilter(const Slice* keys, int n, std::string* dst) const ov...
method KeyMayMatch (line 127) | bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
function leveldb_readoptions_t (line 494) | leveldb_readoptions_t* leveldb_readoptions_create() {
function leveldb_readoptions_destroy (line 498) | void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete op...
function leveldb_readoptions_set_verify_checksums (line 500) | void leveldb_readoptions_set_verify_checksums(leveldb_readoptions_t* opt,
function leveldb_readoptions_set_fill_cache (line 505) | void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t* opt, uint...
function leveldb_readoptions_set_snapshot (line 509) | void leveldb_readoptions_set_snapshot(leveldb_readoptions_t* opt,
function leveldb_writeoptions_t (line 514) | leveldb_writeoptions_t* leveldb_writeoptions_create() {
function leveldb_writeoptions_destroy (line 518) | void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete ...
function leveldb_writeoptions_set_sync (line 520) | void leveldb_writeoptions_set_sync(leveldb_writeoptions_t* opt, uint8_t ...
function leveldb_cache_t (line 524) | leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) {
function leveldb_cache_destroy (line 530) | void leveldb_cache_destroy(leveldb_cache_t* cache) {
function leveldb_env_t (line 535) | leveldb_env_t* leveldb_create_default_env() {
function leveldb_env_destroy (line 542) | void leveldb_env_destroy(leveldb_env_t* env) {
function leveldb_free (line 559) | void leveldb_free(void* ptr) { std::free(ptr); }
function leveldb_major_version (line 561) | int leveldb_major_version() { return kMajorVersion; }
function leveldb_minor_version (line 563) | int leveldb_minor_version() { return kMinorVersion; }
FILE: db/c_test.c
function StartPhase (line 14) | static void StartPhase(const char* name) {
function CheckEqual (line 31) | static void CheckEqual(const char* expected, const char* v, size_t n) {
function Free (line 47) | static void Free(char** ptr) {
function CheckGet (line 54) | static void CheckGet(
function CheckIter (line 68) | static void CheckIter(leveldb_iterator_t* iter,
function CheckPut (line 79) | static void CheckPut(void* ptr,
function CheckDel (line 98) | static void CheckDel(void* ptr, const char* k, size_t klen) {
function CmpDestroy (line 105) | static void CmpDestroy(void* arg) { }
function CmpCompare (line 107) | static int CmpCompare(void* arg, const char* a, size_t alen,
function FilterDestroy (line 124) | static void FilterDestroy(void* arg) { }
function FilterKeyMatch (line 138) | uint8_t FilterKeyMatch(void* arg, const char* key, size_t length,
function main (line 145) | int main(int argc, char** argv) {
FILE: db/corruption_test.cc
type leveldb (line 19) | namespace leveldb {
class CorruptionTest (line 23) | class CorruptionTest : public testing::Test {
method CorruptionTest (line 25) | CorruptionTest()
method Status (line 43) | Status TryReopen() {
method Reopen (line 49) | void Reopen() { ASSERT_LEVELDB_OK(TryReopen()); }
method RepairDB (line 51) | void RepairDB() {
method Build (line 57) | void Build(int n) {
method Check (line 75) | void Check(int min_expected, int max_expected) {
method Corrupt (line 113) | void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
method Property (line 159) | int Property(const std::string& name) {
method Slice (line 171) | Slice Key(int i, std::string* storage) {
method Slice (line 179) | Slice Value(int k, std::string* storage) {
function TEST_F (line 193) | TEST_F(CorruptionTest, Recovery) {
function TEST_F (line 204) | TEST_F(CorruptionTest, RecoverWriteError) {
function TEST_F (line 210) | TEST_F(CorruptionTest, NewFileErrorDuringWrite) {
function TEST_F (line 227) | TEST_F(CorruptionTest, TableFile) {
function TEST_F (line 238) | TEST_F(CorruptionTest, TableFileRepair) {
function TEST_F (line 254) | TEST_F(CorruptionTest, TableFileIndexData) {
function TEST_F (line 264) | TEST_F(CorruptionTest, MissingDescriptor) {
function TEST_F (line 271) | TEST_F(CorruptionTest, SequenceNumberRecovery) {
function TEST_F (line 292) | TEST_F(CorruptionTest, CorruptedDescriptor) {
function TEST_F (line 309) | TEST_F(CorruptionTest, CompactionInputError) {
function TEST_F (line 324) | TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
function TEST_F (line 345) | TEST_F(CorruptionTest, UnrelatedKeys) {
FILE: db/db_impl.cc
type leveldb (line 38) | namespace leveldb {
type DBImpl::Writer (line 43) | struct DBImpl::Writer {
method Writer (line 44) | explicit Writer(port::Mutex* mu)
type DBImpl::CompactionState (line 54) | struct DBImpl::CompactionState {
type Output (line 56) | struct Output {
method Output (line 62) | Output* current_output() { return &outputs[outputs.size() - 1]; }
method CompactionState (line 64) | explicit CompactionState(Compaction* c)
function ClipToRange (line 90) | static void ClipToRange(T* ptr, V minvalue, V maxvalue) {
function Options (line 94) | Options SanitizeOptions(const std::string& dbname,
function TableCacheSize (line 121) | static int TableCacheSize(const Options& sanitized_options) {
function Status (line 181) | Status DBImpl::NewDB() {
function Status (line 292) | Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
function Status (line 385) | Status DBImpl::RecoverLogFile(uint64_t log_number, bool last_log,
function Status (line 505) | Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit,
function Status (line 643) | Status DBImpl::TEST_CompactMemTable() {
function Status (line 806) | Status DBImpl::OpenCompactionOutputFile(CompactionState* compact) {
function Status (line 831) | Status DBImpl::FinishCompactionOutputFile(CompactionState* compact,
function Status (line 880) | Status DBImpl::InstallCompactionResults(CompactionState* compact) {
function Status (line 898) | Status DBImpl::DoCompactionWork(CompactionState* compact) {
type IterState (line 1061) | struct IterState {
method IterState (line 1067) | IterState(port::Mutex* mutex, MemTable* mem, MemTable* imm, Version*...
function CleanupIteratorState (line 1071) | static void CleanupIteratorState(void* arg1, void* arg2) {
function Iterator (line 1083) | Iterator* DBImpl::NewInternalIterator(const ReadOptions& options,
function Iterator (line 1110) | Iterator* DBImpl::TEST_NewInternalIterator() {
function Status (line 1121) | Status DBImpl::Get(const ReadOptions& options, const Slice& key,
function Iterator (line 1168) | Iterator* DBImpl::NewIterator(const ReadOptions& options) {
function Snapshot (line 1187) | const Snapshot* DBImpl::GetSnapshot() {
function Status (line 1198) | Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slic...
function Status (line 1202) | Status DBImpl::Delete(const WriteOptions& options, const Slice& key) {
function Status (line 1206) | Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) {
function WriteBatch (line 1281) | WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {
function Status (line 1331) | Status DBImpl::MakeRoomForWrite(bool force) {
function Status (line 1489) | Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice&...
function Status (line 1495) | Status DB::Delete(const WriteOptions& opt, const Slice& key) {
function Status (line 1503) | Status DB::Open(const Options& options, const std::string& dbname, DB*...
function Status (line 1548) | Status DestroyDB(const std::string& dbname, const Options& options) {
FILE: db/db_impl.h
function namespace (line 21) | namespace leveldb {
FILE: db/db_iter.cc
type leveldb (line 17) | namespace leveldb {
function DumpInternalIter (line 20) | static void DumpInternalIter(Iterator* iter) {
class DBIter (line 39) | class DBIter : public Iterator {
type Direction (line 46) | enum Direction { kForward, kReverse }
method DBIter (line 48) | DBIter(DBImpl* db, const Comparator* cmp, Iterator* iter, SequenceNu...
method DBIter (line 59) | DBIter(const DBIter&) = delete;
method DBIter (line 60) | DBIter& operator=(const DBIter&) = delete;
method Valid (line 63) | bool Valid() const override { return valid_; }
method Slice (line 64) | Slice key() const override {
method Slice (line 68) | Slice value() const override {
method Status (line 72) | Status status() const override {
method SaveKey (line 91) | inline void SaveKey(const Slice& k, std::string* dst) {
method ClearSavedValue (line 95) | inline void ClearSavedValue() {
method RandomCompactionPeriod (line 105) | size_t RandomCompactionPeriod() {
function Iterator (line 312) | Iterator* NewDBIterator(DBImpl* db, const Comparator* user_key_compara...
FILE: db/db_iter.h
function namespace (line 13) | namespace leveldb {
FILE: db/db_test.cc
type leveldb (line 27) | namespace leveldb {
function RandomString (line 29) | static std::string RandomString(Random* rnd, int len) {
function RandomKey (line 35) | static std::string RandomKey(Random* rnd) {
class AtomicCounter (line 43) | class AtomicCounter {
method AtomicCounter (line 45) | AtomicCounter() : count_(0) {}
method Increment (line 46) | void Increment() { IncrementBy(1); }
method LOCKS_EXCLUDED (line 47) | LOCKS_EXCLUDED(mu_) {
method LOCKS_EXCLUDED (line 51) | int Read() LOCKS_EXCLUDED(mu_) {
method LOCKS_EXCLUDED (line 55) | void Reset() LOCKS_EXCLUDED(mu_) {
function DelayMilliseconds (line 65) | void DelayMilliseconds(int millis) {
function IsLdbFile (line 69) | bool IsLdbFile(const std::string& f) {
function IsLogFile (line 73) | bool IsLogFile(const std::string& f) {
function IsManifestFile (line 77) | bool IsManifestFile(const std::string& f) {
class TestEnv (line 84) | class TestEnv : public EnvWrapper {
method TestEnv (line 86) | explicit TestEnv(Env* base) : EnvWrapper(base), ignore_dot_files_(fa...
method SetIgnoreDotFiles (line 88) | void SetIgnoreDotFiles(bool ignored) { ignore_dot_files_ = ignored; }
method Status (line 90) | Status GetChildren(const std::string& dir,
class SpecialEnv (line 114) | class SpecialEnv : public EnvWrapper {
method SpecialEnv (line 144) | explicit SpecialEnv(Env* base)
method Status (line 155) | Status NewWritableFile(const std::string& f, WritableFile** r) {
method Status (line 235) | Status NewRandomAccessFile(const std::string& f, RandomAccessFile** ...
class DBTest (line 260) | class DBTest : public testing::Test {
method DBTest (line 268) | DBTest() : env_(new SpecialEnv(Env::Default())), option_config_(kDef...
method ChangeOptions (line 285) | bool ChangeOptions() {
method Options (line 296) | Options CurrentOptions() {
method DBImpl (line 315) | DBImpl* dbfull() { return reinterpret_cast<DBImpl*>(db_); }
method Reopen (line 317) | void Reopen(Options* options = nullptr) {
method Close (line 321) | void Close() {
method DestroyAndReopen (line 326) | void DestroyAndReopen(Options* options = nullptr) {
method Status (line 333) | Status TryReopen(Options* options) {
method Status (line 348) | Status Put(const std::string& k, const std::string& v) {
method Status (line 352) | Status Delete(const std::string& k) { return db_->Delete(WriteOption...
method Get (line 354) | std::string Get(const std::string& k, const Snapshot* snapshot = nul...
method Contents (line 369) | std::string Contents() {
method AllEntriesFor (line 394) | std::string AllEntriesFor(const Slice& user_key) {
method NumTableFilesAtLevel (line 436) | int NumTableFilesAtLevel(int level) {
method TotalTableFiles (line 443) | int TotalTableFiles() {
method FilesPerLevel (line 452) | std::string FilesPerLevel() {
method CountFiles (line 468) | int CountFiles() {
method Size (line 474) | uint64_t Size(const Slice& start, const Slice& limit) {
method Compact (line 481) | void Compact(const Slice& start, const Slice& limit) {
method MakeTables (line 487) | void MakeTables(int n, const std::string& small_key,
method FillLevels (line 498) | void FillLevels(const std::string& smallest, const std::string& larg...
method DumpFileCounts (line 502) | void DumpFileCounts(const char* label) {
method DumpSSTableList (line 515) | std::string DumpSSTableList() {
method IterStatus (line 521) | std::string IterStatus(Iterator* iter) {
method DeleteAnSSTFile (line 531) | bool DeleteAnSSTFile() {
method RenameLDBToSST (line 546) | int RenameLDBToSST() {
type OptionConfig (line 565) | enum OptionConfig { kDefault, kReuse, kFilter, kUncompressed, kEnd }
function TEST_F (line 571) | TEST_F(DBTest, Empty) {
function TEST_F (line 578) | TEST_F(DBTest, EmptyKey) {
function TEST_F (line 587) | TEST_F(DBTest, EmptyValue) {
function TEST_F (line 598) | TEST_F(DBTest, ReadWrite) {
function TEST_F (line 609) | TEST_F(DBTest, PutDeleteGet) {
function TEST_F (line 620) | TEST_F(DBTest, GetFromImmutableLayer) {
function TEST_F (line 640) | TEST_F(DBTest, GetFromVersions) {
function TEST_F (line 648) | TEST_F(DBTest, GetMemUsage) {
function TEST_F (line 659) | TEST_F(DBTest, GetSnapshot) {
function TEST_F (line 677) | TEST_F(DBTest, GetIdenticalSnapshots) {
function TEST_F (line 702) | TEST_F(DBTest, IterateOverEmptySnapshot) {
function TEST_F (line 726) | TEST_F(DBTest, GetLevel0Ordering) {
function TEST_F (line 741) | TEST_F(DBTest, GetOrderedByLevels) {
function TEST_F (line 753) | TEST_F(DBTest, GetPicksCorrectFile) {
function TEST_F (line 768) | TEST_F(DBTest, GetEncountersEmptyLevel) {
function TEST_F (line 806) | TEST_F(DBTest, IterEmpty) {
function TEST_F (line 821) | TEST_F(DBTest, IterSingle) {
function TEST_F (line 859) | TEST_F(DBTest, IterMulti) {
function TEST_F (line 942) | TEST_F(DBTest, IterSmallAndLargeMix) {
function TEST_F (line 980) | TEST_F(DBTest, IterMultiWithDelete) {
function TEST_F (line 997) | TEST_F(DBTest, IterMultiWithDeleteAndCompaction) {
function TEST_F (line 1017) | TEST_F(DBTest, Recover) {
function TEST_F (line 1039) | TEST_F(DBTest, RecoveryWithEmptyLog) {
function TEST_F (line 1053) | TEST_F(DBTest, RecoverDuringMemtableCompaction) {
function Key (line 1076) | static std::string Key(int i) {
function TEST_F (line 1082) | TEST_F(DBTest, MinorCompactionsHappen) {
function TEST_F (line 1107) | TEST_F(DBTest, RecoverWithLargeLog) {
function TEST_F (line 1131) | TEST_F(DBTest, CompactionsGenerateMultipleFiles) {
function TEST_F (line 1157) | TEST_F(DBTest, RepeatedWritesToSameKey) {
function TEST_F (line 1176) | TEST_F(DBTest, SparseMerge) {
function Between (line 1216) | static bool Between(uint64_t val, uint64_t low, uint64_t high) {
function TEST_F (line 1226) | TEST_F(DBTest, ApproximateSizes) {
function TEST_F (line 1285) | TEST_F(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
function TEST_F (line 1328) | TEST_F(DBTest, IteratorPinsRef) {
function TEST_F (line 1351) | TEST_F(DBTest, Snapshot) {
function TEST_F (line 1380) | TEST_F(DBTest, HiddenValuesAreRemoved) {
function TEST_F (line 1411) | TEST_F(DBTest, DeletionMarkers1) {
function TEST_F (line 1440) | TEST_F(DBTest, DeletionMarkers2) {
function TEST_F (line 1466) | TEST_F(DBTest, OverlapInLevel0) {
function TEST_F (line 1508) | TEST_F(DBTest, L0_CompactionBug_Issue44_a) {
function TEST_F (line 1525) | TEST_F(DBTest, L0_CompactionBug_Issue44_b) {
function TEST_F (line 1551) | TEST_F(DBTest, Fflush_Issue474) {
function TEST_F (line 1560) | TEST_F(DBTest, ComparatorCheck) {
function TEST_F (line 1583) | TEST_F(DBTest, CustomComparator) {
function TEST_F (line 1639) | TEST_F(DBTest, ManualCompaction) {
function TEST_F (line 1673) | TEST_F(DBTest, DBOpen_Options) {
function TEST_F (line 1712) | TEST_F(DBTest, DestroyEmptyDir) {
function TEST_F (line 1746) | TEST_F(DBTest, DestroyOpenDB) {
function TEST_F (line 1770) | TEST_F(DBTest, Locking) {
function TEST_F (line 1777) | TEST_F(DBTest, NoSpace) {
function TEST_F (line 1797) | TEST_F(DBTest, NonWritableFileSystem) {
function TEST_F (line 1818) | TEST_F(DBTest, WriteSyncError) {
function TEST_F (line 1849) | TEST_F(DBTest, ManifestWriteError) {
function TEST_F (line 1889) | TEST_F(DBTest, MissingSSTFile) {
function TEST_F (line 1906) | TEST_F(DBTest, StillReadSST) {
function TEST_F (line 1922) | TEST_F(DBTest, FilesDeletedAfterCompaction) {
function TEST_F (line 1933) | TEST_F(DBTest, BloomFilter) {
function TEST_F (line 1980) | TEST_F(DBTest, LogCloseError) {
type MTState (line 2014) | struct MTState {
type MTThread (line 2021) | struct MTThread {
function MTThreadBody (line 2026) | static void MTThreadBody(void* arg) {
function TEST_F (line 2072) | TEST_F(DBTest, MultiThreaded) {
class ModelDB (line 2108) | class ModelDB : public DB {
class ModelSnapshot (line 2110) | class ModelSnapshot : public Snapshot {
method ModelDB (line 2115) | explicit ModelDB(const Options& options) : options_(options) {}
method Status (line 2117) | Status Put(const WriteOptions& o, const Slice& k, const Slice& v) ov...
method Status (line 2120) | Status Delete(const WriteOptions& o, const Slice& key) override {
method Status (line 2123) | Status Get(const ReadOptions& options, const Slice& key,
method Iterator (line 2128) | Iterator* NewIterator(const ReadOptions& options) override {
method Snapshot (line 2139) | const Snapshot* GetSnapshot() override {
method ReleaseSnapshot (line 2145) | void ReleaseSnapshot(const Snapshot* snapshot) override {
method Status (line 2148) | Status Write(const WriteOptions& options, WriteBatch* batch) override {
method GetProperty (line 2162) | bool GetProperty(const Slice& property, std::string* value) override {
method GetApproximateSizes (line 2165) | void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) ove...
method CompactRange (line 2170) | void CompactRange(const Slice* start, const Slice* end) override {}
class ModelIter (line 2173) | class ModelIter : public Iterator {
method ModelIter (line 2175) | ModelIter(const KVMap* map, bool owned)
method Valid (line 2180) | bool Valid() const override { return iter_ != map_->end(); }
method SeekToFirst (line 2181) | void SeekToFirst() override { iter_ = map_->begin(); }
method SeekToLast (line 2182) | void SeekToLast() override {
method Seek (line 2189) | void Seek(const Slice& k) override {
method Next (line 2192) | void Next() override { ++iter_; }
method Prev (line 2193) | void Prev() override { --iter_; }
method Slice (line 2194) | Slice key() const override { return iter_->first; }
method Slice (line 2195) | Slice value() const override { return iter_->second; }
method Status (line 2196) | Status status() const override { return Status::OK(); }
function CompareIterators (line 2207) | static bool CompareIterators(int step, DB* model, DB* db,
function TEST_F (line 2292) | TEST_F(DBTest, Randomized) {
FILE: db/dbformat.cc
type leveldb (line 13) | namespace leveldb {
function PackSequenceAndType (line 15) | static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
function AppendInternalKey (line 21) | void AppendInternalKey(std::string* result, const ParsedInternalKey& k...
FILE: db/dbformat.h
function namespace (line 20) | namespace leveldb {
FILE: db/dbformat_test.cc
type leveldb (line 10) | namespace leveldb {
function IKey (line 12) | static std::string IKey(const std::string& user_key, uint64_t seq,
function Shorten (line 19) | static std::string Shorten(const std::string& s, const std::string& l) {
function ShortSuccessor (line 25) | static std::string ShortSuccessor(const std::string& s) {
function TestKey (line 31) | static void TestKey(const std::string& key, uint64_t seq, ValueType vt) {
function TEST (line 45) | TEST(FormatTest, InternalKey_EncodeDecode) {
function TEST (line 67) | TEST(FormatTest, InternalKey_DecodeFromEmpty) {
function TEST (line 73) | TEST(FormatTest, InternalKeyShortSeparator) {
function TEST (line 107) | TEST(FormatTest, InternalKeyShortestSuccessor) {
function TEST (line 114) | TEST(FormatTest, ParsedInternalKeyDebugString) {
function TEST (line 120) | TEST(FormatTest, InternalKeyDebugString) {
FILE: db/dumpfile.cc
type leveldb (line 22) | namespace leveldb {
function GuessType (line 26) | bool GuessType(const std::string& fname, FileType* type) {
class CorruptionReporter (line 39) | class CorruptionReporter : public log::Reader::Reporter {
method Corruption (line 41) | void Corruption(size_t bytes, const Status& status) override {
function Status (line 54) | Status PrintLogContents(Env* env, const std::string& fname,
class WriteBatchItemPrinter (line 75) | class WriteBatchItemPrinter : public WriteBatch::Handler {
method Put (line 77) | void Put(const Slice& key, const Slice& value) override {
method Delete (line 85) | void Delete(const Slice& key) override {
function WriteBatchPrinter (line 97) | static void WriteBatchPrinter(uint64_t pos, Slice record, WritableFile...
function Status (line 122) | Status DumpLog(Env* env, const std::string& fname, WritableFile* dst) {
function VersionEditPrinter (line 128) | static void VersionEditPrinter(uint64_t pos, Slice record, WritableFil...
function Status (line 143) | Status DumpDescriptor(Env* env, const std::string& fname, WritableFile...
function Status (line 147) | Status DumpTable(Env* env, const std::string& fname, WritableFile* dst) {
function Status (line 214) | Status DumpFile(Env* env, const std::string& fname, WritableFile* dst) {
FILE: db/fault_injection_test.cc
type leveldb (line 28) | namespace leveldb {
class FaultInjectionTestEnv (line 34) | class FaultInjectionTestEnv
method FaultInjectionTestEnv (line 129) | FaultInjectionTestEnv()
method LOCKS_EXCLUDED (line 150) | LOCKS_EXCLUDED(mutex_) {
method LOCKS_EXCLUDED (line 154) | LOCKS_EXCLUDED(mutex_) {
function GetDirName (line 39) | static std::string GetDirName(const std::string& filename) {
function Status (line 48) | Status SyncDir(const std::string& dir) {
function Status (line 54) | Status Truncate(const std::string& filename, uint64_t length) {
type FileState (line 85) | struct FileState {
method FileState (line 91) | FileState(const std::string& filename)
method FileState (line 97) | FileState() : pos_(-1), pos_at_last_sync_(-1), pos_at_last_flush_(-1...
method IsFullySynced (line 99) | bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last...
class TestWritableFile (line 108) | class TestWritableFile : public WritableFile {
class FaultInjectionTestEnv (line 127) | class FaultInjectionTestEnv : public EnvWrapper {
method FaultInjectionTestEnv (line 129) | FaultInjectionTestEnv()
method LOCKS_EXCLUDED (line 150) | LOCKS_EXCLUDED(mutex_) {
method LOCKS_EXCLUDED (line 154) | LOCKS_EXCLUDED(mutex_) {
function Status (line 179) | Status TestWritableFile::Append(const Slice& data) {
function Status (line 187) | Status TestWritableFile::Close() {
function Status (line 196) | Status TestWritableFile::Flush() {
function Status (line 204) | Status TestWritableFile::SyncParent() {
function Status (line 212) | Status TestWritableFile::Sync() {
function Status (line 230) | Status FaultInjectionTestEnv::NewWritableFile(const std::string& fname,
function Status (line 248) | Status FaultInjectionTestEnv::NewAppendableFile(const std::string& fname,
function Status (line 268) | Status FaultInjectionTestEnv::DropUnsyncedFileData() {
function Status (line 301) | Status FaultInjectionTestEnv::RemoveFile(const std::string& f) {
function Status (line 310) | Status FaultInjectionTestEnv::RenameFile(const std::string& s,
function Status (line 338) | Status FaultInjectionTestEnv::RemoveFilesCreatedAfterLastDirSync() {
function Status (line 359) | Status FileState::DropUnsyncedData() const {
class FaultInjectionTest (line 364) | class FaultInjectionTest : public testing::Test {
type ExpectedVerifResult (line 366) | enum ExpectedVerifResult { VAL_EXPECT_NO_ERROR, VAL_EXPECT_ERROR }
type ResetMethod (line 367) | enum ResetMethod { RESET_DROP_UNSYNCED_DATA, RESET_DELETE_UNSYNCED_F...
method FaultInjectionTest (line 375) | FaultInjectionTest()
method ReuseLogs (line 395) | void ReuseLogs(bool reuse) { options_.reuse_logs = reuse; }
method Build (line 397) | void Build(int start_idx, int num_vals) {
method Status (line 409) | Status ReadValue(int i, std::string* val) const {
method Status (line 417) | Status Verify(int start_idx, int num_vals,
method Slice (line 440) | Slice Key(int i, std::string* storage) const {
method Slice (line 448) | Slice Value(int k, std::string* storage) const {
method Status (line 453) | Status OpenDB() {
method CloseDB (line 460) | void CloseDB() {
method DeleteAllData (line 465) | void DeleteAllData() {
method ResetDBState (line 474) | void ResetDBState(ResetMethod reset_method) {
method PartialCompactTestPreFault (line 487) | void PartialCompactTestPreFault(int num_pre_sync, int num_post_sync) {
method PartialCompactTestReopenWithFault (line 494) | void PartialCompactTestReopenWithFault(ResetMethod reset_method,
method NoWriteTestPreFault (line 506) | void NoWriteTestPreFault() {}
method NoWriteTestReopenWithFault (line 508) | void NoWriteTestReopenWithFault(ResetMethod reset_method) {
method DoTest (line 514) | void DoTest() {
function TEST_F (line 540) | TEST_F(FaultInjectionTest, FaultTestNoLogReuse) {
function TEST_F (line 545) | TEST_F(FaultInjectionTest, FaultTestWithLogReuse) {
FILE: db/filename.cc
type leveldb (line 14) | namespace leveldb {
function MakeFileName (line 20) | static std::string MakeFileName(const std::string& dbname, uint64_t nu...
function LogFileName (line 28) | std::string LogFileName(const std::string& dbname, uint64_t number) {
function TableFileName (line 33) | std::string TableFileName(const std::string& dbname, uint64_t number) {
function SSTTableFileName (line 38) | std::string SSTTableFileName(const std::string& dbname, uint64_t numbe...
function DescriptorFileName (line 43) | std::string DescriptorFileName(const std::string& dbname, uint64_t num...
function CurrentFileName (line 51) | std::string CurrentFileName(const std::string& dbname) {
function LockFileName (line 55) | std::string LockFileName(const std::string& dbname) { return dbname + ...
function TempFileName (line 57) | std::string TempFileName(const std::string& dbname, uint64_t number) {
function InfoLogFileName (line 62) | std::string InfoLogFileName(const std::string& dbname) {
function OldInfoLogFileName (line 67) | std::string OldInfoLogFileName(const std::string& dbname) {
function ParseFileName (line 78) | bool ParseFileName(const std::string& filename, uint64_t* number,
function Status (line 123) | Status SetCurrentFile(Env* env, const std::string& dbname,
FILE: db/filename.h
function namespace (line 17) | namespace leveldb {
FILE: db/filename_test.cc
type leveldb (line 12) | namespace leveldb {
function TEST (line 14) | TEST(FileNameTest, Parse) {
function TEST (line 73) | TEST(FileNameTest, Construction) {
FILE: db/leveldbutil.cc
type leveldb (line 11) | namespace leveldb {
class StdoutPrinter (line 14) | class StdoutPrinter : public WritableFile {
method Status (line 16) | Status Append(const Slice& data) override {
method Status (line 20) | Status Close() override { return Status::OK(); }
method Status (line 21) | Status Flush() override { return Status::OK(); }
method Status (line 22) | Status Sync() override { return Status::OK(); }
function HandleDumpCommand (line 25) | bool HandleDumpCommand(Env* env, char** files, int num) {
function Usage (line 41) | static void Usage() {
function main (line 48) | int main(int argc, char** argv) {
FILE: db/log_format.h
function namespace (line 11) | namespace leveldb {
FILE: db/log_reader.cc
type leveldb (line 13) | namespace leveldb {
type log (line 14) | namespace log {
FILE: db/log_reader.h
function namespace (line 14) | namespace leveldb {
FILE: db/log_test.cc
type leveldb (line 13) | namespace leveldb {
type log (line 14) | namespace log {
function BigString (line 18) | static std::string BigString(const std::string& partial_string, size...
function NumberString (line 28) | static std::string NumberString(int n) {
function RandomSkewedString (line 35) | static std::string RandomSkewedString(int i, Random* rnd) {
class LogTest (line 39) | class LogTest : public testing::Test {
method LogTest (line 41) | LogTest()
method ReopenForAppend (line 52) | void ReopenForAppend() {
method Write (line 57) | void Write(const std::string& msg) {
method WrittenBytes (line 62) | size_t WrittenBytes() const { return dest_.contents_.size(); }
method Read (line 64) | std::string Read() {
method IncrementByte (line 78) | void IncrementByte(int offset, int delta) {
method SetByte (line 82) | void SetByte(int offset, char new_byte) {
method ShrinkSize (line 86) | void ShrinkSize(int bytes) {
method FixChecksum (line 90) | void FixChecksum(int header_offset, int len) {
method ForceError (line 97) | void ForceError() { source_.force_error_ = true; }
method DroppedBytes (line 99) | size_t DroppedBytes() const { return report_.dropped_bytes_; }
method ReportMessage (line 101) | std::string ReportMessage() const { return report_.message_; }
method MatchError (line 104) | std::string MatchError(const std::string& msg) const {
method WriteInitialOffsetLog (line 112) | void WriteInitialOffsetLog() {
method StartReadingAt (line 120) | void StartReadingAt(uint64_t initial_offset) {
method CheckOffsetPastEndReturnsNoRecords (line 125) | void CheckOffsetPastEndReturnsNoRecords(uint64_t offset_past_end) {
method CheckInitialOffsetRecord (line 137) | void CheckInitialOffsetRecord(uint64_t initial_offset,
class StringDest (line 162) | class StringDest : public WritableFile {
method Status (line 164) | Status Close() override { return Status::OK(); }
method Status (line 165) | Status Flush() override { return Status::OK(); }
method Status (line 166) | Status Sync() override { return Status::OK(); }
method Status (line 167) | Status Append(const Slice& slice) override {
class StringSource (line 175) | class StringSource : public SequentialFile {
method StringSource (line 177) | StringSource() : force_error_(false), returned_partial_(false) {}
method Status (line 179) | Status Read(size_t n, Slice* result, char* scratch) override {
method Status (line 197) | Status Skip(uint64_t n) override {
class ReportCollector (line 213) | class ReportCollector : public Reader::Reporter {
method ReportCollector (line 215) | ReportCollector() : dropped_bytes_(0) {}
method Corruption (line 216) | void Corruption(size_t bytes, const Status& status) override {
function TEST_F (line 261) | TEST_F(LogTest, Empty) { ASSERT_EQ("EOF", Read()); }
function TEST_F (line 263) | TEST_F(LogTest, ReadWrite) {
function TEST_F (line 276) | TEST_F(LogTest, ManyBlocks) {
function TEST_F (line 286) | TEST_F(LogTest, Fragmentation) {
function TEST_F (line 296) | TEST_F(LogTest, MarginalTrailer) {
function TEST_F (line 309) | TEST_F(LogTest, MarginalTrailer2) {
function TEST_F (line 322) | TEST_F(LogTest, ShortTrailer) {
function TEST_F (line 334) | TEST_F(LogTest, AlignedEof) {
function TEST_F (line 342) | TEST_F(LogTest, OpenForAppend) {
function TEST_F (line 351) | TEST_F(LogTest, RandomRead) {
function TEST_F (line 366) | TEST_F(LogTest, ReadError) {
function TEST_F (line 374) | TEST_F(LogTest, BadRecordType) {
function TEST_F (line 384) | TEST_F(LogTest, TruncatedTrailingRecordIsIgnored) {
function TEST_F (line 393) | TEST_F(LogTest, BadLength) {
function TEST_F (line 404) | TEST_F(LogTest, BadLengthAtEndIsIgnored) {
function TEST_F (line 412) | TEST_F(LogTest, ChecksumMismatch) {
function TEST_F (line 420) | TEST_F(LogTest, UnexpectedMiddleType) {
function TEST_F (line 429) | TEST_F(LogTest, UnexpectedLastType) {
function TEST_F (line 438) | TEST_F(LogTest, UnexpectedFullType) {
function TEST_F (line 449) | TEST_F(LogTest, UnexpectedFirstType) {
function TEST_F (line 460) | TEST_F(LogTest, MissingLastIsIgnored) {
function TEST_F (line 469) | TEST_F(LogTest, PartialLastIsIgnored) {
function TEST_F (line 478) | TEST_F(LogTest, SkipIntoMultiRecord) {
function TEST_F (line 494) | TEST_F(LogTest, ErrorJoinsRecords) {
function TEST_F (line 517) | TEST_F(LogTest, ReadStart) { CheckInitialOffsetRecord(0, 0); }
function TEST_F (line 519) | TEST_F(LogTest, ReadSecondOneOff) { CheckInitialOffsetRecord(1, 1); }
function TEST_F (line 521) | TEST_F(LogTest, ReadSecondTenThousand) { CheckInitialOffsetRecord(10...
function TEST_F (line 523) | TEST_F(LogTest, ReadSecondStart) { CheckInitialOffsetRecord(10007, 1...
function TEST_F (line 525) | TEST_F(LogTest, ReadThirdOneOff) { CheckInitialOffsetRecord(10008, 2...
function TEST_F (line 527) | TEST_F(LogTest, ReadThirdStart) { CheckInitialOffsetRecord(20014, 2); }
function TEST_F (line 529) | TEST_F(LogTest, ReadFourthOneOff) { CheckInitialOffsetRecord(20015, ...
function TEST_F (line 531) | TEST_F(LogTest, ReadFourthFirstBlockTrailer) {
function TEST_F (line 535) | TEST_F(LogTest, ReadFourthMiddleBlock) {
function TEST_F (line 539) | TEST_F(LogTest, ReadFourthLastBlock) {
function TEST_F (line 543) | TEST_F(LogTest, ReadFourthStart) {
function TEST_F (line 549) | TEST_F(LogTest, ReadInitialOffsetIntoBlockPadding) {
function TEST_F (line 553) | TEST_F(LogTest, ReadEnd) { CheckOffsetPastEndReturnsNoRecords(0); }
function TEST_F (line 555) | TEST_F(LogTest, ReadPastEnd) { CheckOffsetPastEndReturnsNoRecords(5); }
FILE: db/log_writer.cc
type leveldb (line 13) | namespace leveldb {
type log (line 14) | namespace log {
function InitTypeCrc (line 16) | static void InitTypeCrc(uint32_t* type_crc) {
function Status (line 34) | Status Writer::AddRecord(const Slice& slice) {
function Status (line 82) | Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr,
FILE: db/log_writer.h
function namespace (line 14) | namespace leveldb {
FILE: db/memtable.cc
type leveldb (line 12) | namespace leveldb {
function Slice (line 14) | static Slice GetLengthPrefixedSlice(const char* data) {
class MemTableIterator (line 46) | class MemTableIterator : public Iterator {
method MemTableIterator (line 48) | explicit MemTableIterator(MemTable::Table* table) : iter_(table) {}
method MemTableIterator (line 50) | MemTableIterator(const MemTableIterator&) = delete;
method MemTableIterator (line 51) | MemTableIterator& operator=(const MemTableIterator&) = delete;
method Valid (line 55) | bool Valid() const override { return iter_.Valid(); }
method Seek (line 56) | void Seek(const Slice& k) override { iter_.Seek(EncodeKey(&tmp_, k)); }
method SeekToFirst (line 57) | void SeekToFirst() override { iter_.SeekToFirst(); }
method SeekToLast (line 58) | void SeekToLast() override { iter_.SeekToLast(); }
method Next (line 59) | void Next() override { iter_.Next(); }
method Prev (line 60) | void Prev() override { iter_.Prev(); }
method Slice (line 61) | Slice key() const override { return GetLengthPrefixedSlice(iter_.key...
method Slice (line 62) | Slice value() const override {
method Status (line 67) | Status status() const override { return Status::OK(); }
function Iterator (line 74) | Iterator* MemTable::NewIterator() { return new MemTableIterator(&table...
FILE: db/memtable.h
function namespace (line 15) | namespace leveldb {
FILE: db/recovery_test.cc
type leveldb (line 16) | namespace leveldb {
class RecoveryTest (line 18) | class RecoveryTest : public testing::Test {
method RecoveryTest (line 20) | RecoveryTest() : env_(Env::Default()), db_(nullptr) {
method DBImpl (line 31) | DBImpl* dbfull() const { return reinterpret_cast<DBImpl*>(db_); }
method Env (line 32) | Env* env() const { return env_; }
method CanAppend (line 34) | bool CanAppend() {
method Close (line 45) | void Close() {
method Status (line 50) | Status OpenWithStatus(Options* options = nullptr) {
method Open (line 65) | void Open(Options* options = nullptr) {
method Status (line 70) | Status Put(const std::string& k, const std::string& v) {
method Get (line 74) | std::string Get(const std::string& k, const Snapshot* snapshot = nul...
method ManifestFileName (line 85) | std::string ManifestFileName() {
method LogName (line 96) | std::string LogName(uint64_t number) { return LogFileName(dbname_, n...
method RemoveLogFiles (line 98) | size_t RemoveLogFiles() {
method RemoveManifestFile (line 109) | void RemoveManifestFile() {
method FirstLogFile (line 113) | uint64_t FirstLogFile() { return GetFiles(kLogFile)[0]; }
method GetFiles (line 115) | std::vector<uint64_t> GetFiles(FileType t) {
method NumLogs (line 129) | int NumLogs() { return GetFiles(kLogFile).size(); }
method NumTables (line 131) | int NumTables() { return GetFiles(kTableFile).size(); }
method FileSize (line 133) | uint64_t FileSize(const std::string& fname) {
method CompactMemTable (line 139) | void CompactMemTable() { dbfull()->TEST_CompactMemTable(); }
method MakeLogFile (line 142) | void MakeLogFile(uint64_t lognum, SequenceNumber seq, Slice key, Sli...
function TEST_F (line 161) | TEST_F(RecoveryTest, ManifestReused) {
function TEST_F (line 178) | TEST_F(RecoveryTest, LargeManifestCompacted) {
function TEST_F (line 210) | TEST_F(RecoveryTest, NoLogFiles) {
function TEST_F (line 219) | TEST_F(RecoveryTest, LogFileReuse) {
function TEST_F (line 250) | TEST_F(RecoveryTest, MultipleMemTables) {
function TEST_F (line 279) | TEST_F(RecoveryTest, MultipleLogFiles) {
function TEST_F (line 325) | TEST_F(RecoveryTest, ManifestMissing) {
FILE: db/repair.cc
type leveldb (line 41) | namespace leveldb {
class Repairer (line 45) | class Repairer {
method Repairer (line 47) | Repairer(const std::string& dbname, const Options& options)
method Status (line 70) | Status Run() {
type TableInfo (line 93) | struct TableInfo {
method Status (line 98) | Status FindFiles() {
method ConvertLogFilesToTables (line 131) | void ConvertLogFilesToTables() {
method Status (line 143) | Status ConvertLogToTable(uint64_t log) {
method ExtractMetaData (line 221) | void ExtractMetaData() {
method Iterator (line 227) | Iterator* NewTableIterator(const FileMetaData& meta) {
method ScanTable (line 235) | void ScanTable(uint64_t number) {
method RepairTable (line 294) | void RepairTable(const std::string& src, TableInfo t) {
method Status (line 348) | Status WriteDescriptor() {
method ArchiveFile (line 408) | void ArchiveFile(const std::string& fname) {
function Status (line 446) | Status RepairDB(const std::string& dbname, const Options& options) {
FILE: db/skiplist.h
function namespace (line 37) | namespace leveldb {
FILE: db/skiplist_test.cc
type leveldb (line 19) | namespace leveldb {
type Comparator (line 23) | struct Comparator {
function TEST (line 35) | TEST(SkipTest, Empty) {
function TEST (line 51) | TEST(SkipTest, InsertAndLookup) {
class ConcurrentTest (line 152) | class ConcurrentTest {
method key (line 156) | static uint64_t key(Key key) { return (key >> 40); }
method gen (line 157) | static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
method hash (line 158) | static uint64_t hash(Key key) { return key & 0xff; }
method HashNumbers (line 160) | static uint64_t HashNumbers(uint64_t k, uint64_t g) {
method Key (line 165) | static Key MakeKey(uint64_t k, uint64_t g) {
method IsValidKey (line 172) | static bool IsValidKey(Key k) {
method Key (line 176) | static Key RandomTarget(Random* rnd) {
type State (line 191) | struct State {
method Set (line 193) | void Set(int k, int v) {
method Get (line 196) | int Get(int k) { return generation[k].load(std::memory_order_acqui...
method State (line 198) | State() {
method ConcurrentTest (line 215) | ConcurrentTest() : list_(Comparator(), &arena_) {}
method WriteStep (line 218) | void WriteStep(Random* rnd) {
method ReadStep (line 226) | void ReadStep(Random* rnd) {
function TEST (line 289) | TEST(SkipTest, ConcurrentWithoutThreads) {
class TestState (line 298) | class TestState {
type ReaderState (line 304) | enum ReaderState { STARTING, RUNNING, DONE }
method TestState (line 306) | explicit TestState(int s)
method LOCKS_EXCLUDED (line 309) | LOCKS_EXCLUDED(mu_) {
method LOCKS_EXCLUDED (line 317) | LOCKS_EXCLUDED(mu_) {
function ConcurrentReader (line 330) | static void ConcurrentReader(void* arg) {
function RunConcurrent (line 342) | static void RunConcurrent(int run) {
function TEST (line 362) | TEST(SkipTest, Concurrent1) { RunConcurrent(1); }
function TEST (line 363) | TEST(SkipTest, Concurrent2) { RunConcurrent(2); }
function TEST (line 364) | TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
function TEST (line 365) | TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
function TEST (line 366) | TEST(SkipTest, Concurrent5) { RunConcurrent(5); }
FILE: db/snapshot.h
function namespace (line 11) | namespace leveldb {
function class (line 39) | class SnapshotList {
FILE: db/table_cache.cc
type leveldb (line 12) | namespace leveldb {
type TableAndFile (line 14) | struct TableAndFile {
function DeleteEntry (line 19) | static void DeleteEntry(const Slice& key, void* value) {
function UnrefEntry (line 26) | static void UnrefEntry(void* arg1, void* arg2) {
function Status (line 41) | Status TableCache::FindTable(uint64_t file_number, uint64_t file_size,
function Iterator (line 78) | Iterator* TableCache::NewIterator(const ReadOptions& options,
function Status (line 100) | Status TableCache::Get(const ReadOptions& options, uint64_t file_number,
FILE: db/table_cache.h
function namespace (line 18) | namespace leveldb {
FILE: db/version_edit.cc
type leveldb (line 10) | namespace leveldb {
type Tag (line 14) | enum Tag {
function GetInternalKey (line 87) | static bool GetInternalKey(Slice* input, InternalKey* dst) {
function GetLevel (line 96) | static bool GetLevel(Slice* input, int* level) {
function Status (line 106) | Status VersionEdit::DecodeFrom(const Slice& src) {
FILE: db/version_edit.h
function namespace (line 14) | namespace leveldb {
FILE: db/version_edit_test.cc
type leveldb (line 9) | namespace leveldb {
function TestEncodeDecode (line 11) | static void TestEncodeDecode(const VersionEdit& edit) {
function TEST (line 21) | TEST(VersionEditTest, EncodeDecode) {
FILE: db/version_set.cc
type leveldb (line 22) | namespace leveldb {
function TargetFileSize (line 24) | static size_t TargetFileSize(const Options* options) {
function MaxGrandParentOverlapBytes (line 30) | static int64_t MaxGrandParentOverlapBytes(const Options* options) {
function ExpandedCompactionByteSizeLimit (line 37) | static int64_t ExpandedCompactionByteSizeLimit(const Options* options) {
function MaxBytesForLevel (line 41) | static double MaxBytesForLevel(const Options* options, int level) {
function MaxFileSizeForLevel (line 54) | static uint64_t MaxFileSizeForLevel(const Options* options, int level) {
function TotalFileSize (line 59) | static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
function FindFile (line 87) | int FindFile(const InternalKeyComparator& icmp,
function AfterFile (line 107) | static bool AfterFile(const Comparator* ucmp, const Slice* user_key,
function BeforeFile (line 114) | static bool BeforeFile(const Comparator* ucmp, const Slice* user_key,
function SomeFileOverlapsRange (line 121) | bool SomeFileOverlapsRange(const InternalKeyComparator& icmp,
class Version::LevelFileNumIterator (line 163) | class Version::LevelFileNumIterator : public Iterator {
method LevelFileNumIterator (line 165) | LevelFileNumIterator(const InternalKeyComparator& icmp,
method Valid (line 169) | bool Valid() const override { return index_ < flist_->size(); }
method Seek (line 170) | void Seek(const Slice& target) override {
method SeekToFirst (line 173) | void SeekToFirst() override { index_ = 0; }
method SeekToLast (line 174) | void SeekToLast() override {
method Next (line 177) | void Next() override {
method Prev (line 181) | void Prev() override {
method Slice (line 189) | Slice key() const override {
method Slice (line 193) | Slice value() const override {
method Status (line 199) | Status status() const override { return Status::OK(); }
function Iterator (line 210) | static Iterator* GetFileIterator(void* arg, const ReadOptions& options,
function Iterator (line 222) | Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
type SaverState (line 249) | enum SaverState {
type Saver (line 255) | struct Saver {
function SaveValue (line 262) | static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {
function NewestFirst (line 277) | static bool NewestFirst(FileMetaData* a, FileMetaData* b) {
function Status (line 324) | Status Version::Get(const ReadOptions& options, const LookupKey& k,
type State (line 421) | struct State {
method Match (line 425) | static bool Match(void* arg, int level, FileMetaData* f) {
class VersionSet::Builder (line 569) | class VersionSet::Builder {
type BySmallestKey (line 572) | struct BySmallestKey {
type LevelState (line 587) | struct LevelState {
method Builder (line 598) | Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) {
method Apply (line 629) | void Apply(const VersionEdit* edit) {
method SaveTo (line 672) | void SaveTo(Version* v) {
method MaybeAddFile (line 717) | void MaybeAddFile(Version* v, int level, FileMetaData* f) {
function Status (line 777) | Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {
function Status (line 861) | Status VersionSet::Recover(bool* save_manifest) {
function Status (line 1069) | Status VersionSet::WriteSnapshot(log::Writer* log) {
function Iterator (line 1219) | Iterator* VersionSet::MakeInputIterator(Compaction* c) {
function Compaction (line 1252) | Compaction* VersionSet::PickCompaction() {
function FindLargestKey (line 1308) | bool FindLargestKey(const InternalKeyComparator& icmp,
function FileMetaData (line 1326) | FileMetaData* FindSmallestBoundaryFile(
function AddBoundaryInputs (line 1360) | void AddBoundaryInputs(const InternalKeyComparator& icmp,
function Compaction (line 1448) | Compaction* VersionSet::CompactRange(int level, const InternalKey* begin,
FILE: db/version_set.h
function namespace (line 29) | namespace log {
function class (line 60) | class Version {
function class (line 167) | class VersionSet {
FILE: db/version_set_test.cc
type leveldb (line 11) | namespace leveldb {
class FindFileTest (line 13) | class FindFileTest : public testing::Test {
method FindFileTest (line 15) | FindFileTest() : disjoint_sorted_files_(true) {}
method Add (line 23) | void Add(const char* smallest, const char* largest,
method Find (line 33) | int Find(const char* key) {
method Overlaps (line 39) | bool Overlaps(const char* smallest, const char* largest) {
function TEST_F (line 54) | TEST_F(FindFileTest, Empty) {
function TEST_F (line 62) | TEST_F(FindFileTest, Single) {
function TEST_F (line 92) | TEST_F(FindFileTest, Multiple) {
function TEST_F (line 130) | TEST_F(FindFileTest, MultipleNullBoundaries) {
function TEST_F (line 150) | TEST_F(FindFileTest, OverlapSequenceChecks) {
function TEST_F (line 159) | TEST_F(FindFileTest, OverlappingFiles) {
class AddBoundaryInputsTest (line 181) | class AddBoundaryInputsTest : public testing::Test {
method AddBoundaryInputsTest (line 188) | AddBoundaryInputsTest() : icmp_(BytewiseComparator()) {}
method FileMetaData (line 197) | FileMetaData* CreateFileMetaData(uint64_t number, InternalKey smallest,
function TEST_F (line 208) | TEST_F(AddBoundaryInputsTest, TestEmptyFileSets) {
function TEST_F (line 214) | TEST_F(AddBoundaryInputsTest, TestEmptyLevelFiles) {
function TEST_F (line 226) | TEST_F(AddBoundaryInputsTest, TestEmptyCompactionFiles) {
function TEST_F (line 238) | TEST_F(AddBoundaryInputsTest, TestNoBoundaryFiles) {
function TEST_F (line 259) | TEST_F(AddBoundaryInputsTest, TestOneBoundaryFiles) {
function TEST_F (line 281) | TEST_F(AddBoundaryInputsTest, TestTwoBoundaryFiles) {
function TEST_F (line 304) | TEST_F(AddBoundaryInputsTest, TestDisjoinFilePointers) {
FILE: db/write_batch.cc
type leveldb (line 24) | namespace leveldb {
function Status (line 42) | Status WriteBatch::Iterate(Handler* handler) const {
function SequenceNumber (line 90) | SequenceNumber WriteBatchInternal::Sequence(const WriteBatch* b) {
class MemTableInserter (line 116) | class MemTableInserter : public WriteBatch::Handler {
method Put (line 121) | void Put(const Slice& key, const Slice& value) override {
method Delete (line 125) | void Delete(const Slice& key) override {
function Status (line 132) | Status WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* m...
FILE: db/write_batch_internal.h
function namespace (line 11) | namespace leveldb {
FILE: db/write_batch_test.cc
type leveldb (line 12) | namespace leveldb {
function PrintContents (line 14) | static std::string PrintContents(WriteBatch* b) {
function TEST (line 54) | TEST(WriteBatchTest, Empty) {
function TEST (line 60) | TEST(WriteBatchTest, Multiple) {
function TEST (line 75) | TEST(WriteBatchTest, Corruption) {
function TEST (line 89) | TEST(WriteBatchTest, Append) {
function TEST (line 115) | TEST(WriteBatchTest, ApproximateSize) {
FILE: helpers/memenv/memenv.cc
type leveldb (line 19) | namespace leveldb {
class FileState (line 23) | class FileState {
method FileState (line 27) | FileState() : refs_(0), size_(0) {}
method FileState (line 30) | FileState(const FileState&) = delete;
method FileState (line 31) | FileState& operator=(const FileState&) = delete;
method Ref (line 34) | void Ref() {
method Unref (line 40) | void Unref() {
method Size (line 57) | uint64_t Size() const {
method Truncate (line 62) | void Truncate() {
method Status (line 71) | Status Read(uint64_t offset, size_t n, Slice* result, char* scratch)...
method Status (line 108) | Status Append(const Slice& data) {
class SequentialFileImpl (line 152) | class SequentialFileImpl : public SequentialFile {
method SequentialFileImpl (line 154) | explicit SequentialFileImpl(FileState* file) : file_(file), pos_(0) {
method Status (line 160) | Status Read(size_t n, Slice* result, char* scratch) override {
method Status (line 168) | Status Skip(uint64_t n) override {
class RandomAccessFileImpl (line 185) | class RandomAccessFileImpl : public RandomAccessFile {
method RandomAccessFileImpl (line 187) | explicit RandomAccessFileImpl(FileState* file) : file_(file) { file_...
method Status (line 191) | Status Read(uint64_t offset, size_t n, Slice* result,
class WritableFileImpl (line 200) | class WritableFileImpl : public WritableFile {
method WritableFileImpl (line 202) | WritableFileImpl(FileState* file) : file_(file) { file_->Ref(); }
method Status (line 206) | Status Append(const Slice& data) override { return file_->Append(dat...
method Status (line 208) | Status Close() override { return Status::OK(); }
method Status (line 209) | Status Flush() override { return Status::OK(); }
method Status (line 210) | Status Sync() override { return Status::OK(); }
class NoOpLogger (line 216) | class NoOpLogger : public Logger {
method Logv (line 218) | void Logv(const char* format, std::va_list ap) override {}
class InMemoryEnv (line 221) | class InMemoryEnv : public EnvWrapper {
method InMemoryEnv (line 223) | explicit InMemoryEnv(Env* base_env) : EnvWrapper(base_env) {}
method Status (line 232) | Status NewSequentialFile(const std::string& fname,
method Status (line 244) | Status NewRandomAccessFile(const std::string& fname,
method Status (line 256) | Status NewWritableFile(const std::string& fname,
method Status (line 276) | Status NewAppendableFile(const std::string& fname,
method FileExists (line 289) | bool FileExists(const std::string& fname) override {
method Status (line 294) | Status GetChildren(const std::string& dir,
method EXCLUSIVE_LOCKS_REQUIRED (line 312) | EXCLUSIVE_LOCKS_REQUIRED(mutex_) {
method Status (line 321) | Status RemoveFile(const std::string& fname) override {
method Status (line 331) | Status CreateDir(const std::string& dirname) override { return Statu...
method Status (line 333) | Status RemoveDir(const std::string& dirname) override { return Statu...
method Status (line 335) | Status GetFileSize(const std::string& fname, uint64_t* file_size) ov...
method Status (line 345) | Status RenameFile(const std::string& src,
method Status (line 358) | Status LockFile(const std::string& fname, FileLock** lock) override {
method Status (line 363) | Status UnlockFile(FileLock* lock) override {
method Status (line 368) | Status GetTestDirectory(std::string* path) override {
method Status (line 373) | Status NewLogger(const std::string& fname, Logger** result) override {
function Env (line 388) | Env* NewMemEnv(Env* base_env) { return new InMemoryEnv(base_env); }
FILE: helpers/memenv/memenv.h
function namespace (line 10) | namespace leveldb {
FILE: helpers/memenv/memenv_test.cc
type leveldb (line 16) | namespace leveldb {
class MemEnvTest (line 18) | class MemEnvTest : public testing::Test {
method MemEnvTest (line 20) | MemEnvTest() : env_(NewMemEnv(Env::Default())) {}
function TEST_F (line 26) | TEST_F(MemEnvTest, Basics) {
function TEST_F (line 94) | TEST_F(MemEnvTest, ReadWrite) {
function TEST_F (line 137) | TEST_F(MemEnvTest, Locks) {
function TEST_F (line 145) | TEST_F(MemEnvTest, Misc) {
function TEST_F (line 160) | TEST_F(MemEnvTest, LargeWrite) {
function TEST_F (line 193) | TEST_F(MemEnvTest, OverwriteOpenFile) {
function TEST_F (line 216) | TEST_F(MemEnvTest, DBTest) {
FILE: include/leveldb/c.h
type leveldb_t (line 55) | typedef struct leveldb_t leveldb_t;
type leveldb_cache_t (line 56) | typedef struct leveldb_cache_t leveldb_cache_t;
type leveldb_comparator_t (line 57) | typedef struct leveldb_comparator_t leveldb_comparator_t;
type leveldb_env_t (line 58) | typedef struct leveldb_env_t leveldb_env_t;
type leveldb_filelock_t (line 59) | typedef struct leveldb_filelock_t leveldb_filelock_t;
type leveldb_filterpolicy_t (line 60) | typedef struct leveldb_filterpolicy_t leveldb_filterpolicy_t;
type leveldb_iterator_t (line 61) | typedef struct leveldb_iterator_t leveldb_iterator_t;
type leveldb_logger_t (line 62) | typedef struct leveldb_logger_t leveldb_logger_t;
type leveldb_options_t (line 63) | typedef struct leveldb_options_t leveldb_options_t;
type leveldb_randomfile_t (line 64) | typedef struct leveldb_randomfile_t leveldb_randomfile_t;
type leveldb_readoptions_t (line 65) | typedef struct leveldb_readoptions_t leveldb_readoptions_t;
type leveldb_seqfile_t (line 66) | typedef struct leveldb_seqfile_t leveldb_seqfile_t;
type leveldb_snapshot_t (line 67) | typedef struct leveldb_snapshot_t leveldb_snapshot_t;
type leveldb_writablefile_t (line 68) | typedef struct leveldb_writablefile_t leveldb_writablefile_t;
type leveldb_writebatch_t (line 69) | typedef struct leveldb_writebatch_t leveldb_writebatch_t;
type leveldb_writeoptions_t (line 70) | typedef struct leveldb_writeoptions_t leveldb_writeoptions_t;
FILE: include/leveldb/cache.h
function namespace (line 26) | namespace leveldb {
FILE: include/leveldb/comparator.h
function namespace (line 12) | namespace leveldb {
FILE: include/leveldb/db.h
function namespace (line 15) | namespace leveldb {
FILE: include/leveldb/dumpfile.h
function namespace (line 14) | namespace leveldb {
FILE: include/leveldb/env.h
function namespace (line 42) | namespace leveldb {
FILE: include/leveldb/filter_policy.h
function namespace (line 23) | namespace leveldb {
FILE: include/leveldb/iterator.h
type CleanupNode (line 86) | struct CleanupNode {
FILE: include/leveldb/options.h
function namespace (line 12) | namespace leveldb {
FILE: include/leveldb/slice.h
function namespace (line 25) | namespace leveldb {
function compare (line 103) | inline int Slice::compare(const Slice& b) const {
FILE: include/leveldb/status.h
function namespace (line 22) | namespace leveldb {
FILE: include/leveldb/table.h
function namespace (line 13) | namespace leveldb {
FILE: include/leveldb/table_builder.h
function namespace (line 22) | namespace leveldb {
FILE: include/leveldb/write_batch.h
function namespace (line 29) | namespace leveldb {
FILE: issues/issue178_test.cc
function Key1 (line 19) | std::string Key1(int i) {
function Key2 (line 25) | std::string Key2(int i) { return Key1(i) + "_xxx"; }
function TEST (line 27) | TEST(Issue178, Test) {
FILE: issues/issue200_test.cc
type leveldb (line 13) | namespace leveldb {
function TEST (line 15) | TEST(Issue200, Test) {
FILE: issues/issue320_test.cc
type leveldb (line 17) | namespace leveldb {
function GenerateRandomNumber (line 22) | int GenerateRandomNumber(int max) { return std::rand() % max; }
function CreateRandomString (line 24) | std::string CreateRandomString(int32_t index) {
function TEST (line 41) | TEST(Issue320, Test) {
FILE: port/port_example.h
function namespace (line 15) | namespace leveldb {
FILE: port/port_stdcxx.h
function namespace (line 45) | namespace leveldb {
FILE: table/block.cc
type leveldb (line 18) | namespace leveldb {
class Block::Iter (line 77) | class Block::Iter : public Iterator {
method Compare (line 91) | inline int Compare(const Slice& a, const Slice& b) const {
method NextEntryOffset (line 96) | inline uint32_t NextEntryOffset() const {
method GetRestartPoint (line 100) | uint32_t GetRestartPoint(uint32_t index) {
method SeekToRestartPoint (line 105) | void SeekToRestartPoint(uint32_t index) {
method Iter (line 116) | Iter(const Comparator* comparator, const char* data, uint32_t restarts,
method Valid (line 127) | bool Valid() const override { return current_ < restarts_; }
method Status (line 128) | Status status() const override { return status_; }
method Slice (line 129) | Slice key() const override {
method Slice (line 133) | Slice value() const override {
method Next (line 138) | void Next() override {
method Prev (line 143) | void Prev() override {
method Seek (line 164) | void Seek(const Slice& target) override {
method SeekToFirst (line 229) | void SeekToFirst() override {
method SeekToLast (line 234) | void SeekToLast() override {
method CorruptionError (line 242) | void CorruptionError() {
method ParseNextKey (line 250) | bool ParseNextKey() {
function Iterator (line 280) | Iterator* Block::NewIterator(const Comparator* comparator) {
FILE: table/block.h
function namespace (line 13) | namespace leveldb {
FILE: table/block_builder.cc
type leveldb (line 38) | namespace leveldb {
function Slice (line 61) | Slice BlockBuilder::Finish() {
FILE: table/block_builder.h
function namespace (line 13) | namespace leveldb {
FILE: table/filter_block.cc
type leveldb (line 10) | namespace leveldb {
function Slice (line 35) | Slice FilterBlockBuilder::Finish() {
FILE: table/filter_block.h
function namespace (line 20) | namespace leveldb {
FILE: table/filter_block_test.cc
type leveldb (line 14) | namespace leveldb {
class TestHashFilter (line 17) | class TestHashFilter : public FilterPolicy {
method CreateFilter (line 21) | void CreateFilter(const Slice* keys, int n, std::string* dst) const ...
method KeyMayMatch (line 28) | bool KeyMayMatch(const Slice& key, const Slice& filter) const overri...
class FilterBlockTest (line 39) | class FilterBlockTest : public testing::Test {
function TEST_F (line 44) | TEST_F(FilterBlockTest, EmptyBuilder) {
function TEST_F (line 53) | TEST_F(FilterBlockTest, SingleChunk) {
function TEST_F (line 74) | TEST_F(FilterBlockTest, MultiChunk) {
FILE: table/format.cc
type leveldb (line 14) | namespace leveldb {
function Status (line 24) | Status BlockHandle::DecodeFrom(Slice* input) {
function Status (line 43) | Status Footer::DecodeFrom(Slice* input) {
function Status (line 69) | Status ReadBlock(RandomAccessFile* file, const ReadOptions& options,
FILE: table/format.h
function namespace (line 15) | namespace leveldb {
FILE: table/iterator.cc
type leveldb (line 7) | namespace leveldb {
class EmptyIterator (line 43) | class EmptyIterator : public Iterator {
method EmptyIterator (line 45) | EmptyIterator(const Status& s) : status_(s) {}
method Valid (line 48) | bool Valid() const override { return false; }
method Seek (line 49) | void Seek(const Slice& target) override {}
method SeekToFirst (line 50) | void SeekToFirst() override {}
method SeekToLast (line 51) | void SeekToLast() override {}
method Next (line 52) | void Next() override { assert(false); }
method Prev (line 53) | void Prev() override { assert(false); }
method Slice (line 54) | Slice key() const override {
method Slice (line 58) | Slice value() const override {
method Status (line 62) | Status status() const override { return status_; }
function Iterator (line 70) | Iterator* NewEmptyIterator() { return new EmptyIterator(Status::OK()); }
function Iterator (line 72) | Iterator* NewErrorIterator(const Status& status) {
FILE: table/iterator_wrapper.h
function namespace (line 11) | namespace leveldb {
FILE: table/merger.cc
type leveldb (line 11) | namespace leveldb {
class MergingIterator (line 14) | class MergingIterator : public Iterator {
method MergingIterator (line 16) | MergingIterator(const Comparator* comparator, Iterator** children, i...
method Valid (line 29) | bool Valid() const override { return (current_ != nullptr); }
method SeekToFirst (line 31) | void SeekToFirst() override {
method SeekToLast (line 39) | void SeekToLast() override {
method Seek (line 47) | void Seek(const Slice& target) override {
method Next (line 55) | void Next() override {
method Prev (line 81) | void Prev() override {
method Slice (line 110) | Slice key() const override {
method Slice (line 115) | Slice value() const override {
method Status (line 120) | Status status() const override {
type Direction (line 133) | enum Direction { kForward, kReverse }
function Iterator (line 179) | Iterator* NewMergingIterator(const Comparator* comparator, Iterator** ...
FILE: table/merger.h
function namespace (line 8) | namespace leveldb {
FILE: table/table.cc
type leveldb (line 18) | namespace leveldb {
type Table::Rep (line 20) | struct Table::Rep {
function Status (line 38) | Status Table::Open(const Options& options, RandomAccessFile* file,
function DeleteBlock (line 136) | static void DeleteBlock(void* arg, void* ignored) {
function DeleteCachedBlock (line 140) | static void DeleteCachedBlock(const Slice& key, void* value) {
function ReleaseBlock (line 145) | static void ReleaseBlock(void* arg, void* h) {
function Iterator (line 153) | Iterator* Table::BlockReader(void* arg, const ReadOptions& options,
function Iterator (line 208) | Iterator* Table::NewIterator(const ReadOptions& options) const {
function Status (line 214) | Status Table::InternalGet(const ReadOptions& options, const Slice& k, ...
FILE: table/table_builder.cc
type leveldb (line 19) | namespace leveldb {
type TableBuilder::Rep (line 21) | struct TableBuilder::Rep {
method Rep (line 22) | Rep(const Options& opt, WritableFile* f)
function Status (line 78) | Status TableBuilder::ChangeOptions(const Options& options) {
function Status (line 211) | Status TableBuilder::status() const { return rep_->status; }
function Status (line 213) | Status TableBuilder::Finish() {
FILE: table/table_test.cc
type leveldb (line 25) | namespace leveldb {
function Reverse (line 29) | static std::string Reverse(const Slice& key) {
class ReverseKeyComparator (line 40) | class ReverseKeyComparator : public Comparator {
method Compare (line 46) | int Compare(const Slice& a, const Slice& b) const override {
method FindShortestSeparator (line 50) | void FindShortestSeparator(std::string* start,
method FindShortSuccessor (line 58) | void FindShortSuccessor(std::string* key) const override {
function Increment (line 67) | static void Increment(const Comparator* cmp, std::string* key) {
type STLLessThan (line 80) | struct STLLessThan {
method STLLessThan (line 83) | STLLessThan() : cmp(BytewiseComparator()) {}
method STLLessThan (line 84) | STLLessThan(const Comparator* c) : cmp(c) {}
class StringSink (line 91) | class StringSink : public WritableFile {
method Status (line 97) | Status Close() override { return Status::OK(); }
method Status (line 98) | Status Flush() override { return Status::OK(); }
method Status (line 99) | Status Sync() override { return Status::OK(); }
method Status (line 101) | Status Append(const Slice& data) override {
class StringSource (line 110) | class StringSource : public RandomAccessFile {
method StringSource (line 112) | StringSource(const Slice& contents)
method Size (line 117) | uint64_t Size() const { return contents_.size(); }
method Status (line 119) | Status Read(uint64_t offset, size_t n, Slice* result,
class Constructor (line 140) | class Constructor {
method Constructor (line 142) | explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)...
method Add (line 145) | void Add(const std::string& key, const Slice& value) {
method Finish (line 152) | void Finish(const Options& options, std::vector<std::string>* keys,
method KVMap (line 169) | const KVMap& data() const { return data_; }
method DB (line 171) | virtual DB* db() const { return nullptr; }
class BlockConstructor (line 177) | class BlockConstructor : public Constructor {
method BlockConstructor (line 179) | explicit BlockConstructor(const Comparator* cmp)
method Status (line 182) | Status FinishImpl(const Options& options, const KVMap& data) override {
method Iterator (line 199) | Iterator* NewIterator() const override {
class TableConstructor (line 211) | class TableConstructor : public Constructor {
method TableConstructor (line 213) | TableConstructor(const Comparator* cmp)
method Status (line 216) | Status FinishImpl(const Options& options, const KVMap& data) override {
method Iterator (line 237) | Iterator* NewIterator() const override {
method ApproximateOffsetOf (line 241) | uint64_t ApproximateOffsetOf(const Slice& key) const {
method Reset (line 246) | void Reset() {
class KeyConvertingIterator (line 260) | class KeyConvertingIterator : public Iterator {
method KeyConvertingIterator (line 262) | explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) {}
method KeyConvertingIterator (line 264) | KeyConvertingIterator(const KeyConvertingIterator&) = delete;
method KeyConvertingIterator (line 265) | KeyConvertingIterator& operator=(const KeyConvertingIterator&) = del...
method Valid (line 269) | bool Valid() const override { return iter_->Valid(); }
method Seek (line 270) | void Seek(const Slice& target) override {
method SeekToFirst (line 276) | void SeekToFirst() override { iter_->SeekToFirst(); }
method SeekToLast (line 277) | void SeekToLast() override { iter_->SeekToLast(); }
method Next (line 278) | void Next() override { iter_->Next(); }
method Prev (line 279) | void Prev() override { iter_->Prev(); }
method Slice (line 281) | Slice key() const override {
method Slice (line 291) | Slice value() const override { return iter_->value(); }
method Status (line 292) | Status status() const override {
class MemTableConstructor (line 301) | class MemTableConstructor : public Constructor {
method MemTableConstructor (line 303) | explicit MemTableConstructor(const Comparator* cmp)
method Status (line 309) | Status FinishImpl(const Options& options, const KVMap& data) override {
method Iterator (line 320) | Iterator* NewIterator() const override {
class DBConstructor (line 329) | class DBConstructor : public Constructor {
method DBConstructor (line 331) | explicit DBConstructor(const Comparator* cmp)
method Status (line 337) | Status FinishImpl(const Options& options, const KVMap& data) override {
method Iterator (line 348) | Iterator* NewIterator() const override {
method DB (line 352) | DB* db() const override { return db_; }
method NewDB (line 355) | void NewDB() {
type TestType (line 374) | enum TestType { TABLE_TEST, BLOCK_TEST, MEMTABLE_TEST, DB_TEST }
type TestArgs (line 376) | struct TestArgs {
class Harness (line 407) | class Harness : public testing::Test {
method Harness (line 409) | Harness() : constructor_(nullptr) {}
method Init (line 411) | void Init(const TestArgs& args) {
method Add (line 441) | void Add(const std::string& key, const std::string& value) {
method Test (line 445) | void Test(Random* rnd) {
method TestForwardScan (line 455) | void TestForwardScan(const std::vector<std::string>& keys,
method TestBackwardScan (line 469) | void TestBackwardScan(const std::vector<std::string>& keys,
method TestRandomAccess (line 483) | void TestRandomAccess(Random* rnd, const std::vector<std::string>& k...
method ToString (line 552) | std::string ToString(const KVMap& data, const KVMap::const_iterator&...
method ToString (line 560) | std::string ToString(const KVMap& data,
method ToString (line 569) | std::string ToString(const Iterator* it) {
method PickRandomKey (line 577) | std::string PickRandomKey(Random* rnd, const std::vector<std::string...
method DB (line 605) | DB* db() const { return constructor_->db(); }
function TEST_F (line 613) | TEST_F(Harness, Empty) {
function TEST_F (line 624) | TEST_F(Harness, ZeroRestartPointsInBlock) {
function TEST_F (line 643) | TEST_F(Harness, SimpleEmptyKey) {
function TEST_F (line 652) | TEST_F(Harness, SimpleSingle) {
function TEST_F (line 661) | TEST_F(Harness, SimpleMulti) {
function TEST_F (line 672) | TEST_F(Harness, SimpleSpecialKey) {
function TEST_F (line 681) | TEST_F(Harness, Randomized) {
function TEST_F (line 701) | TEST_F(Harness, RandomizedLongDB) {
function TEST (line 725) | TEST(MemTableTest, Simple) {
function Between (line 749) | static bool Between(uint64_t val, uint64_t low, uint64_t high) {
function TEST (line 759) | TEST(TableTest, ApproximateOffsetOfPlain) {
function CompressionSupported (line 788) | static bool CompressionSupported(CompressionType type) {
class CompressionTableTest (line 799) | class CompressionTableTest
function TEST_P (line 806) | TEST_P(CompressionTableTest, ApproximateOffsetOfCompressed) {
FILE: table/two_level_iterator.cc
type leveldb (line 12) | namespace leveldb {
class TwoLevelIterator (line 18) | class TwoLevelIterator : public Iterator {
method Valid (line 31) | bool Valid() const override { return data_iter_.Valid(); }
method Slice (line 32) | Slice key() const override {
method Slice (line 36) | Slice value() const override {
method Status (line 40) | Status status() const override {
method SaveError (line 52) | void SaveError(const Status& s) {
function Iterator (line 165) | Iterator* NewTwoLevelIterator(Iterator* index_iter,
FILE: table/two_level_iterator.h
function namespace (line 10) | namespace leveldb {
FILE: util/arena.cc
type leveldb (line 7) | namespace leveldb {
FILE: util/arena.h
function namespace (line 14) | namespace leveldb {
FILE: util/arena_test.cc
type leveldb (line 10) | namespace leveldb {
function TEST (line 12) | TEST(ArenaTest, Empty) { Arena arena; }
function TEST (line 14) | TEST(ArenaTest, Simple) {
FILE: util/bloom.cc
type leveldb (line 10) | namespace leveldb {
function BloomHash (line 13) | static uint32_t BloomHash(const Slice& key) {
class BloomFilterPolicy (line 17) | class BloomFilterPolicy : public FilterPolicy {
method BloomFilterPolicy (line 19) | explicit BloomFilterPolicy(int bits_per_key) : bits_per_key_(bits_pe...
method CreateFilter (line 28) | void CreateFilter(const Slice* keys, int n, std::string* dst) const ...
method KeyMayMatch (line 56) | bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const ...
function FilterPolicy (line 88) | const FilterPolicy* NewBloomFilterPolicy(int bits_per_key) {
FILE: util/bloom_test.cc
type leveldb (line 11) | namespace leveldb {
function Slice (line 15) | static Slice Key(int i, char* buffer) {
class BloomTest (line 20) | class BloomTest : public testing::Test {
method BloomTest (line 22) | BloomTest() : policy_(NewBloomFilterPolicy(10)) {}
method Reset (line 26) | void Reset() {
method Add (line 31) | void Add(const Slice& s) { keys_.push_back(s.ToString()); }
method Build (line 33) | void Build() {
method FilterSize (line 45) | size_t FilterSize() const { return filter_.size(); }
method DumpFilter (line 47) | void DumpFilter() {
method Matches (line 58) | bool Matches(const Slice& s) {
method FalsePositiveRate (line 65) | double FalsePositiveRate() {
function TEST_F (line 82) | TEST_F(BloomTest, EmptyFilter) {
function TEST_F (line 87) | TEST_F(BloomTest, Small) {
function NextLength (line 96) | static int NextLength(int length) {
function TEST_F (line 109) | TEST_F(BloomTest, VaryingLengths) {
FILE: util/cache.cc
type leveldb (line 16) | namespace leveldb {
type LRUHandle (line 43) | struct LRUHandle {
method Slice (line 56) | Slice key() const {
class HandleTable (line 70) | class HandleTable {
method HandleTable (line 72) | HandleTable() : length_(0), elems_(0), list_(nullptr) { Resize(); }
method LRUHandle (line 75) | LRUHandle* Lookup(const Slice& key, uint32_t hash) {
method LRUHandle (line 79) | LRUHandle* Insert(LRUHandle* h) {
method LRUHandle (line 95) | LRUHandle* Remove(const Slice& key, uint32_t hash) {
method LRUHandle (line 115) | LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
method Resize (line 123) | void Resize() {
class LRUCache (line 151) | class LRUCache {
method SetCapacity (line 157) | void SetCapacity(size_t capacity) { capacity_ = capacity; }
method TotalCharge (line 167) | size_t TotalCharge() const {
class ShardedLRUCache (line 339) | class ShardedLRUCache : public Cache {
method HashSlice (line 345) | static inline uint32_t HashSlice(const Slice& s) {
method Shard (line 349) | static uint32_t Shard(uint32_t hash) { return hash >> (32 - kNumShar...
method ShardedLRUCache (line 352) | explicit ShardedLRUCache(size_t capacity) : last_id_(0) {
method Handle (line 359) | Handle* Insert(const Slice& key, void* value, size_t charge,
method Handle (line 364) | Handle* Lookup(const Slice& key) override {
method Release (line 368) | void Release(Handle* handle) override {
method Erase (line 372) | void Erase(const Slice& key) override {
method NewId (line 379) | uint64_t NewId() override {
method Prune (line 383) | void Prune() override {
method TotalCharge (line 388) | size_t TotalCharge() const override {
function Cache (line 399) | Cache* NewLRUCache(size_t capacity) { return new ShardedLRUCache(capac...
FILE: util/cache_test.cc
type leveldb (line 12) | namespace leveldb {
function EncodeKey (line 15) | static std::string EncodeKey(int k) {
function DecodeKey (line 20) | static int DecodeKey(const Slice& k) {
function DecodeValue (line 25) | static int DecodeValue(void* v) { return reinterpret_cast<uintptr_t>(v...
class CacheTest (line 27) | class CacheTest : public testing::Test {
method Deleter (line 29) | static void Deleter(const Slice& key, void* v) {
method CacheTest (line 39) | CacheTest() : cache_(NewLRUCache(kCacheSize)) { current_ = this; }
method Lookup (line 43) | int Lookup(int key) {
method Insert (line 52) | void Insert(int key, int value, int charge = 1) {
method Erase (line 62) | void Erase(int key) { cache_->Erase(EncodeKey(key)); }
function TEST_F (line 67) | TEST_F(CacheTest, HitAndMiss) {
function TEST_F (line 90) | TEST_F(CacheTest, Erase) {
function TEST_F (line 109) | TEST_F(CacheTest, EntriesArePinned) {
function TEST_F (line 134) | TEST_F(CacheTest, EvictionPolicy) {
function TEST_F (line 153) | TEST_F(CacheTest, UseExceedsCacheSize) {
function TEST_F (line 170) | TEST_F(CacheTest, HeavyEntries) {
function TEST_F (line 197) | TEST_F(CacheTest, NewId) {
function TEST_F (line 203) | TEST_F(CacheTest, Prune) {
function TEST_F (line 216) | TEST_F(CacheTest, ZeroSizeCache) {
FILE: util/coding.cc
type leveldb (line 7) | namespace leveldb {
function PutFixed32 (line 9) | void PutFixed32(std::string* dst, uint32_t value) {
function PutFixed64 (line 15) | void PutFixed64(std::string* dst, uint64_t value) {
function PutVarint32 (line 49) | void PutVarint32(std::string* dst, uint32_t v) {
function PutVarint64 (line 66) | void PutVarint64(std::string* dst, uint64_t v) {
function PutLengthPrefixedSlice (line 72) | void PutLengthPrefixedSlice(std::string* dst, const Slice& value) {
function VarintLength (line 77) | int VarintLength(uint64_t v) {
function GetVarint32 (line 104) | bool GetVarint32(Slice* input, uint32_t* value) {
function GetVarint64 (line 133) | bool GetVarint64(Slice* input, uint64_t* value) {
function GetLengthPrefixedSlice (line 145) | bool GetLengthPrefixedSlice(Slice* input, Slice* result) {
FILE: util/coding.h
function namespace (line 20) | namespace leveldb {
FILE: util/coding_test.cc
type leveldb (line 11) | namespace leveldb {
function TEST (line 13) | TEST(Coding, Fixed32) {
function TEST (line 27) | TEST(Coding, Fixed64) {
function TEST (line 55) | TEST(Coding, EncodingOutput) {
function TEST (line 77) | TEST(Coding, Varint32) {
function TEST (line 98) | TEST(Coding, Varint64) {
function TEST (line 133) | TEST(Coding, Varint32Overflow) {
function TEST (line 140) | TEST(Coding, Varint32Truncation) {
function TEST (line 153) | TEST(Coding, Varint64Overflow) {
function TEST (line 160) | TEST(Coding, Varint64Truncation) {
function TEST (line 173) | TEST(Coding, Strings) {
FILE: util/comparator.cc
type leveldb (line 16) | namespace leveldb {
class BytewiseComparatorImpl (line 21) | class BytewiseComparatorImpl : public Comparator {
method BytewiseComparatorImpl (line 23) | BytewiseComparatorImpl() = default;
method Compare (line 27) | int Compare(const Slice& a, const Slice& b) const override {
method FindShortestSeparator (line 31) | void FindShortestSeparator(std::string* start,
method FindShortSuccessor (line 54) | void FindShortSuccessor(std::string* key) const override {
function Comparator (line 70) | const Comparator* BytewiseComparator() {
FILE: util/crc32c.cc
type leveldb (line 15) | namespace leveldb {
type crc32c (line 16) | namespace crc32c {
function ReadUint32LE (line 249) | inline uint32_t ReadUint32LE(const uint8_t* buffer) {
function CanAccelerateCRC32C (line 267) | static bool CanAccelerateCRC32C() {
function Extend (line 276) | uint32_t Extend(uint32_t crc, const char* data, size_t n) {
FILE: util/crc32c.h
function namespace (line 11) | namespace leveldb {
FILE: util/crc32c_test.cc
type leveldb (line 9) | namespace leveldb {
type crc32c (line 10) | namespace crc32c {
function TEST (line 12) | TEST(CRC, StandardResults) {
function TEST (line 41) | TEST(CRC, Values) { ASSERT_NE(Value("a", 1), Value("foo", 3)); }
function TEST (line 43) | TEST(CRC, Extend) {
function TEST (line 47) | TEST(CRC, Mask) {
FILE: util/env.cc
type leveldb (line 15) | namespace leveldb {
function Status (line 21) | Status Env::NewAppendableFile(const std::string& fname, WritableFile**...
function Status (line 25) | Status Env::RemoveDir(const std::string& dirname) { return DeleteDir(d...
function Status (line 26) | Status Env::DeleteDir(const std::string& dirname) { return RemoveDir(d...
function Status (line 28) | Status Env::RemoveFile(const std::string& fname) { return DeleteFile(f...
function Status (line 29) | Status Env::DeleteFile(const std::string& fname) { return RemoveFile(f...
function Log (line 41) | void Log(Logger* info_log, const char* format, ...) {
function Status (line 50) | static Status DoWriteStringToFile(Env* env, const Slice& data,
function Status (line 71) | Status WriteStringToFile(Env* env, const Slice& data,
function Status (line 76) | Status WriteStringToFileSync(Env* env, const Slice& data,
function Status (line 81) | Status ReadFileToString(Env* env, const std::string& fname, std::strin...
FILE: util/env_posix.cc
function Status (line 61) | Status PosixError(const std::string& context, int error_number) {
class Limiter (line 73) | class Limiter {
method Limiter (line 85) | Limiter(const Limiter&) = delete;
method Limiter (line 86) | Limiter operator=(const Limiter&) = delete;
method Acquire (line 90) | bool Acquire() {
method Release (line 109) | void Release() {
class PosixSequentialFile (line 136) | class PosixSequentialFile final : public SequentialFile {
method PosixSequentialFile (line 138) | PosixSequentialFile(std::string filename, int fd)
method Status (line 142) | Status Read(size_t n, Slice* result, char* scratch) override {
method Status (line 159) | Status Skip(uint64_t n) override {
class PosixRandomAccessFile (line 176) | class PosixRandomAccessFile final : public RandomAccessFile {
method PosixRandomAccessFile (line 180) | PosixRandomAccessFile(std::string filename, int fd, Limiter* fd_limi...
method Status (line 199) | Status Read(uint64_t offset, size_t n, Slice* result,
class PosixMmapReadableFile (line 238) | class PosixMmapReadableFile final : public RandomAccessFile {
method PosixMmapReadableFile (line 247) | PosixMmapReadableFile(std::string filename, char* mmap_base, size_t ...
method Status (line 259) | Status Read(uint64_t offset, size_t n, Slice* result,
class PosixWritableFile (line 277) | class PosixWritableFile final : public WritableFile {
method PosixWritableFile (line 279) | PosixWritableFile(std::string filename, int fd)
method Status (line 293) | Status Append(const Slice& data) override {
method Status (line 322) | Status Close() override {
method Status (line 332) | Status Flush() override { return FlushBuffer(); }
method Status (line 334) | Status Sync() override {
method Status (line 354) | Status FlushBuffer() {
method Status (line 360) | Status WriteUnbuffered(const char* data, size_t size) {
method Status (line 375) | Status SyncDirIfManifest() {
method Status (line 397) | static Status SyncFd(int fd, const std::string& fd_path) {
method Dirname (line 423) | static std::string Dirname(const std::string& filename) {
method Slice (line 439) | static Slice Basename(const std::string& filename) {
method IsManifest (line 453) | static bool IsManifest(const std::string& filename) {
method LockOrUnlock (line 467) | int LockOrUnlock(int fd, bool lock) {
class PosixFileLock (line 479) | class PosixFileLock : public FileLock {
method PosixFileLock (line 481) | PosixFileLock(int fd, std::string filename)
method fd (line 484) | int fd() const { return fd_; }
class PosixLockTable (line 499) | class PosixLockTable {
method LOCKS_EXCLUDED (line 501) | LOCKS_EXCLUDED(mu_) {
method LOCKS_EXCLUDED (line 507) | LOCKS_EXCLUDED(mu_) {
class PosixEnv (line 518) | class PosixEnv : public Env {
method Status (line 528) | Status NewSequentialFile(const std::string& filename,
method Status (line 540) | Status NewRandomAccessFile(const std::string& filename,
method Status (line 573) | Status NewWritableFile(const std::string& filename,
method Status (line 586) | Status NewAppendableFile(const std::string& filename,
method FileExists (line 599) | bool FileExists(const std::string& filename) override {
method Status (line 603) | Status GetChildren(const std::string& directory_path,
method Status (line 618) | Status RemoveFile(const std::string& filename) override {
method Status (line 625) | Status CreateDir(const std::string& dirname) override {
method Status (line 632) | Status RemoveDir(const std::string& dirname) override {
method Status (line 639) | Status GetFileSize(const std::string& filename, uint64_t* size) over...
method Status (line 649) | Status RenameFile(const std::string& from, const std::string& to) ov...
method Status (line 656) | Status LockFile(const std::string& filename, FileLock** lock) overri...
method Status (line 680) | Status UnlockFile(FileLock* lock) override {
method StartThread (line 694) | void StartThread(void (*thread_main)(void* thread_main_arg),
method Status (line 700) | Status GetTestDirectory(std::string* result) override {
method Status (line 717) | Status NewLogger(const std::string& filename, Logger** result) overr...
method NowMicros (line 736) | uint64_t NowMicros() override {
method SleepForMicroseconds (line 743) | void SleepForMicroseconds(int micros) override {
method BackgroundThreadEntryPoint (line 750) | static void BackgroundThreadEntryPoint(PosixEnv* env) {
type BackgroundWorkItem (line 760) | struct BackgroundWorkItem {
method BackgroundWorkItem (line 761) | explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
method MaxMmaps (line 781) | int MaxMmaps() { return g_mmap_limit; }
method MaxOpenFiles (line 784) | int MaxOpenFiles() {
method namespace (line 854) | namespace {
method Env (line 924) | Env* Env::Default() {
FILE: util/env_posix_test.cc
function TestCloseOnExecHelperMain (line 59) | int TestCloseOnExecHelperMain(char* pid_arg) {
function GetMaxFileDescriptor (line 79) | void GetMaxFileDescriptor(int* result_fd) {
function GetOpenFileDescriptors (line 89) | void GetOpenFileDescriptors(std::unordered_set<int>* open_fds) {
function GetNewlyOpenedFileDescriptor (line 113) | void GetNewlyOpenedFileDescriptor(
function CheckCloseOnExecDoesNotLeakFDs (line 128) | void CheckCloseOnExecDoesNotLeakFDs(
type leveldb (line 167) | namespace leveldb {
class EnvPosixTest (line 172) | class EnvPosixTest : public testing::Test {
method SetFileLimits (line 174) | static void SetFileLimits(int read_only_file_limit, int mmap_limit) {
method EnvPosixTest (line 179) | EnvPosixTest() : env_(Env::Default()) {}
function TEST_F (line 184) | TEST_F(EnvPosixTest, TestOpenOnRead) {
function TEST_F (line 217) | TEST_F(EnvPosixTest, TestCloseOnExecSequentialFile) {
function TEST_F (line 234) | TEST_F(EnvPosixTest, TestCloseOnExecRandomAccessFile) {
function TEST_F (line 262) | TEST_F(EnvPosixTest, TestCloseOnExecWritableFile) {
function TEST_F (line 279) | TEST_F(EnvPosixTest, TestCloseOnExecAppendableFile) {
function TEST_F (line 296) | TEST_F(EnvPosixTest, TestCloseOnExecLockFile) {
function TEST_F (line 313) | TEST_F(EnvPosixTest, TestCloseOnExecLogger) {
function main (line 334) | int main(int argc, char** argv) {
FILE: util/env_posix_test_helper.h
function namespace (line 8) | namespace leveldb {
FILE: util/env_test.cc
type leveldb (line 15) | namespace leveldb {
class EnvTest (line 17) | class EnvTest : public testing::Test {
method EnvTest (line 19) | EnvTest() : env_(Env::Default()) {}
function TEST_F (line 24) | TEST_F(EnvTest, ReadWrite) {
function TEST_F (line 71) | TEST_F(EnvTest, RunImmediately) {
function TEST_F (line 95) | TEST_F(EnvTest, RunMany) {
type State (line 140) | struct State {
method State (line 147) | State(int val, int num_running) : val(val), num_running(num_running) {}
function ThreadBody (line 150) | static void ThreadBody(void* arg) {
function TEST_F (line 159) | TEST_F(EnvTest, StartThread) {
function TEST_F (line 172) | TEST_F(EnvTest, TestOpenNonExistentFile) {
function TEST_F (line 200) | TEST_F(EnvTest, ReopenWritableFile) {
function TEST_F (line 224) | TEST_F(EnvTest, ReopenAppendableFile) {
FILE: util/env_windows.cc
function GetWindowsErrorMessage (line 48) | std::string GetWindowsErrorMessage(DWORD error_code) {
function Status (line 65) | Status WindowsError(const std::string& context, DWORD error_code) {
class ScopedHandle (line 71) | class ScopedHandle {
method ScopedHandle (line 73) | ScopedHandle(HANDLE handle) : handle_(handle) {}
method ScopedHandle (line 74) | ScopedHandle(const ScopedHandle&) = delete;
method ScopedHandle (line 75) | ScopedHandle(ScopedHandle&& other) noexcept : handle_(other.Release()) {}
method ScopedHandle (line 78) | ScopedHandle& operator=(const ScopedHandle&) = delete;
method ScopedHandle (line 80) | ScopedHandle& operator=(ScopedHandle&& rhs) noexcept {
method Close (line 85) | bool Close() {
method is_valid (line 94) | bool is_valid() const {
method HANDLE (line 98) | HANDLE get() const { return handle_; }
method HANDLE (line 100) | HANDLE Release() {
class Limiter (line 114) | class Limiter {
method Limiter (line 126) | Limiter(const Limiter&) = delete;
method Limiter (line 127) | Limiter operator=(const Limiter&) = delete;
method Acquire (line 131) | bool Acquire() {
method Release (line 143) | void Release() {
class WindowsSequentialFile (line 166) | class WindowsSequentialFile : public SequentialFile {
method WindowsSequentialFile (line 168) | WindowsSequentialFile(std::string filename, ScopedHandle handle)
method Status (line 172) | Status Read(size_t n, Slice* result, char* scratch) override {
method Status (line 187) | Status Skip(uint64_t n) override {
class WindowsRandomAccessFile (line 201) | class WindowsRandomAccessFile : public RandomAccessFile {
method WindowsRandomAccessFile (line 203) | WindowsRandomAccessFile(std::string filename, ScopedHandle handle)
method Status (line 208) | Status Read(uint64_t offset, size_t n, Slice* result,
class WindowsMmapReadableFile (line 233) | class WindowsMmapReadableFile : public RandomAccessFile {
method WindowsMmapReadableFile (line 236) | WindowsMmapReadableFile(std::string filename, char* mmap_base, size_...
method Status (line 248) | Status Read(uint64_t offset, size_t n, Slice* result,
class WindowsWritableFile (line 266) | class WindowsWritableFile : public WritableFile {
method WindowsWritableFile (line 268) | WindowsWritableFile(std::string filename, ScopedHandle handle)
method Status (line 273) | Status Append(const Slice& data) override {
method Status (line 302) | Status Close() override {
method Status (line 310) | Status Flush() override { return FlushBuffer(); }
method Status (line 312) | Status Sync() override {
method Status (line 329) | Status FlushBuffer() {
method Status (line 335) | Status WriteUnbuffered(const char* data, size_t size) {
method LockOrUnlock (line 356) | bool LockOrUnlock(HANDLE handle, bool lock) {
class WindowsFileLock (line 370) | class WindowsFileLock : public FileLock {
method WindowsFileLock (line 372) | WindowsFileLock(ScopedHandle handle, std::string filename)
method ScopedHandle (line 375) | const ScopedHandle& handle() const { return handle_; }
class WindowsEnv (line 383) | class WindowsEnv : public Env {
method Status (line 393) | Status NewSequentialFile(const std::string& filename,
method Status (line 410) | Status NewRandomAccessFile(const std::string& filename,
method Status (line 457) | Status NewWritableFile(const std::string& filename,
method Status (line 474) | Status NewAppendableFile(const std::string& filename,
method FileExists (line 491) | bool FileExists(const std::string& filename) override {
method Status (line 495) | Status GetChildren(const std::string& directory_path,
method Status (line 524) | Status RemoveFile(const std::string& filename) override {
method Status (line 531) | Status CreateDir(const std::string& dirname) override {
method Status (line 538) | Status RemoveDir(const std::string& dirname) override {
method Status (line 545) | Status GetFileSize(const std::string& filename, uint64_t* size) over...
method Status (line 558) | Status RenameFile(const std::string& from, const std::string& to) ov...
method Status (line 587) | Status LockFile(const std::string& filename, FileLock** lock) overri...
method Status (line 604) | Status UnlockFile(FileLock* lock) override {
method StartThread (line 618) | void StartThread(void (*thread_main)(void* thread_main_arg),
method Status (line 624) | Status GetTestDirectory(std::string* result) override {
method Status (line 644) | Status NewLogger(const std::string& filename, Logger** result) overr...
method NowMicros (line 655) | uint64_t NowMicros() override {
method SleepForMicroseconds (line 668) | void SleepForMicroseconds(int micros) override {
method BackgroundThreadEntryPoint (line 675) | static void BackgroundThreadEntryPoint(WindowsEnv* env) {
type BackgroundWorkItem (line 685) | struct BackgroundWorkItem {
method BackgroundWorkItem (line 686) | explicit BackgroundWorkItem(void (*function)(void* arg), void* arg)
method MaxMmaps (line 704) | int MaxMmaps() { return g_mmap_limit; }
class SingletonEnv (line 764) | class SingletonEnv {
method SingletonEnv (line 766) | SingletonEnv() {
method SingletonEnv (line 782) | SingletonEnv(const SingletonEnv&) = delete;
method SingletonEnv (line 783) | SingletonEnv& operator=(const SingletonEnv&) = delete;
method Env (line 785) | Env* env() { return reinterpret_cast<Env*>(&env_storage_); }
method AssertEnvNotInitialized (line 787) | static void AssertEnvNotInitialized() {
method Env (line 814) | Env* Env::Default() {
FILE: util/env_windows_test.cc
type leveldb (line 11) | namespace leveldb {
class EnvWindowsTest (line 15) | class EnvWindowsTest : public testing::Test {
method SetFileLimits (line 17) | static void SetFileLimits(int mmap_limit) {
method EnvWindowsTest (line 21) | EnvWindowsTest() : env_(Env::Default()) {}
function TEST_F (line 26) | TEST_F(EnvWindowsTest, TestOpenOnRead) {
function main (line 60) | int main(int argc, char** argv) {
FILE: util/env_windows_test_helper.h
function namespace (line 8) | namespace leveldb {
FILE: util/filter_policy.cc
type leveldb (line 7) | namespace leveldb {
FILE: util/hash.cc
type leveldb (line 20) | namespace leveldb {
function Hash (line 22) | uint32_t Hash(const char* data, size_t n, uint32_t seed) {
FILE: util/hash.h
function namespace (line 13) | namespace leveldb {
FILE: util/hash_test.cc
type leveldb (line 9) | namespace leveldb {
function TEST (line 11) | TEST(HASH, SignedUnsignedIssue) {
FILE: util/histogram.cc
type leveldb (line 12) | namespace leveldb {
FILE: util/histogram.h
function namespace (line 10) | namespace leveldb {
FILE: util/logging.cc
type leveldb (line 15) | namespace leveldb {
function AppendNumberTo (line 17) | void AppendNumberTo(std::string* str, uint64_t num) {
function AppendEscapedStringTo (line 23) | void AppendEscapedStringTo(std::string* str, const Slice& value) {
function NumberToString (line 37) | std::string NumberToString(uint64_t num) {
function EscapeString (line 43) | std::string EscapeString(const Slice& value) {
function ConsumeDecimalNumber (line 49) | bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
FILE: util/logging.h
function namespace (line 17) | namespace leveldb {
FILE: util/logging_test.cc
type leveldb (line 13) | namespace leveldb {
function TEST (line 15) | TEST(Logging, NumberToString) {
function ConsumeDecimalNumberRoundtripTest (line 40) | void ConsumeDecimalNumberRoundtripTest(uint64_t number,
function TEST (line 53) | TEST(Logging, ConsumeDecimalNumberRoundtrip) {
function TEST (line 75) | TEST(Logging, ConsumeDecimalNumberRoundtripWithPadding) {
function ConsumeDecimalNumberOverflowTest (line 93) | void ConsumeDecimalNumberOverflowTest(const std::string& input_string) {
function TEST (line 100) | TEST(Logging, ConsumeDecimalNumberOverflow) {
function ConsumeDecimalNumberNoDigitsTest (line 120) | void ConsumeDecimalNumberNoDigitsTest(const std::string& input_string) {
function TEST (line 129) | TEST(Logging, ConsumeDecimalNumberNoDigits) {
FILE: util/mutexlock.h
function namespace (line 11) | namespace leveldb {
FILE: util/no_destructor.h
function namespace (line 12) | namespace leveldb {
FILE: util/no_destructor_test.cc
type leveldb (line 13) | namespace leveldb {
type DoNotDestruct (line 17) | struct DoNotDestruct {
method DoNotDestruct (line 19) | DoNotDestruct(uint32_t a, uint64_t b) : a(a), b(b) {}
function TEST (line 32) | TEST(NoDestructorTest, StackInstance) {
function TEST (line 38) | TEST(NoDestructorTest, StaticInstance) {
FILE: util/options.cc
type leveldb (line 10) | namespace leveldb {
FILE: util/posix_logger.h
function namespace (line 22) | namespace leveldb {
FILE: util/random.h
function namespace (line 10) | namespace leveldb {
FILE: util/status.cc
type leveldb (line 11) | namespace leveldb {
FILE: util/status_test.cc
type leveldb (line 12) | namespace leveldb {
function TEST (line 14) | TEST(Status, MoveConstructor) {
FILE: util/testutil.cc
type leveldb (line 11) | namespace leveldb {
type test (line 12) | namespace test {
function Slice (line 14) | Slice RandomString(Random* rnd, int len, std::string* dst) {
function RandomKey (line 22) | std::string RandomKey(Random* rnd, int len) {
function Slice (line 34) | Slice CompressibleString(Random* rnd, double compressed_fraction, si...
FILE: util/testutil.h
function namespace (line 15) | namespace leveldb {
FILE: util/windows_logger.h
function namespace (line 19) | namespace leveldb {
Condensed preview — 152 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,038K chars).
[
{
"path": ".clang-format",
"chars": 707,
"preview": "# Run manually to reformat a file:\n# clang-format -i --style=file <file>\n# find . -iname '*.cc' -o -iname '*.h' -o -inam"
},
{
"path": ".github/workflows/build.yml",
"chars": 3203,
"preview": "# Copyright 2021 The LevelDB Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license "
},
{
"path": ".gitignore",
"chars": 67,
"preview": "# Editors.\n*.sw*\n.vscode\n.DS_Store\n\n# Build directory.\nbuild/\nout/\n"
},
{
"path": ".gitmodules",
"chars": 225,
"preview": "[submodule \"third_party/googletest\"]\n\tpath = third_party/googletest\n\turl = https://github.com/google/googletest.git\n[sub"
},
{
"path": "AUTHORS",
"chars": 293,
"preview": "# Names should be added to this file like so:\n# Name or Organization <email address>\n\nGoogle Inc.\n\n# Initial version aut"
},
{
"path": "CMakeLists.txt",
"chars": 16127,
"preview": "# Copyright 2017 The LevelDB Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license "
},
{
"path": "CONTRIBUTING.md",
"chars": 1225,
"preview": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guid"
},
{
"path": "LICENSE",
"chars": 1484,
"preview": "Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or"
},
{
"path": "NEWS",
"chars": 509,
"preview": "Release 1.2 2011-05-16\n----------------------\n\nFixes for larger databases (tested up to one billion 100-byte entries,\ni."
},
{
"path": "README.md",
"chars": 10483,
"preview": "LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to strin"
},
{
"path": "TODO",
"chars": 535,
"preview": "ss\n- Stats\n\ndb\n- Maybe implement DB::BulkDeleteForRange(start_key, end_key)\n that would blow away files whose ranges ar"
},
{
"path": "benchmarks/db_bench.cc",
"chars": 34930,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "benchmarks/db_bench_log.cc",
"chars": 2555,
"preview": "// Copyright (c) 2019 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "benchmarks/db_bench_sqlite3.cc",
"chars": 23224,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "benchmarks/db_bench_tree_db.cc",
"chars": 16213,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "cmake/leveldbConfig.cmake.in",
"chars": 319,
"preview": "# Copyright 2019 The LevelDB Authors. All rights reserved.\n# Use of this source code is governed by a BSD-style license "
},
{
"path": "db/autocompact_test.cc",
"chars": 3386,
"preview": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/builder.cc",
"chars": 2014,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/builder.h",
"chars": 988,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/c.cc",
"chars": 17052,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/c_test.c",
"chars": 11593,
"preview": "/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n Use of this source code is governed by a BSD-style li"
},
{
"path": "db/corruption_test.cc",
"chars": 10072,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/db_impl.cc",
"chars": 49868,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/db_impl.h",
"chars": 7628,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/db_iter.cc",
"chars": 8962,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/db_iter.h",
"chars": 823,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/db_test.cc",
"chars": 71488,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/dbformat.cc",
"chars": 4520,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/dbformat.h",
"chars": 7678,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/dbformat_test.cc",
"chars": 4345,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/dumpfile.cc",
"chars": 6343,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/fault_injection_test.cc",
"chars": 15811,
"preview": "// Copyright 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licens"
},
{
"path": "db/filename.cc",
"chars": 4089,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/filename.h",
"chars": 2892,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/filename_test.cc",
"chars": 4182,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/leveldbutil.cc",
"chars": 1567,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_format.h",
"chars": 896,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_reader.cc",
"chars": 8871,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_reader.h",
"chars": 3769,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_test.cc",
"chars": 15880,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_writer.cc",
"chars": 3132,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/log_writer.h",
"chars": 1500,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/memtable.cc",
"chars": 4947,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/memtable.h",
"chars": 2658,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/recovery_test.cc",
"chars": 9361,
"preview": "// Copyright (c) 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/repair.cc",
"chars": 13673,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/skiplist.h",
"chars": 11281,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/skiplist_test.cc",
"chars": 9798,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/snapshot.h",
"chars": 2667,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/table_cache.cc",
"chars": 3610,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/table_cache.h",
"chars": 2036,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_edit.cc",
"chars": 6778,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_edit.h",
"chars": 2938,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_edit_test.cc",
"chars": 1235,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_set.cc",
"chars": 51463,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_set.h",
"chars": 14021,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/version_set_test.cc",
"chars": 10931,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/write_batch.cc",
"chars": 4166,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/write_batch_internal.h",
"chars": 1520,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "db/write_batch_test.cc",
"chars": 3690,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "doc/benchmark.html",
"chars": 20938,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<title>LevelDB Benchmarks</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; char"
},
{
"path": "doc/impl.md",
"chars": 7874,
"preview": "## Files\n\nThe implementation of leveldb is similar in spirit to the representation of a\nsingle [Bigtable tablet (section"
},
{
"path": "doc/index.md",
"chars": 18978,
"preview": "leveldb\n=======\n\n_Jeff Dean, Sanjay Ghemawat_\n\nThe leveldb library provides a persistent key value store. Keys and value"
},
{
"path": "doc/log_format.md",
"chars": 2921,
"preview": "leveldb Log format\n==================\nThe log file contents are a sequence of 32KB blocks. The only exception is that\nt"
},
{
"path": "doc/table_format.md",
"chars": 3790,
"preview": "leveldb File format\n===================\n\n <beginning_of_file>\n [data block 1]\n [data block 2]\n ...\n [data"
},
{
"path": "helpers/memenv/memenv.cc",
"chars": 9875,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "helpers/memenv/memenv.h",
"chars": 743,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "helpers/memenv/memenv_test.cc",
"chars": 8416,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/c.h",
"chars": 12045,
"preview": "/* Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n Use of this source code is governed by a BSD-style lic"
},
{
"path": "include/leveldb/cache.h",
"chars": 4009,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/comparator.h",
"chars": 2425,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/db.h",
"chars": 6803,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/dumpfile.h",
"chars": 951,
"preview": "// Copyright (c) 2014 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/env.h",
"chars": 16040,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/export.h",
"chars": 911,
"preview": "// Copyright (c) 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/filter_policy.h",
"chars": 3021,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/iterator.h",
"chars": 4001,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/options.h",
"chars": 7523,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/slice.h",
"chars": 3355,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/status.h",
"chars": 3961,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/table.h",
"chars": 3014,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/table_builder.h",
"chars": 3441,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "include/leveldb/write_batch.h",
"chars": 2535,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "issues/issue178_test.cc",
"chars": 2523,
"preview": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "issues/issue200_test.cc",
"chars": 1685,
"preview": "// Copyright (c) 2013 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "issues/issue320_test.cc",
"chars": 3611,
"preview": "// Copyright (c) 2019 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "port/README.md",
"chars": 406,
"preview": "This directory contains interfaces and implementations that isolate the\nrest of the package from platform details.\n\nCode"
},
{
"path": "port/port.h",
"chars": 731,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "port/port_config.h.in",
"chars": 1218,
"preview": "// Copyright 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licens"
},
{
"path": "port/port_example.h",
"chars": 4513,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "port/port_stdcxx.h",
"chars": 5713,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "port/thread_annotations.h",
"chars": 3113,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/block.cc",
"chars": 8962,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/block.h",
"chars": 1023,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/block_builder.cc",
"chars": 3620,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/block_builder.h",
"chars": 1737,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/filter_block.cc",
"chars": 3428,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/filter_block.h",
"chars": 2275,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/filter_block_test.cc",
"chars": 3623,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/format.cc",
"chars": 5331,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/format.h",
"chars": 3064,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/iterator.cc",
"chars": 1847,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/iterator_wrapper.h",
"chars": 2106,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/merger.cc",
"chars": 4974,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/merger.h",
"chars": 884,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/table.cc",
"chars": 8351,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/table_builder.cc",
"chars": 8635,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/table_test.cc",
"chars": 24724,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/two_level_iterator.cc",
"chars": 4864,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "table/two_level_iterator.h",
"chars": 1219,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/arena.cc",
"chars": 2022,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/arena.h",
"chars": 1897,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/arena_test.cc",
"chars": 1593,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/bloom.cc",
"chars": 2927,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/bloom_test.cc",
"chars": 3828,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/cache.cc",
"chars": 12092,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/cache_test.cc",
"chars": 5863,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/coding.cc",
"chars": 3913,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/coding.h",
"chars": 4830,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/coding_test.cc",
"chars": 5537,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/comparator.cc",
"chars": 2137,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/crc32c.cc",
"chars": 21150,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/crc32c.h",
"chars": 1446,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/crc32c_test.cc",
"chars": 1608,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env.cc",
"chars": 2832,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_posix.cc",
"chars": 27740,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_posix_test.cc",
"chars": 12166,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_posix_test_helper.h",
"chars": 896,
"preview": "// Copyright 2017 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style licens"
},
{
"path": "util/env_test.cc",
"chars": 7166,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_windows.cc",
"chars": 26313,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_windows_test.cc",
"chars": 2022,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/env_windows_test_helper.h",
"chars": 787,
"preview": "// Copyright 2018 (c) The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/filter_policy.cc",
"chars": 332,
"preview": "// Copyright (c) 2012 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/hash.cc",
"chars": 1389,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/hash.h",
"chars": 537,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/hash_test.cc",
"chars": 1467,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/histogram.cc",
"chars": 5291,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/histogram.h",
"chars": 925,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/logging.cc",
"chars": 2204,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/logging.h",
"chars": 1400,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/logging_test.cc",
"chars": 5167,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/mutexlock.h",
"chars": 1122,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/no_destructor.h",
"chars": 1768,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/no_destructor_test.cc",
"chars": 1106,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/options.cc",
"chars": 429,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/posix_logger.h",
"chars": 4701,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/random.h",
"chars": 2173,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/status.cc",
"chars": 2021,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/status_test.cc",
"chars": 991,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/testutil.cc",
"chars": 1496,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/testutil.h",
"chars": 2673,
"preview": "// Copyright (c) 2011 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
},
{
"path": "util/windows_logger.h",
"chars": 4477,
"preview": "// Copyright (c) 2018 The LevelDB Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style li"
}
]
About this extraction
This page contains the full source code of the google/leveldb GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 152 files (969.1 KB), approximately 268.1k tokens, and a symbol index with 1438 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.