mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 22:55:23 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfaeb5846b | |||
| 62e9418a70 | |||
| 03df818cff | |||
| 96a092b1a3 | |||
| d59fdc3946 | |||
| e96d06c816 | |||
| b86f89f25b | |||
| 48cf039064 | |||
| c39939d468 | |||
| 65afd8a1cc | |||
| 6df239cfee | |||
| 54c4b3ab4f | |||
| 27768b0ec3 | |||
| 8673a8c567 | |||
| 6124420d5d | |||
| 258fd9ac46 |
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"project_id" : "rocksdb",
|
||||
"conduit_uri" : "https://phabricator.fb.com/api/",
|
||||
"copyright_holder" : "Facebook",
|
||||
"load" : [
|
||||
"arcanist_util"
|
||||
],
|
||||
"lint.engine" : "FacebookFbcodeLintEngine",
|
||||
"lint.engine.single.linter" : "FbcodeCppLinter",
|
||||
"unit.engine" : "FacebookFbcodeUnitTestEngine",
|
||||
"arcanist_configuration" : "FacebookArcanistConfiguration",
|
||||
"base" : "git:HEAD^, hg:.^",
|
||||
"git.default-relative-commit" : "HEAD^",
|
||||
"git:arc.feature.start.default" : "origin/master",
|
||||
"arc.feature.start.default" : "master",
|
||||
"history.immutable" : false
|
||||
}
|
||||
@@ -39,6 +39,7 @@ coverage/COVERAGE_REPORT
|
||||
.gdbhistory
|
||||
.gdb_history
|
||||
package/
|
||||
.phutil_module_cache
|
||||
unity.a
|
||||
tags
|
||||
etags
|
||||
|
||||
+7
-19
@@ -20,9 +20,7 @@ addons:
|
||||
env:
|
||||
- TEST_GROUP=platform_dependent # 16-18 minutes
|
||||
- TEST_GROUP=1 # 33-35 minutes
|
||||
- TEST_GROUP=2 # 18-20 minutes
|
||||
- TEST_GROUP=3 # 20-22 minutes
|
||||
- TEST_GROUP=4 # 12-14 minutes
|
||||
- TEST_GROUP=2 # 30-32 minutes
|
||||
# Run java tests
|
||||
- JOB_NAME=java_test # 4-11 minutes
|
||||
# Build ROCKSDB_LITE
|
||||
@@ -38,10 +36,6 @@ matrix:
|
||||
env: TEST_GROUP=1
|
||||
- os: osx
|
||||
env: TEST_GROUP=2
|
||||
- os: osx
|
||||
env: TEST_GROUP=3
|
||||
- os: osx
|
||||
env: TEST_GROUP=4
|
||||
- os : osx
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os : linux
|
||||
@@ -55,9 +49,6 @@ install:
|
||||
brew install ccache;
|
||||
PATH=$PATH:/usr/local/opt/ccache/libexec;
|
||||
fi
|
||||
- if [[ "${JOB_NAME}" == cmake* ]] && [ "${TRAVIS_OS_NAME}" == linux ]; then
|
||||
mkdir cmake-dist && curl -sfSL https://cmake.org/files/v3.8/cmake-3.8.1-Linux-x86_64.tar.gz | tar --strip-components=1 -C cmake-dist -xz && export PATH=$PWD/cmake-dist/bin:$PATH;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
# Increase the maximum number of open file descriptors, since some tests use
|
||||
@@ -66,17 +57,14 @@ before_script:
|
||||
|
||||
script:
|
||||
- ${CXX} --version
|
||||
- if [ `command -v ccache` ]; then ccache -C; fi
|
||||
- if [ "${TEST_GROUP}" == 'platform_dependent' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_END=db_block_cache_test make -j4 all_but_some_tests check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '1' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=db_block_cache_test ROCKSDBTESTS_END=full_filter_block_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '2' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=full_filter_block_test ROCKSDBTESTS_END=write_batch_with_index_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '3' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=write_batch_with_index_test ROCKSDBTESTS_END=write_prepared_transaction_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '4' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=write_prepared_transaction_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == 'platform_dependent' ]; then OPT=-DTRAVIS V=1 make -j4 all; OPT=-DTRAVIS V=1 ROCKSDBTESTS_END=db_block_cache_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '1' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=db_block_cache_test ROCKSDBTESTS_END=comparator_db_test make -j4 check_some; fi
|
||||
- if [ "${TEST_GROUP}" == '2' ]; then OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=comparator_db_test make -j4 check_some; fi
|
||||
- if [ "${JOB_NAME}" == 'java_test' ]; then OPT=-DTRAVIS V=1 make clean jclean && make rocksdbjava jtest; fi
|
||||
- if [ "${JOB_NAME}" == 'lite_build' ]; then OPT="-DTRAVIS -DROCKSDB_LITE" V=1 make -j4 static_lib tools; fi
|
||||
- if [ "${JOB_NAME}" == 'lite_build' ]; then OPT="-DTRAVIS -DROCKSDB_LITE" V=1 make -j4 static_lib; fi
|
||||
- if [ "${JOB_NAME}" == 'examples' ]; then OPT=-DTRAVIS V=1 make -j4 static_lib; cd examples; make -j4; fi
|
||||
- if [ "${JOB_NAME}" == 'cmake' ]; then mkdir build && cd build && cmake -DJNI=1 .. && make -j4 rocksdb rocksdbjni; fi
|
||||
- if [ "${JOB_NAME}" == 'cmake-mingw' ]; then mkdir build && cd build && cmake -DJNI=1 .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb rocksdbjni; fi
|
||||
- if [ "${JOB_NAME}" == 'cmake' ]; then mkdir build && cd build && cmake .. && make -j4 rocksdb; fi
|
||||
- if [ "${JOB_NAME}" == 'cmake-mingw' ]; then mkdir build && cd build && cmake .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb; fi
|
||||
notifications:
|
||||
email:
|
||||
- leveldb@fb.com
|
||||
|
||||
@@ -9,4 +9,3 @@ Sanjay Ghemawat <sanjay@google.com>
|
||||
# Partial list of contributors:
|
||||
Kevin Regan <kevin.d.regan@gmail.com>
|
||||
Johan Bilien <jobi@litl.com>
|
||||
Matthew Von-Maszewski <https://github.com/matthewvon> (Basho Technologies)
|
||||
|
||||
+167
-390
@@ -14,9 +14,9 @@
|
||||
# cd build
|
||||
# 3. Run cmake to generate project files for Windows, add more options to enable required third-party libraries.
|
||||
# See thirdparty.inc for more information.
|
||||
# sample command: cmake -G "Visual Studio 15 Win64" -DWITH_GFLAGS=1 -DWITH_SNAPPY=1 -DWITH_JEMALLOC=1 -DWITH_JNI=1 ..
|
||||
# sample command: cmake -G "Visual Studio 14 Win64" -DGFLAGS=1 -DSNAPPY=1 -DJEMALLOC=1 -DJNI=1 ..
|
||||
# 4. Then build the project in debug mode (you may want to add /m[:<N>] flag to run msbuild in <N> parallel threads
|
||||
# or simply /m to use all avail cores)
|
||||
# or simply /m ot use all avail cores)
|
||||
# msbuild rocksdb.sln
|
||||
#
|
||||
# rocksdb.sln build features exclusions of test only code in Release. If you build ALL_BUILD then everything
|
||||
@@ -32,31 +32,21 @@
|
||||
# 3. cmake ..
|
||||
# 4. make -j
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(rocksdb)
|
||||
enable_language(CXX)
|
||||
enable_language(C)
|
||||
enable_language(ASM)
|
||||
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
option(WITH_JEMALLOC "build with JeMalloc" OFF)
|
||||
option(WITH_SNAPPY "build with SNAPPY" OFF)
|
||||
option(WITH_LZ4 "build with lz4" OFF)
|
||||
option(WITH_ZLIB "build with zlib" OFF)
|
||||
if(MSVC)
|
||||
# Defaults currently different for GFLAGS.
|
||||
# We will address find_package work a little later
|
||||
option(WITH_GFLAGS "build with GFlags" OFF)
|
||||
option(WITH_XPRESS "build with windows built in compression" OFF)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc)
|
||||
else()
|
||||
option(WITH_JEMALLOC "build with JeMalloc" OFF)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
# FreeBSD has jemalloc as default malloc
|
||||
# FreeBSD has jemaloc as default malloc
|
||||
# but it does not have all the jemalloc files in include/...
|
||||
set(WITH_JEMALLOC ON)
|
||||
else()
|
||||
@@ -64,60 +54,28 @@ else()
|
||||
find_package(JeMalloc REQUIRED)
|
||||
add_definitions(-DROCKSDB_JEMALLOC -DJEMALLOC_NO_DEMANGLE)
|
||||
include_directories(${JEMALLOC_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${JEMALLOC_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# No config file for this
|
||||
option(WITH_GFLAGS "build with GFlags" ON)
|
||||
if(WITH_GFLAGS)
|
||||
find_package(gflags)
|
||||
if(gflags_FOUND)
|
||||
add_definitions(-DGFLAGS=1)
|
||||
include_directories(${gflags_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${gflags_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_SNAPPY "build with SNAPPY" OFF)
|
||||
if(WITH_SNAPPY)
|
||||
find_package(snappy REQUIRED)
|
||||
add_definitions(-DSNAPPY)
|
||||
include_directories(${SNAPPY_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${SNAPPY_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_ZLIB)
|
||||
find_package(zlib REQUIRED)
|
||||
add_definitions(-DZLIB)
|
||||
include_directories(${ZLIB_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WITH_BZ2 "build with bzip2" OFF)
|
||||
if(WITH_BZ2)
|
||||
find_package(bzip2 REQUIRED)
|
||||
add_definitions(-DBZIP2)
|
||||
include_directories(${BZIP2_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${BZIP2_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_LZ4)
|
||||
find_package(lz4 REQUIRED)
|
||||
add_definitions(-DLZ4)
|
||||
include_directories(${LZ4_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${LZ4_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WITH_ZSTD "build with zstd" OFF)
|
||||
if(WITH_ZSTD)
|
||||
find_package(zstd REQUIRED)
|
||||
add_definitions(-DZSTD)
|
||||
include_directories(${ZSTD_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${ZSTD_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(TIMESTAMP GIT_DATE_TIME "%Y/%m/%d %H:%M:%S" UTC)
|
||||
if(WIN32)
|
||||
execute_process(COMMAND powershell -noprofile -Command "Get-Date -format MM_dd_yyyy" OUTPUT_VARIABLE DATE)
|
||||
execute_process(COMMAND powershell -noprofile -Command "Get-Date -format HH:mm:ss" OUTPUT_VARIABLE TIME)
|
||||
string(REGEX REPLACE "(..)_(..)_..(..).*" "\\1/\\2/\\3" DATE "${DATE}")
|
||||
string(REGEX REPLACE "(..):(.....).*" " \\1:\\2" TIME "${TIME}")
|
||||
set(GIT_DATE_TIME "${DATE} ${TIME}")
|
||||
else()
|
||||
execute_process(COMMAND date "+%Y/%m/%d %H:%M:%S" OUTPUT_VARIABLE DATETIME)
|
||||
string(REGEX REPLACE "\n" "" DATETIME ${DATETIME})
|
||||
set(GIT_DATE_TIME "${DATETIME}")
|
||||
endif()
|
||||
|
||||
find_package(Git)
|
||||
|
||||
@@ -133,17 +91,20 @@ endif()
|
||||
|
||||
string(REGEX REPLACE "[^0-9a-f]+" "" GIT_SHA "${GIT_SHA}")
|
||||
|
||||
|
||||
# Read rocksdb version from version.h header file.
|
||||
file(READ include/rocksdb/version.h version_header_file)
|
||||
string(REGEX MATCH "#define ROCKSDB_MAJOR ([0-9]+)" _ ${version_header_file})
|
||||
set(ROCKSDB_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "#define ROCKSDB_MINOR ([0-9]+)" _ ${version_header_file})
|
||||
set(ROCKSDB_VERSION_MINOR ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "#define ROCKSDB_PATCH ([0-9]+)" _ ${version_header_file})
|
||||
set(ROCKSDB_VERSION_PATCH ${CMAKE_MATCH_1})
|
||||
set(ROCKSDB_VERSION ${ROCKSDB_VERSION_MAJOR}.${ROCKSDB_VERSION_MINOR}.${ROCKSDB_VERSION_PATCH})
|
||||
|
||||
if(NOT WIN32)
|
||||
execute_process(COMMAND
|
||||
"./build_tools/version.sh" "full"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE ROCKSDB_VERSION
|
||||
)
|
||||
string(STRIP "${ROCKSDB_VERSION}" ROCKSDB_VERSION)
|
||||
execute_process(COMMAND
|
||||
"./build_tools/version.sh" "major"
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE ROCKSDB_VERSION_MAJOR
|
||||
)
|
||||
string(STRIP "${ROCKSDB_VERSION_MAJOR}" ROCKSDB_VERSION_MAJOR)
|
||||
endif()
|
||||
|
||||
option(WITH_MD_LIBRARY "build with MD" ON)
|
||||
if(WIN32 AND MSVC)
|
||||
@@ -154,81 +115,33 @@ if(WIN32 AND MSVC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(BUILD_VERSION_CC ${CMAKE_BINARY_DIR}/build_version.cc)
|
||||
configure_file(util/build_version.cc.in ${BUILD_VERSION_CC} @ONLY)
|
||||
add_library(build_version OBJECT ${BUILD_VERSION_CC})
|
||||
target_include_directories(build_version PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util)
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W4 /wd4127 /wd4800 /wd4996 /wd4351 /wd4100 /wd4204 /wd4324")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers -Wno-strict-aliasing")
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fno-omit-frame-pointer")
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-momit-leaf-frame-pointer" HAVE_OMIT_LEAF_FRAME_POINTER)
|
||||
if(HAVE_OMIT_LEAF_FRAME_POINTER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -momit-leaf-frame-pointer")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
|
||||
CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC)
|
||||
if(HAS_ALTIVEC)
|
||||
message(STATUS " HAS_ALTIVEC yes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maltivec")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=power8")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=power8")
|
||||
endif(HAS_ALTIVEC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
|
||||
|
||||
option(PORTABLE "build a portable binary" OFF)
|
||||
option(FORCE_SSE42 "force building with SSE4.2, even when PORTABLE=ON" OFF)
|
||||
if(PORTABLE)
|
||||
# MSVC does not need a separate compiler flag to enable SSE4.2; if nmmintrin.h
|
||||
# is available, it is available by default.
|
||||
if(FORCE_SSE42 AND NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2 -mpclmul")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2")
|
||||
endif()
|
||||
else()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||
else()
|
||||
if(NOT HAVE_POWER8)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
include(CheckCXXSourceCompiles)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_REQUIRED_FLAGS "-msse4.2 -mpclmul")
|
||||
endif()
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <cstdint>
|
||||
#include <nmmintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
int main() {
|
||||
volatile uint32_t x = _mm_crc32_u32(0, 0);
|
||||
const auto a = _mm_set_epi64x(0, 0);
|
||||
const auto b = _mm_set_epi64x(0, 0);
|
||||
const auto c = _mm_clmulepi64_si128(a, b, 0x00);
|
||||
auto d = _mm_cvtsi128_si64(c);
|
||||
}
|
||||
" HAVE_SSE42)
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
if(HAVE_SSE42)
|
||||
add_definitions(-DHAVE_SSE42)
|
||||
add_definitions(-DHAVE_PCLMUL)
|
||||
elseif(FORCE_SSE42)
|
||||
message(FATAL_ERROR "FORCE_SSE42=ON but unable to compile with SSE4.2 enabled")
|
||||
endif()
|
||||
@@ -245,6 +158,32 @@ if(HAVE_THREAD_LOCAL)
|
||||
add_definitions(-DROCKSDB_SUPPORT_THREAD_LOCAL)
|
||||
endif()
|
||||
|
||||
set(BUILD_VERSION_CC ${CMAKE_BINARY_DIR}/build_version.cc)
|
||||
configure_file(util/build_version.cc.in ${BUILD_VERSION_CC} @ONLY)
|
||||
add_library(build_version OBJECT ${BUILD_VERSION_CC})
|
||||
target_include_directories(build_version PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util)
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W3 /wd4127 /wd4800 /wd4996 /wd4351")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers")
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DNDEBUG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fno-omit-frame-pointer")
|
||||
include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-momit-leaf-frame-pointer" HAVE_OMIT_LEAF_FRAME_POINTER)
|
||||
if(HAVE_OMIT_LEAF_FRAME_POINTER)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -momit-leaf-frame-pointer")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(FAIL_ON_WARNINGS "Treat compile warnings as errors" ON)
|
||||
if(FAIL_ON_WARNINGS)
|
||||
if(MSVC)
|
||||
@@ -285,28 +224,6 @@ if(WITH_UBSAN)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_NUMA "build with NUMA policy support" OFF)
|
||||
if(WITH_NUMA)
|
||||
find_package(NUMA REQUIRED)
|
||||
add_definitions(-DNUMA)
|
||||
include_directories(${NUMA_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${NUMA_LIBRARIES})
|
||||
endif()
|
||||
|
||||
option(WITH_TBB "build with Threading Building Blocks (TBB)" OFF)
|
||||
if(WITH_TBB)
|
||||
find_package(TBB REQUIRED)
|
||||
add_definitions(-DTBB)
|
||||
include_directories(${TBB_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${TBB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# Stall notifications eat some performance from inserts
|
||||
option(DISABLE_STALL_NOTIF "Build with stall notifications" OFF)
|
||||
if(DISABLE_STALL_NOTIF)
|
||||
add_definitions(-DROCKSDB_DISABLE_STALL_NOTIFICATION)
|
||||
endif()
|
||||
|
||||
# Used to run CI build and tests so we can run faster
|
||||
set(OPTIMIZE_DEBUG_DEFAULT 0) # Debug build is unoptimized by default use -DOPTDBG=1 to optimize
|
||||
|
||||
@@ -316,22 +233,6 @@ else()
|
||||
set(OPTIMIZE_DEBUG ${OPTIMIZE_DEBUG_DEFAULT})
|
||||
endif()
|
||||
|
||||
if(DEFINED USE_RTTI)
|
||||
if(USE_RTTI)
|
||||
message(STATUS "Enabling RTTI")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DROCKSDB_USE_RTTI")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DROCKSDB_USE_RTTI")
|
||||
else()
|
||||
message(STATUS "Disabling RTTI")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-rtti")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-rtti")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Enabling RTTI in Debug builds only (default)")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DROCKSDB_USE_RTTI")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-rtti")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if((${OPTIMIZE_DEBUG} EQUAL 1))
|
||||
message(STATUS "Debug optimization is enabled")
|
||||
@@ -390,8 +291,10 @@ if(NOT WIN32)
|
||||
endif()
|
||||
|
||||
option(WITH_FALLOCATE "build with fallocate" ON)
|
||||
|
||||
if(WITH_FALLOCATE)
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
include(CheckCSourceCompiles)
|
||||
CHECK_C_SOURCE_COMPILES("
|
||||
#include <fcntl.h>
|
||||
#include <linux/falloc.h>
|
||||
int main() {
|
||||
@@ -404,38 +307,12 @@ int main() {
|
||||
endif()
|
||||
endif()
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <fcntl.h>
|
||||
int main() {
|
||||
int fd = open(\"/dev/null\", 0);
|
||||
sync_file_range(fd, 0, 1024, SYNC_FILE_RANGE_WRITE);
|
||||
}
|
||||
" HAVE_SYNC_FILE_RANGE_WRITE)
|
||||
if(HAVE_SYNC_FILE_RANGE_WRITE)
|
||||
add_definitions(-DROCKSDB_RANGESYNC_PRESENT)
|
||||
endif()
|
||||
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <pthread.h>
|
||||
int main() {
|
||||
(void) PTHREAD_MUTEX_ADAPTIVE_NP;
|
||||
}
|
||||
" HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
|
||||
if(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
|
||||
add_definitions(-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX)
|
||||
endif()
|
||||
|
||||
include(CheckCXXSymbolExists)
|
||||
check_cxx_symbol_exists(malloc_usable_size malloc.h HAVE_MALLOC_USABLE_SIZE)
|
||||
include(CheckFunctionExists)
|
||||
CHECK_FUNCTION_EXISTS(malloc_usable_size HAVE_MALLOC_USABLE_SIZE)
|
||||
if(HAVE_MALLOC_USABLE_SIZE)
|
||||
add_definitions(-DROCKSDB_MALLOC_USABLE_SIZE)
|
||||
endif()
|
||||
|
||||
check_cxx_symbol_exists(sched_getcpu sched.h HAVE_SCHED_GETCPU)
|
||||
if(HAVE_SCHED_GETCPU)
|
||||
add_definitions(-DROCKSDB_SCHED_GETCPU_PRESENT)
|
||||
endif()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/third-party/gtest-1.7.0/fused-src)
|
||||
@@ -479,7 +356,6 @@ set(SOURCES
|
||||
db/flush_scheduler.cc
|
||||
db/forward_iterator.cc
|
||||
db/internal_stats.cc
|
||||
db/logs_with_prep_tracker.cc
|
||||
db/log_reader.cc
|
||||
db/log_writer.cc
|
||||
db/malloc_stats.cc
|
||||
@@ -539,7 +415,6 @@ set(SOURCES
|
||||
table/block_based_table_factory.cc
|
||||
table/block_based_table_reader.cc
|
||||
table/block_builder.cc
|
||||
table/block_fetcher.cc
|
||||
table/block_prefix_index.cc
|
||||
table/bloom_block.cc
|
||||
table/cuckoo_table_builder.cc
|
||||
@@ -594,25 +469,21 @@ set(SOURCES
|
||||
util/status_message.cc
|
||||
util/string_util.cc
|
||||
util/sync_point.cc
|
||||
util/sync_point_impl.cc
|
||||
util/testutil.cc
|
||||
util/thread_local.cc
|
||||
util/threadpool_imp.cc
|
||||
util/transaction_test_util.cc
|
||||
util/xxhash.cc
|
||||
utilities/backupable/backupable_db.cc
|
||||
utilities/blob_db/blob_compaction_filter.cc
|
||||
utilities/blob_db/blob_db.cc
|
||||
utilities/blob_db/blob_db_impl.cc
|
||||
utilities/blob_db/blob_db_options_impl.cc
|
||||
utilities/blob_db/blob_dump_tool.cc
|
||||
utilities/blob_db/blob_file.cc
|
||||
utilities/blob_db/blob_log_reader.cc
|
||||
utilities/blob_db/blob_log_writer.cc
|
||||
utilities/blob_db/blob_log_format.cc
|
||||
utilities/blob_db/ttl_extractor.cc
|
||||
utilities/cassandra/cassandra_compaction_filter.cc
|
||||
utilities/cassandra/format.cc
|
||||
utilities/cassandra/merge_operator.cc
|
||||
utilities/checkpoint/checkpoint_impl.cc
|
||||
utilities/col_buf_decoder.cc
|
||||
utilities/col_buf_encoder.cc
|
||||
@@ -629,9 +500,10 @@ set(SOURCES
|
||||
utilities/leveldb_options/leveldb_options.cc
|
||||
utilities/lua/rocks_lua_compaction_filter.cc
|
||||
utilities/memory/memory_util.cc
|
||||
utilities/merge_operators/bytesxor.cc
|
||||
utilities/merge_operators/max.cc
|
||||
utilities/merge_operators/put.cc
|
||||
utilities/merge_operators/cassandra/format.cc
|
||||
utilities/merge_operators/cassandra/merge_operator.cc
|
||||
utilities/merge_operators/string_append/stringappend.cc
|
||||
utilities/merge_operators/string_append/stringappend2.cc
|
||||
utilities/merge_operators/uint64add.cc
|
||||
@@ -647,35 +519,18 @@ set(SOURCES
|
||||
utilities/spatialdb/spatial_db.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector.cc
|
||||
utilities/transactions/optimistic_transaction_db_impl.cc
|
||||
utilities/transactions/optimistic_transaction.cc
|
||||
utilities/transactions/pessimistic_transaction.cc
|
||||
utilities/transactions/pessimistic_transaction_db.cc
|
||||
utilities/transactions/snapshot_checker.cc
|
||||
utilities/transactions/optimistic_transaction_impl.cc
|
||||
utilities/transactions/transaction_base.cc
|
||||
utilities/transactions/transaction_db_impl.cc
|
||||
utilities/transactions/transaction_db_mutex_impl.cc
|
||||
utilities/transactions/transaction_impl.cc
|
||||
utilities/transactions/transaction_lock_mgr.cc
|
||||
utilities/transactions/transaction_util.cc
|
||||
utilities/transactions/write_prepared_txn.cc
|
||||
utilities/transactions/write_prepared_txn_db.cc
|
||||
utilities/ttl/db_ttl_impl.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index_internal.cc
|
||||
$<TARGET_OBJECTS:build_version>)
|
||||
|
||||
if(HAVE_SSE42 AND NOT FORCE_SSE42)
|
||||
if(NOT MSVC)
|
||||
set_source_files_properties(
|
||||
util/crc32c.cc
|
||||
PROPERTIES COMPILE_FLAGS "-msse4.2 -mpclmul")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_POWER8)
|
||||
list(APPEND SOURCES
|
||||
util/crc32c_ppc.c
|
||||
util/crc32c_ppc_asm.S)
|
||||
endif(HAVE_POWER8)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SOURCES
|
||||
port/win/io_win.cc
|
||||
@@ -683,18 +538,8 @@ if(WIN32)
|
||||
port/win/env_default.cc
|
||||
port/win/port_win.cc
|
||||
port/win/win_logger.cc
|
||||
port/win/win_thread.cc)
|
||||
|
||||
if(WITH_XPRESS)
|
||||
list(APPEND SOURCES
|
||||
port/win/win_thread.cc
|
||||
port/win/xpress_win.cc)
|
||||
endif()
|
||||
|
||||
if(WITH_JEMALLOC)
|
||||
list(APPEND SOURCES
|
||||
port/win/win_jemalloc.cc)
|
||||
endif()
|
||||
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
port/port_posix.cc
|
||||
@@ -705,14 +550,6 @@ endif()
|
||||
set(ROCKSDB_STATIC_LIB rocksdb${ARTIFACT_SUFFIX})
|
||||
set(ROCKSDB_SHARED_LIB rocksdb-shared${ARTIFACT_SUFFIX})
|
||||
set(ROCKSDB_IMPORT_LIB ${ROCKSDB_SHARED_LIB})
|
||||
|
||||
option(WITH_LIBRADOS "Build with librados" OFF)
|
||||
if(WITH_LIBRADOS)
|
||||
list(APPEND SOURCES
|
||||
utilities/env_librados.cc)
|
||||
list(APPEND THIRDPARTY_LIBS rados)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(SYSTEM_LIBS ${SYSTEM_LIBS} Shlwapi.lib Rpcrt4.lib)
|
||||
set(LIBS ${ROCKSDB_STATIC_LIB} ${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
@@ -731,6 +568,13 @@ else()
|
||||
OUTPUT_NAME "rocksdb")
|
||||
endif()
|
||||
|
||||
option(WITH_LIBRADOS "Build with librados" OFF)
|
||||
if(WITH_LIBRADOS)
|
||||
list(APPEND SOURCES
|
||||
utilities/env_librados.cc)
|
||||
list(APPEND THIRDPARTY_LIBS rados)
|
||||
endif()
|
||||
|
||||
add_library(${ROCKSDB_STATIC_LIB} STATIC ${SOURCES})
|
||||
target_link_libraries(${ROCKSDB_STATIC_LIB}
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
@@ -757,72 +601,7 @@ else()
|
||||
message(STATUS "JNI library is disabled")
|
||||
endif()
|
||||
|
||||
# Installation and packaging
|
||||
if(WIN32)
|
||||
option(ROCKSDB_INSTALL_ON_WINDOWS "Enable install target on Windows" OFF)
|
||||
endif()
|
||||
if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
# Change default installation prefix on Linux to /usr
|
||||
set(CMAKE_INSTALL_PREFIX /usr CACHE PATH "Install path prefix, prepended onto install directories." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(package_config_destination ${CMAKE_INSTALL_LIBDIR}/cmake/rocksdb)
|
||||
|
||||
configure_package_config_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/cmake/RocksDBConfig.cmake.in RocksDBConfig.cmake
|
||||
INSTALL_DESTINATION ${package_config_destination}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
RocksDBConfigVersion.cmake
|
||||
VERSION ${ROCKSDB_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
install(DIRECTORY include/rocksdb COMPONENT devel DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
install(
|
||||
TARGETS ${ROCKSDB_STATIC_LIB}
|
||||
EXPORT RocksDBTargets
|
||||
COMPONENT devel
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${ROCKSDB_SHARED_LIB}
|
||||
EXPORT RocksDBTargets
|
||||
COMPONENT runtime
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT RocksDBTargets
|
||||
COMPONENT devel
|
||||
DESTINATION ${package_config_destination}
|
||||
NAMESPACE RocksDB::
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/RocksDBConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/RocksDBConfigVersion.cmake
|
||||
COMPONENT devel
|
||||
DESTINATION ${package_config_destination}
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_TESTS "build with tests" ON)
|
||||
if(WITH_TESTS)
|
||||
set(TESTS
|
||||
set(TESTS
|
||||
cache/cache_test.cc
|
||||
cache/lru_cache_test.cc
|
||||
db/column_family_test.cc
|
||||
@@ -835,7 +614,6 @@ if(WITH_TESTS)
|
||||
db/corruption_test.cc
|
||||
db/cuckoo_table_db_test.cc
|
||||
db/db_basic_test.cc
|
||||
db/db_blob_index_test.cc
|
||||
db/db_block_cache_test.cc
|
||||
db/db_bloom_filter_test.cc
|
||||
db/db_compaction_filter_test.cc
|
||||
@@ -845,7 +623,6 @@ if(WITH_TESTS)
|
||||
db/db_inplace_update_test.cc
|
||||
db/db_io_failure_test.cc
|
||||
db/db_iter_test.cc
|
||||
db/db_iter_stress_test.cc
|
||||
db/db_iterator_test.cc
|
||||
db/db_log_iter_test.cc
|
||||
db/db_memtable_test.cc
|
||||
@@ -864,7 +641,6 @@ if(WITH_TESTS)
|
||||
db/db_write_test.cc
|
||||
db/dbformat_test.cc
|
||||
db/deletefile_test.cc
|
||||
db/obsolete_files_test.cc
|
||||
db/external_sst_file_basic_test.cc
|
||||
db/external_sst_file_test.cc
|
||||
db/fault_injection_test.cc
|
||||
@@ -903,7 +679,6 @@ if(WITH_TESTS)
|
||||
options/options_test.cc
|
||||
table/block_based_filter_block_test.cc
|
||||
table/block_test.cc
|
||||
table/cleanable_test.cc
|
||||
table/cuckoo_table_builder_test.cc
|
||||
table/cuckoo_table_reader_test.cc
|
||||
table/full_filter_block_test.cc
|
||||
@@ -932,10 +707,6 @@ if(WITH_TESTS)
|
||||
util/thread_local_test.cc
|
||||
utilities/backupable/backupable_db_test.cc
|
||||
utilities/blob_db/blob_db_test.cc
|
||||
utilities/cassandra/cassandra_functional_test.cc
|
||||
utilities/cassandra/cassandra_format_test.cc
|
||||
utilities/cassandra/cassandra_row_merge_test.cc
|
||||
utilities/cassandra/cassandra_serialize_test.cc
|
||||
utilities/checkpoint/checkpoint_test.cc
|
||||
utilities/column_aware_encoding_test.cc
|
||||
utilities/date_tiered/date_tiered_test.cc
|
||||
@@ -944,6 +715,10 @@ if(WITH_TESTS)
|
||||
utilities/geodb/geodb_test.cc
|
||||
utilities/lua/rocks_lua_test.cc
|
||||
utilities/memory/memory_test.cc
|
||||
utilities/merge_operators/cassandra/cassandra_merge_test.cc
|
||||
utilities/merge_operators/cassandra/cassandra_format_test.cc
|
||||
utilities/merge_operators/cassandra/cassandra_row_merge_test.cc
|
||||
utilities/merge_operators/cassandra/cassandra_serialize_test.cc
|
||||
utilities/merge_operators/string_append/stringappend_test.cc
|
||||
utilities/object_registry_test.cc
|
||||
utilities/option_change_migration/option_change_migration_test.cc
|
||||
@@ -952,96 +727,98 @@ if(WITH_TESTS)
|
||||
utilities/persistent_cache/persistent_cache_test.cc
|
||||
utilities/redis/redis_lists_test.cc
|
||||
utilities/spatialdb/spatial_db_test.cc
|
||||
utilities/simulator_cache/sim_cache_test.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc
|
||||
utilities/transactions/optimistic_transaction_test.cc
|
||||
utilities/transactions/transaction_test.cc
|
||||
utilities/transactions/write_prepared_transaction_test.cc
|
||||
utilities/ttl/ttl_test.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index_test.cc
|
||||
)
|
||||
if(WITH_LIBRADOS)
|
||||
list(APPEND TESTS utilities/env_librados_test.cc)
|
||||
endif()
|
||||
)
|
||||
if(WITH_LIBRADOS)
|
||||
list(APPEND TESTS utilities/env_librados_test.cc)
|
||||
endif()
|
||||
|
||||
set(BENCHMARKS
|
||||
cache/cache_bench.cc
|
||||
memtable/memtablerep_bench.cc
|
||||
tools/db_bench.cc
|
||||
table/table_reader_bench.cc
|
||||
utilities/column_aware_encoding_exp.cc
|
||||
utilities/persistent_cache/hash_table_bench.cc)
|
||||
add_library(testharness OBJECT util/testharness.cc)
|
||||
foreach(sourcefile ${BENCHMARKS})
|
||||
set(BENCHMARKS
|
||||
cache/cache_bench.cc
|
||||
memtable/memtablerep_bench.cc
|
||||
tools/db_bench.cc
|
||||
table/table_reader_bench.cc
|
||||
utilities/column_aware_encoding_exp.cc
|
||||
utilities/persistent_cache/hash_table_bench.cc)
|
||||
add_library(testharness OBJECT util/testharness.cc)
|
||||
foreach(sourcefile ${BENCHMARKS})
|
||||
get_filename_component(exename ${sourcefile} NAME_WE)
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile}
|
||||
$<TARGET_OBJECTS:testharness>)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
endforeach(sourcefile ${BENCHMARKS})
|
||||
|
||||
# For test util library that is build only in DEBUG mode
|
||||
# and linked to tests. Add test only code that is not #ifdefed for Release here.
|
||||
set(TESTUTIL_SOURCE
|
||||
db/db_test_util.cc
|
||||
monitoring/thread_status_updater_debug.cc
|
||||
table/mock_table.cc
|
||||
util/fault_injection_test_env.cc
|
||||
utilities/merge_operators/cassandra/test_utils.cc
|
||||
)
|
||||
# test utilities are only build in debug
|
||||
enable_testing()
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
set(TESTUTILLIB testutillib${ARTIFACT_SUFFIX})
|
||||
add_library(${TESTUTILLIB} STATIC ${TESTUTIL_SOURCE})
|
||||
if(MSVC)
|
||||
set_target_properties(${TESTUTILLIB} PROPERTIES COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/testutillib${ARTIFACT_SUFFIX}.pdb")
|
||||
endif()
|
||||
set_target_properties(${TESTUTILLIB}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
|
||||
# Tests are excluded from Release builds
|
||||
set(TEST_EXES ${TESTS})
|
||||
|
||||
foreach(sourcefile ${TEST_EXES})
|
||||
get_filename_component(exename ${sourcefile} NAME_WE)
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile}
|
||||
$<TARGET_OBJECTS:testharness>)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
endforeach(sourcefile ${BENCHMARKS})
|
||||
|
||||
# For test util library that is build only in DEBUG mode
|
||||
# and linked to tests. Add test only code that is not #ifdefed for Release here.
|
||||
set(TESTUTIL_SOURCE
|
||||
db/db_test_util.cc
|
||||
monitoring/thread_status_updater_debug.cc
|
||||
table/mock_table.cc
|
||||
util/fault_injection_test_env.cc
|
||||
utilities/cassandra/test_utils.cc
|
||||
)
|
||||
# test utilities are only build in debug
|
||||
enable_testing()
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
set(TESTUTILLIB testutillib${ARTIFACT_SUFFIX})
|
||||
add_library(${TESTUTILLIB} STATIC ${TESTUTIL_SOURCE})
|
||||
if(MSVC)
|
||||
set_target_properties(${TESTUTILLIB} PROPERTIES COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/testutillib${ARTIFACT_SUFFIX}.pdb")
|
||||
endif()
|
||||
set_target_properties(${TESTUTILLIB}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
|
||||
# Tests are excluded from Release builds
|
||||
set(TEST_EXES ${TESTS})
|
||||
|
||||
foreach(sourcefile ${TEST_EXES})
|
||||
get_filename_component(exename ${sourcefile} NAME_WE)
|
||||
add_executable(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} ${sourcefile}
|
||||
$<TARGET_OBJECTS:testharness>)
|
||||
set_target_properties(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
OUTPUT_NAME ${exename}${ARTIFACT_SUFFIX}
|
||||
)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
if(NOT "${exename}" MATCHES "db_sanity_test")
|
||||
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX})
|
||||
endif()
|
||||
endforeach(sourcefile ${TEST_EXES})
|
||||
|
||||
# C executables must link to a shared object
|
||||
set(C_TESTS db/c_test.c)
|
||||
set(C_TEST_EXES ${C_TESTS})
|
||||
|
||||
foreach(sourcefile ${C_TEST_EXES})
|
||||
string(REPLACE ".c" "" exename ${sourcefile})
|
||||
string(REGEX REPLACE "^((.+)/)+" "" exename ${exename})
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile})
|
||||
set_target_properties(${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} ${ROCKSDB_IMPORT_LIB} testutillib${ARTIFACT_SUFFIX})
|
||||
set_target_properties(${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
if(NOT "${exename}" MATCHES "db_sanity_test")
|
||||
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
|
||||
endforeach(sourcefile ${C_TEST_EXES})
|
||||
endif()
|
||||
endif()
|
||||
endforeach(sourcefile ${TEST_EXES})
|
||||
|
||||
option(WITH_TOOLS "build with tools" ON)
|
||||
if(WITH_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
# C executables must link to a shared object
|
||||
set(C_TESTS db/c_test.c)
|
||||
set(C_TEST_EXES ${C_TESTS})
|
||||
|
||||
foreach(sourcefile ${C_TEST_EXES})
|
||||
string(REPLACE ".c" "" exename ${sourcefile})
|
||||
string(REGEX REPLACE "^((.+)/)+" "" exename ${exename})
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile})
|
||||
set_target_properties(${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} ${ROCKSDB_IMPORT_LIB} testutillib${ARTIFACT_SUFFIX})
|
||||
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
|
||||
endforeach(sourcefile ${C_TEST_EXES})
|
||||
add_subdirectory(tools)
|
||||
|
||||
# Installation and packaging for Linux
|
||||
if(NOT WIN32)
|
||||
install(TARGETS ${ROCKSDB_STATIC_LIB} COMPONENT devel ARCHIVE DESTINATION lib64)
|
||||
install(TARGETS ${ROCKSDB_SHARED_LIB} COMPONENT runtime DESTINATION lib64)
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/rocksdb/"
|
||||
COMPONENT devel
|
||||
DESTINATION include/rocksdb)
|
||||
set(CMAKE_INSTALL_PREFIX /usr)
|
||||
endif()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Code of Conduct
|
||||
|
||||
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
|
||||
@@ -1,8 +1,5 @@
|
||||
# Contributing to RocksDB
|
||||
|
||||
## Code of Conduct
|
||||
The code of conduct is described in [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md)
|
||||
|
||||
## Contributor License Agreement ("CLA")
|
||||
|
||||
In order to accept your pull request, we need you to submit a CLA. You
|
||||
|
||||
+4
-148
@@ -1,156 +1,12 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
### Public API Change
|
||||
* For users of `Statistics` objects created via `CreateDBStatistics()`, the format of the string returned by its `ToString()` method has changed.
|
||||
|
||||
## 5.14.0 (5/16/2018)
|
||||
### Public API Change
|
||||
* Add a BlockBasedTableOption to align uncompressed data blocks on the smaller of block size or page size boundary, to reduce flash reads by avoiding reads spanning 4K pages.
|
||||
* The background thread naming convention changed (on supporting platforms) to "rocksdb:<thread pool priority><thread number>", e.g., "rocksdb:low0".
|
||||
* Add a new ticker stat rocksdb.number.multiget.keys.found to count number of keys successfully read in MultiGet calls
|
||||
* Touch-up to write-related counters in PerfContext. New counters added: write_scheduling_flushes_compactions_time, write_thread_wait_nanos. Counters whose behavior was fixed or modified: write_memtable_time, write_pre_and_post_process_time, write_delay_time.
|
||||
* Posix Env's NewRandomRWFile() will fail if the file doesn't exist.
|
||||
* Now, `DBOptions::use_direct_io_for_flush_and_compaction` only applies to background writes, and `DBOptions::use_direct_reads` applies to both user reads and background reads. This conforms with Linux's `open(2)` manpage, which advises against simultaneously reading a file in buffered and direct modes, due to possibly undefined behavior and degraded performance.
|
||||
* Iterator::Valid() always returns false if !status().ok(). So, now when doing a Seek() followed by some Next()s, there's no need to check status() after every operation.
|
||||
* Iterator::Seek()/SeekForPrev()/SeekToFirst()/SeekToLast() always resets status().
|
||||
* Introduced `CompressionOptions::kDefaultCompressionLevel`, which is a generic way to tell RocksDB to use the compression library's default level. It is now the default value for `CompressionOptions::level`. Previously the level defaulted to -1, which gave poor compression ratios in ZSTD.
|
||||
|
||||
### New Features
|
||||
* Introduce TTL for level compaction so that all files older than ttl go through the compaction process to get rid of old data.
|
||||
* TransactionDBOptions::write_policy can be configured to enable WritePrepared 2PC transactions. Read more about them in the wiki.
|
||||
* Add DB properties "rocksdb.block-cache-capacity", "rocksdb.block-cache-usage", "rocksdb.block-cache-pinned-usage" to show block cache usage.
|
||||
* Add `Env::LowerThreadPoolCPUPriority(Priority)` method, which lowers the CPU priority of background (esp. compaction) threads to minimize interference with foreground tasks.
|
||||
* Fsync parent directory after deleting a file in delete scheduler.
|
||||
* In level-based compaction, if bottom-pri thread pool was setup via `Env::SetBackgroundThreads()`, compactions to the bottom level will be delegated to that thread pool.
|
||||
* `prefix_extractor` has been moved from ImmutableCFOptions to MutableCFOptions, meaning it can be dynamically changed without a DB restart.
|
||||
|
||||
## 5.7.2 (08/15/2017)
|
||||
### Bug Fixes
|
||||
* Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob.
|
||||
* Fix WAL corruption caused by race condition between user write thread and FlushWAL when two_write_queue is not set.
|
||||
* Fix `BackupableDBOptions::max_valid_backups_to_open` to not delete backup files when refcount cannot be accurately determined.
|
||||
* Fix memory leak when pin_l0_filter_and_index_blocks_in_cache is used with partitioned filters
|
||||
* Disable rollback of merge operands in WritePrepared transactions to work around an issue in MyRocks. It can be enabled back by setting TransactionDBOptions::rollback_merge_operands to true.
|
||||
* Fix wrong results by ReverseBytewiseComparator::FindShortSuccessor()
|
||||
|
||||
### Java API Changes
|
||||
* Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances.
|
||||
* Added SstFileManager to the Java API to allow managing SST files across DB instances.
|
||||
|
||||
## 5.13.0 (3/20/2018)
|
||||
### Public API Change
|
||||
* RocksDBOptionsParser::Parse()'s `ignore_unknown_options` argument will only be effective if the option file shows it is generated using a higher version of RocksDB than the current version.
|
||||
* Remove CompactionEventListener.
|
||||
|
||||
### New Features
|
||||
* SstFileManager now can cancel compactions if they will result in max space errors. SstFileManager users can also use SetCompactionBufferSize to specify how much space must be leftover during a compaction for auxiliary file functions such as logging and flushing.
|
||||
* Avoid unnecessarily flushing in `CompactRange()` when the range specified by the user does not overlap unflushed memtables.
|
||||
* If `ColumnFamilyOptions::max_subcompactions` is set greater than one, we now parallelize large manual level-based compactions.
|
||||
* Add "rocksdb.live-sst-files-size" DB property to return total bytes of all SST files belong to the latest LSM tree.
|
||||
* NewSstFileManager to add an argument bytes_max_delete_chunk with default 64MB. With this argument, a file larger than 64MB will be ftruncated multiple times based on this size.
|
||||
* Fix incorrect dropping of deletions issue with FIFO compaction.
|
||||
* Fix LITE build compiler error with missing abort().
|
||||
|
||||
## 5.7.1 (08/13/2017)
|
||||
### Bug Fixes
|
||||
* Fix a leak in prepared_section_completed_ where the zeroed entries would not removed from the map.
|
||||
* Fix WAL corruption caused by race condition between user write thread and backup/checkpoint thread.
|
||||
|
||||
## 5.12.0 (2/14/2018)
|
||||
### Public API Change
|
||||
* Iterator::SeekForPrev is now a pure virtual method. This is to prevent user who implement the Iterator interface fail to implement SeekForPrev by mistake.
|
||||
* Add `include_end` option to make the range end exclusive when `include_end == false` in `DeleteFilesInRange()`.
|
||||
* Add `CompactRangeOptions::allow_write_stall`, which makes `CompactRange` start working immediately, even if it causes user writes to stall. The default value is false, meaning we add delay to `CompactRange` calls until stalling can be avoided when possible. Note this delay is not present in previous RocksDB versions.
|
||||
* Creating checkpoint with empty directory now returns `Status::InvalidArgument`; previously, it returned `Status::IOError`.
|
||||
* Adds a BlockBasedTableOption to turn off index block compression.
|
||||
* Close() method now returns a status when closing a db.
|
||||
|
||||
### New Features
|
||||
* Improve the performance of iterators doing long range scans by using readahead.
|
||||
* Add new function `DeleteFilesInRanges()` to delete files in multiple ranges at once for better performance.
|
||||
* FreeBSD build support for RocksDB and RocksJava.
|
||||
* Improved performance of long range scans with readahead.
|
||||
* Updated to and now continuously tested in Visual Studio 2017.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix `DisableFileDeletions()` followed by `GetSortedWalFiles()` to not return obsolete WAL files that `PurgeObsoleteFiles()` is going to delete.
|
||||
* Fix Handle error return from WriteBuffer() during WAL file close and DB close.
|
||||
* Fix advance reservation of arena block addresses.
|
||||
* Fix handling of empty string as checkpoint directory.
|
||||
|
||||
## 5.11.0 (01/08/2018)
|
||||
### Public API Change
|
||||
* Add `autoTune` and `getBytesPerSecond()` to RocksJava RateLimiter
|
||||
|
||||
### New Features
|
||||
* Add a new histogram stat called rocksdb.db.flush.micros for memtable flush.
|
||||
* Add "--use_txn" option to use transactional API in db_stress.
|
||||
* Disable onboard cache for compaction output in Windows platform.
|
||||
* Improve the performance of iterators doing long range scans by using readahead.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a stack-use-after-scope bug in ForwardIterator.
|
||||
* Fix builds on platforms including Linux, Windows, and PowerPC.
|
||||
* Fix buffer overrun in backup engine for DBs with huge number of files.
|
||||
* Fix a mislabel bug for bottom-pri compaction threads.
|
||||
* Fix DB::Flush() keep waiting after flush finish under certain condition.
|
||||
|
||||
## 5.10.0 (12/11/2017)
|
||||
### Public API Change
|
||||
* When running `make` with environment variable `USE_SSE` set and `PORTABLE` unset, will use all machine features available locally. Previously this combination only compiled SSE-related features.
|
||||
|
||||
### New Features
|
||||
* Provide lifetime hints when writing files on Linux. This reduces hardware write-amp on storage devices supporting multiple streams.
|
||||
* Add a DB stat, `NUMBER_ITER_SKIP`, which returns how many internal keys were skipped during iterations (e.g., due to being tombstones or duplicate versions of a key).
|
||||
* Add PerfContext counters, `key_lock_wait_count` and `key_lock_wait_time`, which measure the number of times transactions wait on key locks and total amount of time waiting.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix IOError on WAL write doesn't propagate to write group follower
|
||||
* Make iterator invalid on merge error.
|
||||
* Fix performance issue in `IngestExternalFile()` affecting databases with large number of SST files.
|
||||
* Fix possible corruption to LSM structure when `DeleteFilesInRange()` deletes a subset of files spanned by a `DeleteRange()` marker.
|
||||
|
||||
## 5.9.0 (11/1/2017)
|
||||
### Public API Change
|
||||
* `BackupableDBOptions::max_valid_backups_to_open == 0` now means no backups will be opened during BackupEngine initialization. Previously this condition disabled limiting backups opened.
|
||||
* `DBOptions::preserve_deletes` is a new option that allows one to specify that DB should not drop tombstones for regular deletes if they have sequence number larger than what was set by the new API call `DB::SetPreserveDeletesSequenceNumber(SequenceNumber seqnum)`. Disabled by default.
|
||||
* API call `DB::SetPreserveDeletesSequenceNumber(SequenceNumber seqnum)` was added, users who wish to preserve deletes are expected to periodically call this function to advance the cutoff seqnum (all deletes made before this seqnum can be dropped by DB). It's user responsibility to figure out how to advance the seqnum in the way so the tombstones are kept for the desired period of time, yet are eventually processed in time and don't eat up too much space.
|
||||
* `ReadOptions::iter_start_seqnum` was added; if set to something > 0 user will see 2 changes in iterators behavior 1) only keys written with sequence larger than this parameter would be returned and 2) the `Slice` returned by iter->key() now points to the memory that keep User-oriented representation of the internal key, rather than user key. New struct `FullKey` was added to represent internal keys, along with a new helper function `ParseFullKey(const Slice& internal_key, FullKey* result);`.
|
||||
* Deprecate trash_dir param in NewSstFileManager, right now we will rename deleted files to <name>.trash instead of moving them to trash directory
|
||||
* Allow setting a custom trash/DB size ratio limit in the SstFileManager, after which files that are to be scheduled for deletion are deleted immediately, regardless of any delete ratelimit.
|
||||
* Return an error on write if write_options.sync = true and write_options.disableWAL = true to warn user of inconsistent options. Previously we will not write to WAL and not respecting the sync options in this case.
|
||||
|
||||
### New Features
|
||||
* CRC32C is now using the 3-way pipelined SSE algorithm `crc32c_3way` on supported platforms to improve performance. The system will choose to use this algorithm on supported platforms automatically whenever possible. If PCLMULQDQ is not supported it will fall back to the old Fast_CRC32 algorithm.
|
||||
* `DBOptions::writable_file_max_buffer_size` can now be changed dynamically.
|
||||
* `DBOptions::bytes_per_sync`, `DBOptions::compaction_readahead_size`, and `DBOptions::wal_bytes_per_sync` can now be changed dynamically, `DBOptions::wal_bytes_per_sync` will flush all memtables and switch to a new WAL file.
|
||||
* Support dynamic adjustment of rate limit according to demand for background I/O. It can be enabled by passing `true` to the `auto_tuned` parameter in `NewGenericRateLimiter()`. The value passed as `rate_bytes_per_sec` will still be respected as an upper-bound.
|
||||
* Support dynamically changing `ColumnFamilyOptions::compaction_options_fifo`.
|
||||
* Introduce `EventListener::OnStallConditionsChanged()` callback. Users can implement it to be notified when user writes are stalled, stopped, or resumed.
|
||||
* Add a new db property "rocksdb.estimate-oldest-key-time" to return oldest data timestamp. The property is available only for FIFO compaction with compaction_options_fifo.allow_compaction = false.
|
||||
* Upon snapshot release, recompact bottommost files containing deleted/overwritten keys that previously could not be dropped due to the snapshot. This alleviates space-amp caused by long-held snapshots.
|
||||
* Support lower bound on iterators specified via `ReadOptions::iterate_lower_bound`.
|
||||
* Support for differential snapshots (via iterator emitting the sequence of key-values representing the difference between DB state at two different sequence numbers). Supports preserving and emitting puts and regular deletes, doesn't support SingleDeletes, MergeOperator, Blobs and Range Deletes.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a potential data inconsistency issue during point-in-time recovery. `DB:Open()` will abort if column family inconsistency is found during PIT recovery.
|
||||
* Fix possible metadata corruption in databases using `DeleteRange()`.
|
||||
|
||||
## 5.8.0 (08/30/2017)
|
||||
### Public API Change
|
||||
* Users of `Statistics::getHistogramString()` will see fewer histogram buckets and different bucket endpoints.
|
||||
* `Slice::compare` and BytewiseComparator `Compare` no longer accept `Slice`s containing nullptr.
|
||||
* `Transaction::Get` and `Transaction::GetForUpdate` variants with `PinnableSlice` added.
|
||||
|
||||
### New Features
|
||||
* Add Iterator::Refresh(), which allows users to update the iterator state so that they can avoid some initialization costs of recreating iterators.
|
||||
* Replace dynamic_cast<> (except unit test) so people can choose to build with RTTI off. With make, release mode is by default built with -fno-rtti and debug mode is built without it. Users can override it by setting USE_RTTI=0 or 1.
|
||||
* Universal compactions including the bottom level can be executed in a dedicated thread pool. This alleviates head-of-line blocking in the compaction queue, which cause write stalling, particularly in multi-instance use cases. Users can enable this feature via `Env::SetBackgroundThreads(N, Env::Priority::BOTTOM)`, where `N > 0`.
|
||||
* Allow merge operator to be called even with a single merge operand during compactions, by appropriately overriding `MergeOperator::AllowSingleOperand`.
|
||||
* Add `DB::VerifyChecksum()`, which verifies the checksums in all SST files in a running DB.
|
||||
* Block-based table support for disabling checksums by setting `BlockBasedTableOptions::checksum = kNoChecksum`.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix wrong latencies in `rocksdb.db.get.micros`, `rocksdb.db.write.micros`, and `rocksdb.sst.read.micros`.
|
||||
* Fix incorrect dropping of deletions during intra-L0 compaction.
|
||||
* Fix transient reappearance of keys covered by range deletions when memtable prefix bloom filter is enabled.
|
||||
* Fix potentially wrong file smallest key when range deletions separated by snapshot are written together.
|
||||
|
||||
## 5.7.0 (07/13/2017)
|
||||
### Public API Change
|
||||
|
||||
-58
@@ -107,70 +107,12 @@ to build a portable binary, add `PORTABLE=1` before your make commands, like thi
|
||||
* run `brew tap homebrew/versions; brew install gcc48 --use-llvm` to install gcc 4.8 (or higher).
|
||||
* run `brew install rocksdb`
|
||||
|
||||
* **FreeBSD** (11.01):
|
||||
|
||||
* You can either install RocksDB from the Ports system using `cd /usr/ports/databases/rocksdb && make install`, or you can follow the details below to install dependencies and compile from source code:
|
||||
|
||||
* Install the dependencies for RocksDB:
|
||||
|
||||
export BATCH=YES
|
||||
cd /usr/ports/devel/gmake && make install
|
||||
cd /usr/ports/devel/gflags && make install
|
||||
|
||||
cd /usr/ports/archivers/snappy && make install
|
||||
cd /usr/ports/archivers/bzip2 && make install
|
||||
cd /usr/ports/archivers/liblz4 && make install
|
||||
cd /usr/ports/archivesrs/zstd && make install
|
||||
|
||||
cd /usr/ports/devel/git && make install
|
||||
|
||||
|
||||
* Install the dependencies for RocksJava (optional):
|
||||
|
||||
export BATCH=yes
|
||||
cd /usr/ports/java/openjdk7 && make install
|
||||
|
||||
* Build RocksDB from source:
|
||||
cd ~
|
||||
git clone https://github.com/facebook/rocksdb.git
|
||||
cd rocksdb
|
||||
gmake static_lib
|
||||
|
||||
* Build RocksJava from source (optional):
|
||||
cd rocksdb
|
||||
export JAVA_HOME=/usr/local/openjdk7
|
||||
gmake rocksdbjava
|
||||
|
||||
* **OpenBSD** (6.3/-current):
|
||||
|
||||
* As RocksDB is not available in the ports yet you have to build it on your own:
|
||||
|
||||
* Install the dependencies for RocksDB:
|
||||
|
||||
pkg_add gmake gflags snappy bzip2 lz4 zstd git jdk bash findutils gnuwatch
|
||||
|
||||
* Build RocksDB from source:
|
||||
|
||||
cd ~
|
||||
git clone https://github.com/facebook/rocksdb.git
|
||||
cd rocksdb
|
||||
gmake static_lib
|
||||
|
||||
* Build RocksJava from source (optional):
|
||||
|
||||
cd rocksdb
|
||||
export JAVA_HOME=/usr/local/jdk-1.8.0
|
||||
export PATH=$PATH:/usr/local/jdk-1.8.0/bin
|
||||
gmake rocksdbjava
|
||||
|
||||
* **iOS**:
|
||||
* Run: `TARGET_OS=IOS make static_lib`. When building the project which uses rocksdb iOS library, make sure to define two important pre-processing macros: `ROCKSDB_LITE` and `IOS_CROSS_COMPILE`.
|
||||
|
||||
* **Windows**:
|
||||
* For building with MS Visual Studio 13 you will need Update 4 installed.
|
||||
* Read and follow the instructions at CMakeLists.txt
|
||||
* Or install via [vcpkg](https://github.com/microsoft/vcpkg)
|
||||
* run `vcpkg install rocksdb:x64-windows`
|
||||
|
||||
* **AIX 6.1**
|
||||
* Install AIX Toolbox rpms with gcc
|
||||
|
||||
@@ -9,10 +9,5 @@ This is the list of all known third-party language bindings for RocksDB. If some
|
||||
* Haskell - https://hackage.haskell.org/package/rocksdb-haskell
|
||||
* PHP - https://github.com/Photonios/rocksdb-php
|
||||
* C# - https://github.com/warrenfalk/rocksdb-sharp
|
||||
* Rust
|
||||
* https://github.com/spacejam/rust-rocksdb
|
||||
* https://github.com/bh1xuw/rust-rocks
|
||||
* Rust - https://github.com/spacejam/rust-rocksdb
|
||||
* D programming language - https://github.com/b1naryth1ef/rocksdb
|
||||
* Erlang - https://gitlab.com/barrel-db/erlang-rocksdb
|
||||
* Elixir - https://github.com/urbint/rox
|
||||
* Nim - https://github.com/status-im/nim-rocksdb
|
||||
|
||||
@@ -76,9 +76,7 @@ ifeq ($(MAKECMDGOALS),install)
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),rocksdbjavastatic)
|
||||
ifneq ($(DEBUG_LEVEL),2)
|
||||
DEBUG_LEVEL=0
|
||||
endif
|
||||
DEBUG_LEVEL=0
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),rocksdbjavastaticrelease)
|
||||
@@ -98,34 +96,12 @@ OPT += -momit-leaf-frame-pointer
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (,$(shell $(CXX) -fsyntax-only -maltivec -xc /dev/null 2>&1))
|
||||
CXXFLAGS += -DHAS_ALTIVEC
|
||||
CFLAGS += -DHAS_ALTIVEC
|
||||
HAS_ALTIVEC=1
|
||||
endif
|
||||
|
||||
ifeq (,$(shell $(CXX) -fsyntax-only -mcpu=power8 -xc /dev/null 2>&1))
|
||||
CXXFLAGS += -DHAVE_POWER8
|
||||
CFLAGS += -DHAVE_POWER8
|
||||
HAVE_POWER8=1
|
||||
endif
|
||||
|
||||
# if we're compiling for release, compile without debug code (-DNDEBUG)
|
||||
# if we're compiling for release, compile without debug code (-DNDEBUG) and
|
||||
# don't treat warnings as errors
|
||||
ifeq ($(DEBUG_LEVEL),0)
|
||||
OPT += -DNDEBUG
|
||||
|
||||
ifneq ($(USE_RTTI), 1)
|
||||
CXXFLAGS += -fno-rtti
|
||||
DISABLE_WARNING_AS_ERROR=1
|
||||
else
|
||||
CXXFLAGS += -DROCKSDB_USE_RTTI
|
||||
endif
|
||||
else
|
||||
ifneq ($(USE_RTTI), 0)
|
||||
CXXFLAGS += -DROCKSDB_USE_RTTI
|
||||
else
|
||||
CXXFLAGS += -fno-rtti
|
||||
endif
|
||||
|
||||
$(warning Warning: Compiling in debug mode. Don't use the resulting binary in production)
|
||||
endif
|
||||
|
||||
@@ -224,9 +200,6 @@ ifdef COMPILE_WITH_TSAN
|
||||
PROFILING_FLAGS =
|
||||
# LUA is not supported under TSAN
|
||||
LUA_PATH =
|
||||
# Limit keys for crash test under TSAN to avoid error:
|
||||
# "ThreadSanitizer: DenseSlabAllocator overflow. Dying."
|
||||
CRASH_TEST_EXT_ARGS += --max_key=1000000
|
||||
endif
|
||||
|
||||
# AIX doesn't work with -pg
|
||||
@@ -237,18 +210,9 @@ endif
|
||||
# USAN doesn't work well with jemalloc. If we're compiling with USAN, we should use regular malloc.
|
||||
ifdef COMPILE_WITH_UBSAN
|
||||
DISABLE_JEMALLOC=1
|
||||
# Suppress alignment warning because murmurhash relies on casting unaligned
|
||||
# memory to integer. Fixing it may cause performance regression. 3-way crc32
|
||||
# relies on it too, although it can be rewritten to eliminate with minimal
|
||||
# performance regression.
|
||||
EXEC_LDFLAGS += -fsanitize=undefined -fno-sanitize-recover=all
|
||||
PLATFORM_CCFLAGS += -fsanitize=undefined -fno-sanitize-recover=all -DROCKSDB_UBSAN_RUN
|
||||
PLATFORM_CXXFLAGS += -fsanitize=undefined -fno-sanitize-recover=all -DROCKSDB_UBSAN_RUN
|
||||
endif
|
||||
|
||||
ifdef ROCKSDB_VALGRIND_RUN
|
||||
PLATFORM_CCFLAGS += -DROCKSDB_VALGRIND_RUN
|
||||
PLATFORM_CXXFLAGS += -DROCKSDB_VALGRIND_RUN
|
||||
EXEC_LDFLAGS += -fsanitize=undefined
|
||||
PLATFORM_CCFLAGS += -fsanitize=undefined -DROCKSDB_UBSAN_RUN
|
||||
PLATFORM_CXXFLAGS += -fsanitize=undefined -DROCKSDB_UBSAN_RUN
|
||||
endif
|
||||
|
||||
ifndef DISABLE_JEMALLOC
|
||||
@@ -256,10 +220,6 @@ ifndef DISABLE_JEMALLOC
|
||||
PLATFORM_CXXFLAGS += -DROCKSDB_JEMALLOC -DJEMALLOC_NO_DEMANGLE
|
||||
PLATFORM_CCFLAGS += -DROCKSDB_JEMALLOC -DJEMALLOC_NO_DEMANGLE
|
||||
endif
|
||||
ifdef WITH_JEMALLOC_FLAG
|
||||
PLATFORM_LDFLAGS += -ljemalloc
|
||||
JAVA_LDFLAGS += -ljemalloc
|
||||
endif
|
||||
EXEC_LDFLAGS := $(JEMALLOC_LIB) $(EXEC_LDFLAGS)
|
||||
PLATFORM_CXXFLAGS += $(JEMALLOC_INCLUDE)
|
||||
PLATFORM_CCFLAGS += $(JEMALLOC_INCLUDE)
|
||||
@@ -281,11 +241,7 @@ endif
|
||||
default: all
|
||||
|
||||
WARNING_FLAGS = -W -Wextra -Wall -Wsign-compare -Wshadow \
|
||||
-Wunused-parameter
|
||||
|
||||
ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
WARNING_FLAGS += -Wno-unused-lambda-capture
|
||||
endif
|
||||
-Wno-unused-parameter
|
||||
|
||||
ifndef DISABLE_WARNING_AS_ERROR
|
||||
WARNING_FLAGS += -Werror
|
||||
@@ -318,9 +274,6 @@ LDFLAGS += $(LUA_LIB)
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(NO_THREEWAY_CRC32C), 1)
|
||||
CXXFLAGS += -DNO_THREEWAY_CRC32C
|
||||
endif
|
||||
|
||||
CFLAGS += $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CCFLAGS) $(OPT)
|
||||
CXXFLAGS += $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers
|
||||
@@ -353,14 +306,6 @@ util/build_version.cc: FORCE
|
||||
endif
|
||||
|
||||
LIBOBJECTS = $(LIB_SOURCES:.cc=.o)
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
LIB_CC_OBJECTS = $(LIB_SOURCES:.cc=.o)
|
||||
LIBOBJECTS += $(LIB_SOURCES_C:.c=.o)
|
||||
LIBOBJECTS += $(LIB_SOURCES_ASM:.S=.o)
|
||||
else
|
||||
LIB_CC_OBJECTS = $(LIB_SOURCES:.cc=.o)
|
||||
endif
|
||||
|
||||
LIBOBJECTS += $(TOOL_LIB_SOURCES:.cc=.o)
|
||||
MOCKOBJECTS = $(MOCK_LIB_SOURCES:.cc=.o)
|
||||
|
||||
@@ -399,10 +344,8 @@ TESTS = \
|
||||
db_wal_test \
|
||||
db_block_cache_test \
|
||||
db_test \
|
||||
db_blob_index_test \
|
||||
db_bloom_filter_test \
|
||||
db_iter_test \
|
||||
db_iter_stress_test \
|
||||
db_log_iter_test \
|
||||
db_compaction_filter_test \
|
||||
db_compaction_test \
|
||||
@@ -416,6 +359,7 @@ TESTS = \
|
||||
db_range_del_test \
|
||||
db_sst_test \
|
||||
db_tailing_iter_test \
|
||||
db_universal_compaction_test \
|
||||
db_io_failure_test \
|
||||
db_properties_test \
|
||||
db_table_properties_test \
|
||||
@@ -461,7 +405,7 @@ TESTS = \
|
||||
write_buffer_manager_test \
|
||||
stringappend_test \
|
||||
cassandra_format_test \
|
||||
cassandra_functional_test \
|
||||
cassandra_merge_test \
|
||||
cassandra_row_merge_test \
|
||||
cassandra_serialize_test \
|
||||
ttl_test \
|
||||
@@ -480,7 +424,6 @@ TESTS = \
|
||||
write_batch_with_index_test \
|
||||
write_controller_test\
|
||||
deletefile_test \
|
||||
obsolete_files_test \
|
||||
table_test \
|
||||
geodb_test \
|
||||
delete_scheduler_test \
|
||||
@@ -517,14 +460,11 @@ TESTS = \
|
||||
object_registry_test \
|
||||
repair_test \
|
||||
env_timed_test \
|
||||
write_prepared_transaction_test \
|
||||
db_universal_compaction_test \
|
||||
|
||||
PARALLEL_TEST = \
|
||||
backupable_db_test \
|
||||
db_compaction_filter_test \
|
||||
db_compaction_test \
|
||||
db_merge_operator_test \
|
||||
db_sst_test \
|
||||
db_test \
|
||||
db_universal_compaction_test \
|
||||
@@ -535,13 +475,8 @@ PARALLEL_TEST = \
|
||||
manual_compaction_test \
|
||||
persistent_cache_test \
|
||||
table_test \
|
||||
transaction_test \
|
||||
write_prepared_transaction_test \
|
||||
transaction_test
|
||||
|
||||
# options_settable_test doesn't pass with UBSAN as we use hack in the test
|
||||
ifdef COMPILE_WITH_UBSAN
|
||||
TESTS := $(shell echo $(TESTS) | sed 's/\boptions_settable_test\b//g')
|
||||
endif
|
||||
SUBSET := $(TESTS)
|
||||
ifdef ROCKSDBTESTS_START
|
||||
SUBSET := $(shell echo $(SUBSET) | sed 's/^.*$(ROCKSDBTESTS_START)/$(ROCKSDBTESTS_START)/')
|
||||
@@ -620,36 +555,15 @@ $(SHARED2): $(SHARED4)
|
||||
$(SHARED3): $(SHARED4)
|
||||
ln -fs $(SHARED4) $(SHARED3)
|
||||
endif
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
SHARED_C_OBJECTS = $(LIB_SOURCES_C:.c=.o)
|
||||
SHARED_ASM_OBJECTS = $(LIB_SOURCES_ASM:.S=.o)
|
||||
SHARED_C_LIBOBJECTS = $(patsubst %.o,shared-objects/%.o,$(SHARED_C_OBJECTS))
|
||||
SHARED_ASM_LIBOBJECTS = $(patsubst %.o,shared-objects/%.o,$(SHARED_ASM_OBJECTS))
|
||||
shared_libobjects = $(patsubst %,shared-objects/%,$(LIB_CC_OBJECTS))
|
||||
else
|
||||
|
||||
shared_libobjects = $(patsubst %,shared-objects/%,$(LIBOBJECTS))
|
||||
endif
|
||||
|
||||
CLEAN_FILES += shared-objects
|
||||
shared_all_libobjects = $(shared_libobjects)
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
shared-ppc-objects = $(SHARED_C_LIBOBJECTS) $(SHARED_ASM_LIBOBJECTS)
|
||||
|
||||
shared-objects/util/crc32c_ppc.o: util/crc32c_ppc.c
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
shared-objects/util/crc32c_ppc_asm.o: util/crc32c_ppc_asm.S
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
$(shared_libobjects): shared-objects/%.o: %.cc
|
||||
$(AM_V_CC)mkdir -p $(@D) && $(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) -c $< -o $@
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
shared_all_libobjects = $(shared_libobjects) $(shared-ppc-objects)
|
||||
endif
|
||||
$(SHARED4): $(shared_all_libobjects)
|
||||
$(CXX) $(PLATFORM_SHARED_LDFLAGS)$(SHARED3) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(shared_all_libobjects) $(LDFLAGS) -o $@
|
||||
$(SHARED4): $(shared_libobjects)
|
||||
$(CXX) $(PLATFORM_SHARED_LDFLAGS)$(SHARED3) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(shared_libobjects) $(LDFLAGS) -o $@
|
||||
|
||||
endif # PLATFORM_SHARED_EXT
|
||||
|
||||
@@ -661,8 +575,6 @@ endif # PLATFORM_SHARED_EXT
|
||||
|
||||
all: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS)
|
||||
|
||||
all_but_some_tests: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(SUBSET)
|
||||
|
||||
static_lib: $(LIBRARY)
|
||||
|
||||
shared_lib: $(SHARED)
|
||||
@@ -685,7 +597,7 @@ coverage:
|
||||
COVERAGEFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS+="-lgcov" $(MAKE) J=1 all check
|
||||
cd coverage && ./coverage_test.sh
|
||||
# Delete intermediate files
|
||||
$(FIND) . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||
find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||
|
||||
ifneq (,$(filter check parallel_check,$(MAKECMDGOALS)),)
|
||||
# Use /dev/shm if it has the sticky bit set (otherwise, /tmp),
|
||||
@@ -770,7 +682,7 @@ gen_parallel_tests:
|
||||
# 107.816 PASS t/DBTest.EncodeDecompressedBlockSizeTest
|
||||
#
|
||||
slow_test_regexp = \
|
||||
^.*SnapshotConcurrentAccessTest.*$$|^t/run-table_test-HarnessTest.Randomized$$|^t/run-db_test-.*(?:FileCreationRandomFailure|EncodeDecompressedBlockSizeTest)$$|^.*RecoverFromCorruptedWALWithoutFlush$$
|
||||
^t/run-table_test-HarnessTest.Randomized$$|^t/run-db_test-.*(?:FileCreationRandomFailure|EncodeDecompressedBlockSizeTest)$$|^.*RecoverFromCorruptedWALWithoutFlush$$
|
||||
prioritize_long_running_tests = \
|
||||
perl -pe 's,($(slow_test_regexp)),100 $$1,' \
|
||||
| sort -k1,1gr \
|
||||
@@ -802,7 +714,7 @@ check_0:
|
||||
| grep -E '$(tests-regexp)' \
|
||||
| build_tools/gnu_parallel -j$(J) --plain --joblog=LOG $$eta --gnu '{} >& t/log-{/}'
|
||||
|
||||
valgrind-blacklist-regexp = InlineSkipTest.ConcurrentInsert|TransactionTest.DeadlockStress|DBCompactionTest.SuggestCompactRangeNoTwoLevel0Compactions|BackupableDBTest.RateLimiting|DBTest.CloseSpeedup|DBTest.ThreadStatusFlush|DBTest.RateLimitingTest|DBTest.EncodeDecompressedBlockSizeTest|FaultInjectionTest.UninstalledCompaction|HarnessTest.Randomized|ExternalSSTFileTest.CompactDuringAddFileRandom|ExternalSSTFileTest.IngestFileWithGlobalSeqnoRandomized|MySQLStyleTransactionTest.TransactionStressTest
|
||||
valgrind-blacklist-regexp = InlineSkipTest.ConcurrentInsert|TransactionTest.DeadlockStress|DBCompactionTest.SuggestCompactRangeNoTwoLevel0Compactions|BackupableDBTest.RateLimiting|DBTest.CloseSpeedup|DBTest.ThreadStatusFlush|DBTest.RateLimitingTest|DBTest.EncodeDecompressedBlockSizeTest|FaultInjectionTest.UninstalledCompaction|HarnessTest.Randomized|ExternalSSTFileTest.CompactDuringAddFileRandom|ExternalSSTFileTest.IngestFileWithGlobalSeqnoRandomized
|
||||
|
||||
.PHONY: valgrind_check_0
|
||||
valgrind_check_0:
|
||||
@@ -832,7 +744,7 @@ CLEAN_FILES += t LOG $(TMPD)
|
||||
# regardless of their duration. As with any use of "watch", hit ^C to
|
||||
# interrupt.
|
||||
watch-log:
|
||||
$(WATCH) --interval=0 'sort -k7,7nr -k4,4gr LOG|$(quoted_perl_command)'
|
||||
watch --interval=0 'sort -k7,7nr -k4,4gr LOG|$(quoted_perl_command)'
|
||||
|
||||
# If J != 1 and GNU parallel is installed, run the tests in parallel,
|
||||
# via the check_0 rule above. Otherwise, run them sequentially.
|
||||
@@ -866,8 +778,8 @@ ldb_tests: ldb
|
||||
crash_test: whitebox_crash_test blackbox_crash_test
|
||||
|
||||
blackbox_crash_test: db_stress
|
||||
python -u tools/db_crashtest.py --simple blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
python -u tools/db_crashtest.py blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
python -u tools/db_crashtest.py --simple blackbox
|
||||
python -u tools/db_crashtest.py blackbox
|
||||
|
||||
ifeq ($(CRASH_TEST_KILL_ODD),)
|
||||
CRASH_TEST_KILL_ODD=888887
|
||||
@@ -875,9 +787,9 @@ endif
|
||||
|
||||
whitebox_crash_test: db_stress
|
||||
python -u tools/db_crashtest.py --simple whitebox --random_kill_odd \
|
||||
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
|
||||
$(CRASH_TEST_KILL_ODD)
|
||||
python -u tools/db_crashtest.py whitebox --random_kill_odd \
|
||||
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
|
||||
$(CRASH_TEST_KILL_ODD)
|
||||
|
||||
asan_check:
|
||||
$(MAKE) clean
|
||||
@@ -900,7 +812,7 @@ ubsan_crash_test:
|
||||
$(MAKE) clean
|
||||
|
||||
valgrind_test:
|
||||
ROCKSDB_VALGRIND_RUN=1 DISABLE_JEMALLOC=1 $(MAKE) valgrind_check
|
||||
DISABLE_JEMALLOC=1 $(MAKE) valgrind_check
|
||||
|
||||
valgrind_check: $(TESTS)
|
||||
$(MAKE) DRIVER="$(VALGRIND_VER) $(VALGRIND_OPTS)" gen_parallel_tests
|
||||
@@ -997,14 +909,14 @@ rocksdb.h rocksdb.cc: build_tools/amalgamate.py Makefile $(LIB_SOURCES) unity.cc
|
||||
clean:
|
||||
rm -f $(BENCHMARKS) $(TOOLS) $(TESTS) $(LIBRARY) $(SHARED)
|
||||
rm -rf $(CLEAN_FILES) ios-x86 ios-arm scan_build_report
|
||||
$(FIND) . -name "*.[oda]" -exec rm -f {} \;
|
||||
$(FIND) . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||
find . -name "*.[oda]" -exec rm -f {} \;
|
||||
find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||
rm -rf bzip2* snappy* zlib* lz4* zstd*
|
||||
cd java; $(MAKE) clean
|
||||
|
||||
tags:
|
||||
ctags -R .
|
||||
cscope -b `$(FIND) . -name '*.cc'` `$(FIND) . -name '*.h'` `$(FIND) . -name '*.c'`
|
||||
ctags * -R
|
||||
cscope -b `find . -name '*.cc'` `find . -name '*.h'` `find . -name '*.c'`
|
||||
ctags -e -R -o etags *
|
||||
|
||||
format:
|
||||
@@ -1088,16 +1000,16 @@ option_change_migration_test: utilities/option_change_migration/option_change_mi
|
||||
stringappend_test: utilities/merge_operators/string_append/stringappend_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
cassandra_format_test: utilities/cassandra/cassandra_format_test.o utilities/cassandra/test_utils.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
cassandra_format_test: utilities/merge_operators/cassandra/cassandra_format_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
cassandra_functional_test: utilities/cassandra/cassandra_functional_test.o utilities/cassandra/test_utils.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
cassandra_merge_test: utilities/merge_operators/cassandra/cassandra_merge_test.o utilities/merge_operators/cassandra/test_utils.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
cassandra_row_merge_test: utilities/cassandra/cassandra_row_merge_test.o utilities/cassandra/test_utils.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
cassandra_row_merge_test: utilities/merge_operators/cassandra/cassandra_row_merge_test.o utilities/merge_operators/cassandra/test_utils.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
cassandra_serialize_test: utilities/cassandra/cassandra_serialize_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
cassandra_serialize_test: utilities/merge_operators/cassandra/cassandra_serialize_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
redis_test: utilities/redis/redis_lists_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
@@ -1133,9 +1045,6 @@ db_test: db/db_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
db_test2: db/db_test2.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_blob_index_test: db/db_blob_index_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_block_cache_test: db/db_block_cache_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1196,9 +1105,6 @@ db_tailing_iter_test: db/db_tailing_iter_test.o db/db_test_util.o $(LIBOBJECTS)
|
||||
db_iter_test: db/db_iter_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_iter_stress_test: db/db_iter_stress_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_universal_compaction_test: db/db_universal_compaction_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1303,7 +1209,7 @@ env_test: env/env_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
fault_injection_test: db/fault_injection_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
rate_limiter_test: util/rate_limiter_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
rate_limiter_test: util/rate_limiter_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
delete_scheduler_test: util/delete_scheduler_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
@@ -1390,9 +1296,6 @@ options_file_test: db/options_file_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
deletefile_test: db/deletefile_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
obsolete_files_test: db/obsolete_files_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
geodb_test: utilities/geodb/geodb_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1471,9 +1374,6 @@ heap_test: util/heap_test.o $(GTEST)
|
||||
transaction_test: utilities/transactions/transaction_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
write_prepared_transaction_test: utilities/transactions/write_prepared_transaction_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
sst_dump: tools/sst_dump.o $(LIBOBJECTS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1527,10 +1427,10 @@ uninstall:
|
||||
|
||||
install-headers:
|
||||
install -d $(INSTALL_PATH)/lib
|
||||
for header_dir in `$(FIND) "include/rocksdb" -type d`; do \
|
||||
for header_dir in `find "include/rocksdb" -type d`; do \
|
||||
install -d $(INSTALL_PATH)/$$header_dir; \
|
||||
done
|
||||
for header in `$(FIND) "include/rocksdb" -type f -name *.h`; do \
|
||||
for header in `find "include/rocksdb" -type f -name *.h`; do \
|
||||
install -C -m 644 $$header $(INSTALL_PATH)/$$header; \
|
||||
done
|
||||
|
||||
@@ -1557,12 +1457,6 @@ install: install-static
|
||||
JAVA_INCLUDE = -I$(JAVA_HOME)/include/ -I$(JAVA_HOME)/include/linux
|
||||
ifeq ($(PLATFORM), OS_SOLARIS)
|
||||
ARCH := $(shell isainfo -b)
|
||||
else ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
ifneq (,$(filter $(MACHINE), amd64 arm64 sparc64))
|
||||
ARCH := 64
|
||||
else
|
||||
ARCH := 32
|
||||
endif
|
||||
else
|
||||
ARCH := $(shell getconf LONG_BIT)
|
||||
endif
|
||||
@@ -1587,13 +1481,12 @@ BZIP2_DOWNLOAD_BASE ?= http://www.bzip.org
|
||||
SNAPPY_VER ?= 1.1.4
|
||||
SNAPPY_SHA256 ?= 134bfe122fd25599bb807bb8130e7ba6d9bdb851e0b16efcb83ac4f5d0b70057
|
||||
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/releases/download
|
||||
LZ4_VER ?= 1.8.0
|
||||
LZ4_SHA256 ?= 2ca482ea7a9bb103603108b5a7510b7592b90158c151ff50a28f1ca8389fccf6
|
||||
LZ4_VER ?= 1.7.5
|
||||
LZ4_SHA256 ?= 0190cacd63022ccb86f44fa5041dc6c3804407ad61550ca21c382827319e7e7e
|
||||
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
|
||||
ZSTD_VER ?= 1.3.3
|
||||
ZSTD_SHA256 ?= a77c47153ee7de02626c5b2a097005786b71688be61e9fb81806a011f90b297b
|
||||
ZSTD_VER ?= 1.2.0
|
||||
ZSTD_SHA256 ?= 4a7e4593a3638276ca7f2a09dc4f38e674d8317bbea51626393ca73fc047cbfb
|
||||
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
|
||||
CURL_SSL_OPTS ?= --tlsv1
|
||||
|
||||
ifeq ($(PLATFORM), OS_MACOSX)
|
||||
ROCKSDBJNILIB = librocksdbjni-osx.jnilib
|
||||
@@ -1606,7 +1499,7 @@ else
|
||||
endif
|
||||
endif
|
||||
ifeq ($(PLATFORM), OS_FREEBSD)
|
||||
JAVA_INCLUDE = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/freebsd
|
||||
JAVA_INCLUDE += -I$(JAVA_HOME)/include/freebsd
|
||||
ROCKSDBJNILIB = librocksdbjni-freebsd$(ARCH).so
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-freebsd$(ARCH).jar
|
||||
endif
|
||||
@@ -1622,11 +1515,6 @@ ifeq ($(PLATFORM), OS_AIX)
|
||||
EXTRACT_SOURCES = gunzip < TAR_GZ | tar xvf -
|
||||
SNAPPY_MAKE_TARGET = libsnappy.la
|
||||
endif
|
||||
ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
JAVA_INCLUDE = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/openbsd
|
||||
ROCKSDBJNILIB = librocksdbjni-openbsd$(ARCH).so
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-openbsd$(ARCH).jar
|
||||
endif
|
||||
|
||||
libz.a:
|
||||
-rm -rf zlib-$(ZLIB_VER)
|
||||
@@ -1637,7 +1525,7 @@ libz.a:
|
||||
exit 1; \
|
||||
fi
|
||||
tar xvzf zlib-$(ZLIB_VER).tar.gz
|
||||
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC ${EXTRA_CFLAGS}' LDFLAGS='${EXTRA_LDFLAGS}' ./configure --static && $(MAKE)
|
||||
cd zlib-$(ZLIB_VER) && CFLAGS='-fPIC ${EXTRA_CFLAGS}' LDFLAGS='${EXTRA_LDFLAGS}' ./configure --static && make
|
||||
cp zlib-$(ZLIB_VER)/libz.a .
|
||||
|
||||
libbz2.a:
|
||||
@@ -1649,12 +1537,12 @@ libbz2.a:
|
||||
exit 1; \
|
||||
fi
|
||||
tar xvzf bzip2-$(BZIP2_VER).tar.gz
|
||||
cd bzip2-$(BZIP2_VER) && $(MAKE) CFLAGS='-fPIC -O2 -g -D_FILE_OFFSET_BITS=64 ${EXTRA_CFLAGS}' AR='ar ${EXTRA_ARFLAGS}'
|
||||
cd bzip2-$(BZIP2_VER) && make CFLAGS='-fPIC -O2 -g -D_FILE_OFFSET_BITS=64 ${EXTRA_CFLAGS}' AR='ar ${EXTRA_ARFLAGS}'
|
||||
cp bzip2-$(BZIP2_VER)/libbz2.a .
|
||||
|
||||
libsnappy.a:
|
||||
-rm -rf snappy-$(SNAPPY_VER)
|
||||
curl -O -L ${CURL_SSL_OPTS} ${SNAPPY_DOWNLOAD_BASE}/$(SNAPPY_VER)/snappy-$(SNAPPY_VER).tar.gz
|
||||
curl -O -L ${SNAPPY_DOWNLOAD_BASE}/$(SNAPPY_VER)/snappy-$(SNAPPY_VER).tar.gz
|
||||
SNAPPY_SHA256_ACTUAL=`$(SHA256_CMD) snappy-$(SNAPPY_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(SNAPPY_SHA256)" != "$$SNAPPY_SHA256_ACTUAL" ]; then \
|
||||
echo snappy-$(SNAPPY_VER).tar.gz checksum mismatch, expected=\"$(SNAPPY_SHA256)\" actual=\"$$SNAPPY_SHA256_ACTUAL\"; \
|
||||
@@ -1662,12 +1550,12 @@ libsnappy.a:
|
||||
fi
|
||||
tar xvzf snappy-$(SNAPPY_VER).tar.gz
|
||||
cd snappy-$(SNAPPY_VER) && CFLAGS='${EXTRA_CFLAGS}' CXXFLAGS='${EXTRA_CXXFLAGS}' LDFLAGS='${EXTRA_LDFLAGS}' ./configure --with-pic --enable-static --disable-shared
|
||||
cd snappy-$(SNAPPY_VER) && $(MAKE) ${SNAPPY_MAKE_TARGET}
|
||||
cd snappy-$(SNAPPY_VER) && make ${SNAPPY_MAKE_TARGET}
|
||||
cp snappy-$(SNAPPY_VER)/.libs/libsnappy.a .
|
||||
|
||||
liblz4.a:
|
||||
-rm -rf lz4-$(LZ4_VER)
|
||||
curl -O -L ${CURL_SSL_OPTS} ${LZ4_DOWNLOAD_BASE}/v$(LZ4_VER).tar.gz
|
||||
curl -O -L ${LZ4_DOWNLOAD_BASE}/v$(LZ4_VER).tar.gz
|
||||
mv v$(LZ4_VER).tar.gz lz4-$(LZ4_VER).tar.gz
|
||||
LZ4_SHA256_ACTUAL=`$(SHA256_CMD) lz4-$(LZ4_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(LZ4_SHA256)" != "$$LZ4_SHA256_ACTUAL" ]; then \
|
||||
@@ -1675,12 +1563,12 @@ liblz4.a:
|
||||
exit 1; \
|
||||
fi
|
||||
tar xvzf lz4-$(LZ4_VER).tar.gz
|
||||
cd lz4-$(LZ4_VER)/lib && $(MAKE) CFLAGS='-fPIC -O2 ${EXTRA_CFLAGS}' all
|
||||
cd lz4-$(LZ4_VER)/lib && make CFLAGS='-fPIC -O2 ${EXTRA_CFLAGS}' all
|
||||
cp lz4-$(LZ4_VER)/lib/liblz4.a .
|
||||
|
||||
libzstd.a:
|
||||
-rm -rf zstd-$(ZSTD_VER)
|
||||
curl -O -L ${CURL_SSL_OPTS} ${ZSTD_DOWNLOAD_BASE}/v$(ZSTD_VER).tar.gz
|
||||
curl -O -L ${ZSTD_DOWNLOAD_BASE}/v$(ZSTD_VER).tar.gz
|
||||
mv v$(ZSTD_VER).tar.gz zstd-$(ZSTD_VER).tar.gz
|
||||
ZSTD_SHA256_ACTUAL=`$(SHA256_CMD) zstd-$(ZSTD_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(ZSTD_SHA256)" != "$$ZSTD_SHA256_ACTUAL" ]; then \
|
||||
@@ -1688,49 +1576,31 @@ libzstd.a:
|
||||
exit 1; \
|
||||
fi
|
||||
tar xvzf zstd-$(ZSTD_VER).tar.gz
|
||||
cd zstd-$(ZSTD_VER)/lib && DESTDIR=. PREFIX= $(MAKE) CFLAGS='-fPIC -O2 ${EXTRA_CFLAGS}' install
|
||||
cd zstd-$(ZSTD_VER)/lib && make CFLAGS='-fPIC -O2 ${EXTRA_CFLAGS}' all
|
||||
cp zstd-$(ZSTD_VER)/lib/libzstd.a .
|
||||
|
||||
# A version of each $(LIBOBJECTS) compiled with -fPIC and a fixed set of static compression libraries
|
||||
java_static_libobjects = $(patsubst %,jls/%,$(LIB_CC_OBJECTS))
|
||||
java_static_libobjects = $(patsubst %,jls/%,$(LIBOBJECTS))
|
||||
CLEAN_FILES += jls
|
||||
java_static_all_libobjects = $(java_static_libobjects)
|
||||
|
||||
ifneq ($(ROCKSDB_JAVA_NO_COMPRESSION), 1)
|
||||
JAVA_COMPRESSIONS = libz.a libbz2.a libsnappy.a liblz4.a libzstd.a
|
||||
endif
|
||||
|
||||
JAVA_STATIC_FLAGS = -DZLIB -DBZIP2 -DSNAPPY -DLZ4 -DZSTD
|
||||
JAVA_STATIC_INCLUDES = -I./zlib-$(ZLIB_VER) -I./bzip2-$(BZIP2_VER) -I./snappy-$(SNAPPY_VER) -I./lz4-$(LZ4_VER)/lib -I./zstd-$(ZSTD_VER)/lib/include
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
JAVA_STATIC_C_LIBOBJECTS = $(patsubst %.c.o,jls/%.c.o,$(LIB_SOURCES_C:.c=.o))
|
||||
JAVA_STATIC_ASM_LIBOBJECTS = $(patsubst %.S.o,jls/%.S.o,$(LIB_SOURCES_ASM:.S=.o))
|
||||
|
||||
java_static_ppc_libobjects = $(JAVA_STATIC_C_LIBOBJECTS) $(JAVA_STATIC_ASM_LIBOBJECTS)
|
||||
|
||||
jls/util/crc32c_ppc.o: util/crc32c_ppc.c
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES) -c $< -o $@
|
||||
|
||||
jls/util/crc32c_ppc_asm.o: util/crc32c_ppc_asm.S
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES) -c $< -o $@
|
||||
|
||||
java_static_all_libobjects += $(java_static_ppc_libobjects)
|
||||
endif
|
||||
JAVA_STATIC_INCLUDES = -I./zlib-$(ZLIB_VER) -I./bzip2-$(BZIP2_VER) -I./snappy-$(SNAPPY_VER) -I./lz4-$(LZ4_VER)/lib -I./zstd-$(ZSTD_VER)/lib
|
||||
|
||||
$(java_static_libobjects): jls/%.o: %.cc $(JAVA_COMPRESSIONS)
|
||||
$(AM_V_CC)mkdir -p $(@D) && $(CXX) $(CXXFLAGS) $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES) -fPIC -c $< -o $@ $(COVERAGEFLAGS)
|
||||
|
||||
rocksdbjavastatic: $(java_static_all_libobjects)
|
||||
rocksdbjavastatic: $(java_static_libobjects)
|
||||
cd java;$(MAKE) javalib;
|
||||
rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC \
|
||||
-o ./java/target/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) \
|
||||
$(java_static_all_libobjects) $(COVERAGEFLAGS) \
|
||||
$(java_static_libobjects) $(COVERAGEFLAGS) \
|
||||
$(JAVA_COMPRESSIONS) $(JAVA_STATIC_LDFLAGS)
|
||||
cd java/target;if [ "$(DEBUG_LEVEL)" == "0" ]; then \
|
||||
strip $(STRIPFLAGS) $(ROCKSDBJNILIB); \
|
||||
fi
|
||||
cd java/target;strip $(STRIPFLAGS) $(ROCKSDBJNILIB)
|
||||
cd java;jar -cf target/$(ROCKSDB_JAR) HISTORY*.md
|
||||
cd java/target;jar -uf $(ROCKSDB_JAR) $(ROCKSDBJNILIB)
|
||||
cd java/target/classes;jar -uf ../$(ROCKSDB_JAR) org/rocksdb/*.class org/rocksdb/util/*.class
|
||||
@@ -1758,14 +1628,6 @@ rocksdbjavastaticreleasedocker: rocksdbjavastatic
|
||||
cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib
|
||||
cd java/target/classes;jar -uf ../$(ROCKSDB_JAR_ALL) org/rocksdb/*.class org/rocksdb/util/*.class
|
||||
|
||||
rocksdbjavastaticdockerppc64le:
|
||||
mkdir -p java/target
|
||||
DOCKER_LINUX_PPC64LE_CONTAINER=`docker ps -aqf name=rocksdb_linux_ppc64le-be`; \
|
||||
if [ -z "$$DOCKER_LINUX_PPC64LE_CONTAINER" ]; then \
|
||||
docker container create --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host --name rocksdb_linux_ppc64le-be evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh; \
|
||||
fi
|
||||
docker start -a rocksdb_linux_ppc64le-be
|
||||
|
||||
rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral
|
||||
|
||||
rocksdbjavastaticpublishdocker: rocksdbjavastaticreleasedocker rocksdbjavastaticpublishcentral
|
||||
@@ -1780,36 +1642,13 @@ rocksdbjavastaticpublishcentral:
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar
|
||||
|
||||
# A version of each $(LIBOBJECTS) compiled with -fPIC
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
JAVA_CC_OBJECTS = $(SHARED_CC_OBJECTS)
|
||||
JAVA_C_OBJECTS = $(SHARED_C_OBJECTS)
|
||||
JAVA_ASM_OBJECTS = $(SHARED_ASM_OBJECTS)
|
||||
|
||||
JAVA_C_LIBOBJECTS = $(patsubst %.c.o,jl/%.c.o,$(JAVA_C_OBJECTS))
|
||||
JAVA_ASM_LIBOBJECTS = $(patsubst %.S.o,jl/%.S.o,$(JAVA_ASM_OBJECTS))
|
||||
endif
|
||||
|
||||
java_libobjects = $(patsubst %,jl/%,$(LIB_CC_OBJECTS))
|
||||
java_libobjects = $(patsubst %,jl/%,$(LIBOBJECTS))
|
||||
CLEAN_FILES += jl
|
||||
java_all_libobjects = $(java_libobjects)
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
java_ppc_libobjects = $(JAVA_C_LIBOBJECTS) $(JAVA_ASM_LIBOBJECTS)
|
||||
|
||||
jl/crc32c_ppc.o: util/crc32c_ppc.c
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
jl/crc32c_ppc_asm.o: util/crc32c_ppc_asm.S
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
java_all_libobjects += $(java_ppc_libobjects)
|
||||
endif
|
||||
|
||||
$(java_libobjects): jl/%.o: %.cc
|
||||
$(AM_V_CC)mkdir -p $(@D) && $(CXX) $(CXXFLAGS) -fPIC -c $< -o $@ $(COVERAGEFLAGS)
|
||||
|
||||
|
||||
|
||||
rocksdbjava: $(java_all_libobjects)
|
||||
rocksdbjava: $(java_libobjects)
|
||||
$(AM_V_GEN)cd java;$(MAKE) javalib;
|
||||
$(AM_V_at)rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(AM_V_at)$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/target/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(java_libobjects) $(JAVA_LDFLAGS) $(COVERAGEFLAGS)
|
||||
@@ -1864,54 +1703,30 @@ IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBu
|
||||
lipo ios-x86/$@ ios-arm/$@ -create -output $@
|
||||
|
||||
else
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
util/crc32c_ppc.o: util/crc32c_ppc.c
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
util/crc32c_ppc_asm.o: util/crc32c_ppc_asm.S
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
.cc.o:
|
||||
$(AM_V_CC)$(CXX) $(CXXFLAGS) -c $< -o $@ $(COVERAGEFLAGS)
|
||||
|
||||
.c.o:
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Source files dependencies detection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
all_sources = $(LIB_SOURCES) $(MAIN_SOURCES) $(MOCK_LIB_SOURCES) $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(TEST_LIB_SOURCES) $(EXP_LIB_SOURCES)
|
||||
DEPFILES = $(all_sources:.cc=.cc.d)
|
||||
DEPFILES = $(all_sources:.cc=.d)
|
||||
|
||||
# Add proper dependency support so changing a .h file forces a .cc file to
|
||||
# rebuild.
|
||||
|
||||
# The .d file indicates .cc file's dependencies on .h files. We generate such
|
||||
# dependency by g++'s -MM option, whose output is a make dependency rule.
|
||||
%.cc.d: %.cc
|
||||
$(DEPFILES): %.d: %.cc
|
||||
@$(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) \
|
||||
-MM -MT'$@' -MT'$(<:.cc=.o)' "$<" -o '$@'
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
DEPFILES_C = $(LIB_SOURCES_C:.c=.c.d)
|
||||
DEPFILES_ASM = $(LIB_SOURCES_ASM:.S=.S.d)
|
||||
|
||||
%.c.d: %.c
|
||||
@$(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) \
|
||||
-MM -MT'$@' -MT'$(<:.c=.o)' "$<" -o '$@'
|
||||
|
||||
%.S.d: %.S
|
||||
@$(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) \
|
||||
-MM -MT'$@' -MT'$(<:.S=.o)' "$<" -o '$@'
|
||||
|
||||
$(DEPFILES_C): %.c.d
|
||||
|
||||
$(DEPFILES_ASM): %.S.d
|
||||
depend: $(DEPFILES) $(DEPFILES_C) $(DEPFILES_ASM)
|
||||
else
|
||||
depend: $(DEPFILES)
|
||||
endif
|
||||
|
||||
# if the make goal is either "clean" or "format", we shouldn't
|
||||
# try to import the *.d files.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
## RocksDB: A Persistent Key-Value Store for Flash and RAM Storage
|
||||
|
||||
[](https://travis-ci.org/facebook/rocksdb)
|
||||
[](https://ci.appveyor.com/project/Facebook/rocksdb/branch/master)
|
||||
[](http://140.211.168.68:8080/job/Rocksdb)
|
||||
[](https://travis-ci.org/facebook/rocksdb)
|
||||
[](https://ci.appveyor.com/project/Facebook/rocksdb/branch/master)
|
||||
|
||||
|
||||
RocksDB is developed and maintained by Facebook Database Engineering Team.
|
||||
@@ -26,7 +25,3 @@ rely on the details of any other header files in this package. Those
|
||||
internal APIs may be changed without warning.
|
||||
|
||||
Design discussions are conducted in https://www.facebook.com/groups/rocksdb.dev/
|
||||
|
||||
## License
|
||||
|
||||
RocksDB is dual-licensed under both the GPLv2 (found in the COPYING file in the root directory) and Apache 2.0 License (found in the LICENSE.Apache file in the root directory). You may select, at your option, one of the above-listed licenses.
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ RocksDBLite is a project focused on mobile use cases, which don't need a lot of
|
||||
Some examples of the features disabled by ROCKSDB_LITE:
|
||||
* compiled-in support for LDB tool
|
||||
* No backupable DB
|
||||
* No support for replication (which we provide in form of TransactionalIterator)
|
||||
* No support for replication (which we provide in form of TrasactionalIterator)
|
||||
* No advanced monitoring tools
|
||||
* No special-purpose memtables that are highly optimized for specific use cases
|
||||
* No Transactions
|
||||
|
||||
@@ -5,14 +5,12 @@ At Facebook, we use RocksDB as storage engines in multiple data management servi
|
||||
|
||||
1. MyRocks -- https://github.com/MySQLOnRocksDB/mysql-5.6
|
||||
2. MongoRocks -- https://github.com/mongodb-partners/mongo-rocks
|
||||
3. ZippyDB -- Facebook's distributed key-value store with Paxos-style replication, built on top of RocksDB.[1] https://www.youtube.com/watch?v=DfiN7pG0D0khtt
|
||||
4. Laser -- Laser is a high query throughput, low (millisecond) latency, key-value storage service built on top of RocksDB.[1]
|
||||
3. ZippyDB -- Facebook's distributed key-value store with Paxos-style replication, built on top of RocksDB.[*] https://www.youtube.com/watch?v=DfiN7pG0D0khtt
|
||||
4. Laser -- Laser is a high query throughput, low (millisecond) latency, key-value storage service built on top of RocksDB.[*]
|
||||
4. Dragon -- a distributed graph query engine. https://code.facebook.com/posts/1737605303120405/dragon-a-distributed-graph-query-engine/
|
||||
5. Stylus -- a low-level stream processing framework writtenin C++.[1]
|
||||
6. LogDevice -- a distributed data store for logs [2]
|
||||
5. Stylus -- a low-level stream processing framework writtenin C++.[*]
|
||||
|
||||
[1] https://research.facebook.com/publications/realtime-data-processing-at-facebook/
|
||||
[2] https://code.facebook.com/posts/357056558062811/logdevice-a-distributed-data-store-for-logs/
|
||||
[*] https://research.facebook.com/publications/realtime-data-processing-at-facebook/
|
||||
|
||||
## LinkedIn
|
||||
Two different use cases at Linkedin are using RocksDB as a storage engine:
|
||||
@@ -82,9 +80,3 @@ quasardb uses a heavily tuned RocksDB as its persistence layer.
|
||||
|
||||
## 360 Pika
|
||||
[360](http://www.360.cn/) [Pika](https://github.com/Qihoo360/pika) is a nosql compatible with redis. With the huge amount of data stored, redis may suffer for a capacity bottleneck, and pika was born for solving it. It has widely been widely used in many company
|
||||
|
||||
## LzLabs
|
||||
LzLabs is using RocksDB as a storage engine in their multi-database distributed framework to store application configuration and user data.
|
||||
|
||||
## ProfaneDB
|
||||
[ProfaneDB](https://profanedb.gitlab.io/) is a database for Protocol Buffers, and uses RocksDB for storage. It is accessible via gRPC, and the schema is defined using directly `.proto` files.
|
||||
|
||||
Vendored
-5
@@ -14,11 +14,6 @@ Vagrant.configure("2") do |config|
|
||||
box.vm.box = "chef/centos-6.5"
|
||||
end
|
||||
|
||||
config.vm.define "centos7" do |box|
|
||||
box.vm.box = "centos/7"
|
||||
box.vm.provision "shell", path: "build_tools/setup_centos7.sh"
|
||||
end
|
||||
|
||||
config.vm.define "FreeBSD10" do |box|
|
||||
box.vm.guest = :freebsd
|
||||
box.vm.box = "robin/freebsd-10"
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2017
|
||||
image: Visual Studio 2015
|
||||
before_build:
|
||||
- md %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cmake -G "Visual Studio 15 Win64" -DOPTDBG=1 -DWITH_XPRESS=1 -DPORTABLE=1 ..
|
||||
- cmake -G "Visual Studio 14 2015 Win64" -DOPTDBG=1 -DXPRESS=1 ..
|
||||
- cd ..
|
||||
build:
|
||||
project: build\rocksdb.sln
|
||||
parallel: true
|
||||
verbosity: normal
|
||||
verbosity: minimal
|
||||
test:
|
||||
test_script:
|
||||
- ps: build_tools\run_ci_db_test.ps1 -SuiteRun db_basic_test,db_test2,db_test,env_basic_test,env_test -Concurrency 8
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
phutil_register_library('arcanist_util', __FILE__);
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is automatically generated. Use 'arc liberate' to rebuild it.
|
||||
* @generated
|
||||
* @phutil-library-version 2
|
||||
*/
|
||||
|
||||
if (class_exists('ArcanistWorkflow')) {
|
||||
phutil_register_library_map(array(
|
||||
'__library_version__' => 2,
|
||||
'class' =>
|
||||
array(
|
||||
'ArcanistCpplintLinter' => 'cpp_linter/ArcanistCpplintLinter.php',
|
||||
'BaseDirectoryScopedFormatLinter' => 'cpp_linter/BaseDirectoryScopedFormatLinter.php',
|
||||
'FacebookArcanistConfiguration' => 'config/FacebookArcanistConfiguration.php',
|
||||
'FacebookFbcodeLintEngine' => 'lint_engine/FacebookFbcodeLintEngine.php',
|
||||
'FacebookFbcodeUnitTestEngine' => 'unit_engine/FacebookFbcodeUnitTestEngine.php',
|
||||
'FacebookHowtoevenLintEngine' => 'lint_engine/FacebookHowtoevenLintEngine.php',
|
||||
'FacebookHowtoevenLinter' => 'cpp_linter/FacebookHowtoevenLinter.php',
|
||||
'FbcodeClangFormatLinter' => 'cpp_linter/FbcodeClangFormatLinter.php',
|
||||
'FbcodeCppLinter' => 'cpp_linter/FbcodeCppLinter.php',
|
||||
),
|
||||
'function' =>
|
||||
array(
|
||||
),
|
||||
'xmap' =>
|
||||
array(
|
||||
'ArcanistCpplintLinter' => 'ArcanistLinter',
|
||||
'BaseDirectoryScopedFormatLinter' => 'ArcanistLinter',
|
||||
'FacebookArcanistConfiguration' => 'ArcanistConfiguration',
|
||||
'FacebookFbcodeLintEngine' => 'ArcanistLintEngine',
|
||||
'FacebookFbcodeUnitTestEngine' => 'ArcanistBaseUnitTestEngine',
|
||||
'FacebookHowtoevenLintEngine' => 'ArcanistLintEngine',
|
||||
'FacebookHowtoevenLinter' => 'ArcanistLinter',
|
||||
'FbcodeClangFormatLinter' => 'BaseDirectoryScopedFormatLinter',
|
||||
'FbcodeCppLinter' => 'ArcanistLinter',
|
||||
),
|
||||
));
|
||||
} else {
|
||||
phutil_register_library_map(array(
|
||||
'__library_version__' => 2,
|
||||
'class' =>
|
||||
array(
|
||||
'ArcanistCpplintLinter' => 'cpp_linter/ArcanistCpplintLinter.php',
|
||||
'BaseDirectoryScopedFormatLinter' => 'cpp_linter/BaseDirectoryScopedFormatLinter.php',
|
||||
'FacebookArcanistConfiguration' => 'config/FacebookOldArcanistConfiguration.php',
|
||||
'FacebookFbcodeLintEngine' => 'lint_engine/FacebookFbcodeLintEngine.php',
|
||||
'FacebookFbcodeUnitTestEngine' => 'unit_engine/FacebookOldFbcodeUnitTestEngine.php',
|
||||
'FacebookHowtoevenLintEngine' => 'lint_engine/FacebookHowtoevenLintEngine.php',
|
||||
'FacebookHowtoevenLinter' => 'cpp_linter/FacebookHowtoevenLinter.php',
|
||||
'FbcodeClangFormatLinter' => 'cpp_linter/FbcodeClangFormatLinter.php',
|
||||
'FbcodeCppLinter' => 'cpp_linter/FbcodeCppLinter.php',
|
||||
),
|
||||
'function' =>
|
||||
array(
|
||||
),
|
||||
'xmap' =>
|
||||
array(
|
||||
'ArcanistCpplintLinter' => 'ArcanistLinter',
|
||||
'BaseDirectoryScopedFormatLinter' => 'ArcanistLinter',
|
||||
'FacebookArcanistConfiguration' => 'ArcanistConfiguration',
|
||||
'FacebookFbcodeLintEngine' => 'ArcanistLintEngine',
|
||||
'FacebookFbcodeUnitTestEngine' => 'ArcanistBaseUnitTestEngine',
|
||||
'FacebookHowtoevenLintEngine' => 'ArcanistLintEngine',
|
||||
'FacebookHowtoevenLinter' => 'ArcanistLinter',
|
||||
'FbcodeClangFormatLinter' => 'BaseDirectoryScopedFormatLinter',
|
||||
'FbcodeCppLinter' => 'ArcanistLinter',
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
require('RocksDBCommonHelper.php');
|
||||
|
||||
define("DIFF_COMMAND", "diff");
|
||||
|
||||
class FacebookArcanistConfiguration extends ArcanistConfiguration {
|
||||
public function getCustomArgumentsForCommand($command) {
|
||||
if ($command == "land") {
|
||||
return array(
|
||||
'async' => array('help' => 'Just to make tools happy'));
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
public function didRunWorkflow($command,
|
||||
ArcanistWorkflow $workflow,
|
||||
$error_code) {
|
||||
// Default options don't terminate on failure, but that's what we want. In
|
||||
// the current case we use assertions intentionally as "terminate on failure
|
||||
// invariants".
|
||||
assert_options(ASSERT_BAIL, true);
|
||||
|
||||
assert($workflow);
|
||||
assert(strlen($command) > 0);
|
||||
|
||||
if ($command == DIFF_COMMAND && !$workflow->isRawDiffSource()) {
|
||||
$diffID = $workflow->getDiffId();
|
||||
|
||||
// When submitting a diff this code path gets executed multiple times in
|
||||
// a row. We only care about the case when ID for the diff is provided
|
||||
// because that's what we need to apply the diff and trigger the tests.
|
||||
if (strlen($diffID) > 0) {
|
||||
assert(is_numeric($diffID));
|
||||
startTestsInSandcastle(true /* $applyDiff */, $workflow, $diffID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
require('RocksDBCommonHelper.php');
|
||||
|
||||
define("DIFF_COMMAND", "diff");
|
||||
|
||||
class FacebookArcanistConfiguration extends ArcanistConfiguration {
|
||||
public function getCustomArgumentsForCommand($command) {
|
||||
if ($command == "land") {
|
||||
return array(
|
||||
'async' => array('help' => 'Just to make tools happy'));
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
public function didRunWorkflow($command,
|
||||
ArcanistBaseWorkflow $workflow,
|
||||
$error_code) {
|
||||
// Default options don't terminate on failure, but that's what we want. In
|
||||
// the current case we use assertions intentionally as "terminate on failure
|
||||
// invariants".
|
||||
assert_options(ASSERT_BAIL, true);
|
||||
|
||||
assert($workflow);
|
||||
assert(strlen($command) > 0);
|
||||
|
||||
if ($command == DIFF_COMMAND && !$workflow->isRawDiffSource()) {
|
||||
$diffID = $workflow->getDiffId();
|
||||
|
||||
// When submitting a diff this code path gets executed multiple times in
|
||||
// a row. We only care about the case when ID for the diff is provided
|
||||
// because that's what we need to apply the diff and trigger the tests.
|
||||
if (strlen($diffID) > 0) {
|
||||
assert(is_numeric($diffID));
|
||||
startTestsInSandcastle(true /* $applyDiff */, $workflow, $diffID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
-45
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
// Name of the environment variables which need to be set by the entity which
|
||||
// triggers continuous runs so that code at the end of the file gets executed
|
||||
@@ -21,17 +21,11 @@ function postURL($diffID, $url) {
|
||||
assert(is_numeric($diffID));
|
||||
assert(strlen($url) > 0);
|
||||
|
||||
$cmd_args = array(
|
||||
'diff_id' => (int)$diffID,
|
||||
'name' => sprintf(
|
||||
'click here for sandcastle tests for D%d',
|
||||
(int)$diffID
|
||||
),
|
||||
'link' => $url
|
||||
);
|
||||
$cmd = 'echo ' . escapeshellarg(json_encode($cmd_args))
|
||||
. ' | arc call-conduit differential.updateunitresults';
|
||||
|
||||
$cmd = 'echo \'{"diff_id": ' . $diffID . ', '
|
||||
. '"name":"click here for sandcastle tests for D' . $diffID . '", '
|
||||
. '"link":"' . $url . '"}\' | '
|
||||
. 'arc call-conduit '
|
||||
. 'differential.updateunitresults';
|
||||
shell_exec($cmd);
|
||||
}
|
||||
|
||||
@@ -41,15 +35,11 @@ function buildUpdateTestStatusCmd($diffID, $test, $status) {
|
||||
assert(strlen($test) > 0);
|
||||
assert(strlen($status) > 0);
|
||||
|
||||
$cmd_args = array(
|
||||
'diff_id' => (int)$diffID,
|
||||
'name' => $test,
|
||||
'result' => $status
|
||||
);
|
||||
|
||||
$cmd = 'echo ' . escapeshellarg(json_encode($cmd_args))
|
||||
. ' | arc call-conduit differential.updateunitresults';
|
||||
|
||||
$cmd = 'echo \'{"diff_id": ' . $diffID . ', '
|
||||
. '"name":"' . $test . '", '
|
||||
. '"result":"' . $status . '"}\' | '
|
||||
. 'arc call-conduit '
|
||||
. 'differential.updateunitresults';
|
||||
return $cmd;
|
||||
}
|
||||
|
||||
@@ -78,7 +68,7 @@ function getSteps($applyDiff, $diffID, $username, $test) {
|
||||
// and authenticate using that in Sandcastle.
|
||||
$setup = array(
|
||||
"name" => "Setup arcrc",
|
||||
"shell" => "echo " . escapeshellarg($arcrc_content) . " | base64 --decode"
|
||||
"shell" => "echo " . $arcrc_content . " | base64 --decode"
|
||||
. " | gzip -d > ~/.arcrc",
|
||||
"user" => "root"
|
||||
);
|
||||
@@ -104,17 +94,7 @@ function getSteps($applyDiff, $diffID, $username, $test) {
|
||||
"user" => "root"
|
||||
);
|
||||
|
||||
// This fixes "FATAL: ThreadSanitizer can not mmap the shadow memory"
|
||||
// Source:
|
||||
// https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual#FAQ
|
||||
$fix_kernel_issue = array(
|
||||
"name" => "Fix kernel issue with tsan",
|
||||
"shell" => "echo 2 >/proc/sys/kernel/randomize_va_space",
|
||||
"user" => "root"
|
||||
);
|
||||
|
||||
$steps[] = $fix_git_ignore;
|
||||
$steps[] = $fix_kernel_issue;
|
||||
|
||||
// This will be the command used to execute particular type of tests.
|
||||
$cmd = "";
|
||||
@@ -124,7 +104,7 @@ function getSteps($applyDiff, $diffID, $username, $test) {
|
||||
$patch = array(
|
||||
"name" => "Patch " . $diffID,
|
||||
"shell" => "arc --arcrc-file ~/.arcrc "
|
||||
. "patch --nocommit --diff " . escapeshellarg($diffID),
|
||||
. "patch --nocommit --diff " . $diffID,
|
||||
"user" => "root"
|
||||
);
|
||||
|
||||
@@ -135,8 +115,8 @@ function getSteps($applyDiff, $diffID, $username, $test) {
|
||||
}
|
||||
|
||||
// Run the actual command.
|
||||
$cmd = $cmd . "J=$(nproc) ./build_tools/precommit_checker.py " .
|
||||
escapeshellarg($test) . "; exit_code=$?; ";
|
||||
$cmd = $cmd . "J=$(nproc) ./build_tools/precommit_checker.py " . $test
|
||||
. "; exit_code=$?; ";
|
||||
|
||||
if ($applyDiff) {
|
||||
$cmd = $cmd . "([[ \$exit_code -eq 0 ]] &&"
|
||||
@@ -169,7 +149,7 @@ function getSteps($applyDiff, $diffID, $username, $test) {
|
||||
"name" => "Run " . $test,
|
||||
"shell" => $cmd,
|
||||
"user" => "root",
|
||||
"parser" => "python build_tools/error_filter.py " . escapeshellarg($test),
|
||||
"parser" => "python build_tools/error_filter.py " . $test,
|
||||
);
|
||||
|
||||
$steps[] = $run_test;
|
||||
@@ -217,7 +197,7 @@ function getSandcastleConfig() {
|
||||
if (file_exists(PRIMARY_TOKEN_FILE)) {
|
||||
$cmd = 'cat ' . PRIMARY_TOKEN_FILE;
|
||||
} else {
|
||||
$cmd = 'cat ' . escapeshellarg($cwd_token_file);
|
||||
$cmd = 'cat ' . $cwd_token_file;
|
||||
}
|
||||
|
||||
assert(strlen($cmd) > 0);
|
||||
@@ -261,7 +241,7 @@ function getSandcastleConfig() {
|
||||
// List of tests we want to run in Sandcastle.
|
||||
$tests = array("unit", "unit_non_shm", "unit_481", "clang_unit", "tsan",
|
||||
"asan", "lite_test", "valgrind", "release", "release_481",
|
||||
"clang_release", "clang_analyze", "code_cov",
|
||||
"clang_release", "punit", "clang_analyze", "code_cov",
|
||||
"java_build", "no_compression", "unity", "ubsan");
|
||||
|
||||
$send_email_template = array(
|
||||
@@ -341,11 +321,9 @@ function getSandcastleConfig() {
|
||||
$app = $sandcastle_config[0];
|
||||
$token = $sandcastle_config[1];
|
||||
|
||||
$cmd = 'curl -s -k '
|
||||
. ' -F app=' . escapeshellarg($app)
|
||||
. ' -F token=' . escapeshellarg($token)
|
||||
. ' -F job=' . escapeshellarg(json_encode($job))
|
||||
.' ' . escapeshellarg($url);
|
||||
$cmd = 'curl -s -k -F app=' . $app . ' '
|
||||
. '-F token=' . $token . ' -F job=\'' . json_encode($job)
|
||||
.'\' "' . $url . '"';
|
||||
|
||||
$output = shell_exec($cmd);
|
||||
assert(strlen($output) > 0);
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Uses google's cpplint.py to check code. RocksDB team forked this file from
|
||||
* phabricator's /src/lint/linter/ArcanistCpplintLinter.php, and customized it
|
||||
* for its own use.
|
||||
*
|
||||
* You can get it here:
|
||||
* http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
|
||||
* @group linter
|
||||
*/
|
||||
final class ArcanistCpplintLinter extends ArcanistLinter {
|
||||
|
||||
public function willLintPaths(array $paths) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function getLinterName() {
|
||||
return 'cpplint.py';
|
||||
}
|
||||
|
||||
public function getLintPath() {
|
||||
$bin = 'cpplint.py';
|
||||
// Search under current dir
|
||||
list($err) = exec_manual('which %s/%s', $this->linterDir(), $bin);
|
||||
if (!$err) {
|
||||
return $this->linterDir().'/'.$bin;
|
||||
}
|
||||
|
||||
// Look for globally installed cpplint.py
|
||||
list($err) = exec_manual('which %s', $bin);
|
||||
if ($err) {
|
||||
throw new ArcanistUsageException(
|
||||
"cpplint.py does not appear to be installed on this system. Install ".
|
||||
"it (e.g., with 'wget \"http://google-styleguide.googlecode.com/".
|
||||
"svn/trunk/cpplint/cpplint.py\"') ".
|
||||
"in your .arcconfig to point to the directory where it resides. ".
|
||||
"Also don't forget to chmod a+x cpplint.py!");
|
||||
}
|
||||
|
||||
return $bin;
|
||||
}
|
||||
|
||||
public function lintPath($path) {
|
||||
$bin = $this->getLintPath();
|
||||
$path = $this->rocksdbDir().'/'.$path;
|
||||
|
||||
$f = new ExecFuture("%C $path", $bin);
|
||||
|
||||
list($err, $stdout, $stderr) = $f->resolve();
|
||||
|
||||
if ($err === 2) {
|
||||
throw new Exception("cpplint failed to run correctly:\n".$stderr);
|
||||
}
|
||||
|
||||
$lines = explode("\n", $stderr);
|
||||
$messages = array();
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
$matches = null;
|
||||
$regex = '/^[^:]+:(\d+):\s*(.*)\s*\[(.*)\] \[(\d+)\]$/';
|
||||
if (!preg_match($regex, $line, $matches)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($matches as $key => $match) {
|
||||
$matches[$key] = trim($match);
|
||||
}
|
||||
$message = new ArcanistLintMessage();
|
||||
$message->setPath($path);
|
||||
$message->setLine($matches[1]);
|
||||
$message->setCode($matches[3]);
|
||||
$message->setName($matches[3]);
|
||||
$message->setDescription($matches[2]);
|
||||
$message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
|
||||
$this->addLintMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
// The path of this linter
|
||||
private function linterDir() {
|
||||
return dirname(__FILE__);
|
||||
}
|
||||
|
||||
// TODO(kaili) a quick and dirty way to figure out rocksdb's root dir.
|
||||
private function rocksdbDir() {
|
||||
return $this->linterDir()."/../..";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
abstract class BaseDirectoryScopedFormatLinter extends ArcanistLinter {
|
||||
|
||||
const LINT_FORMATTING = 1;
|
||||
|
||||
private $changedLines = array();
|
||||
private $rawLintOutput = array();
|
||||
|
||||
abstract protected function getPathsToLint();
|
||||
|
||||
protected function shouldLintPath($path) {
|
||||
foreach ($this->getPathsToLint() as $p) {
|
||||
// check if $path starts with $p
|
||||
if (strncmp($path, $p, strlen($p)) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// API to tell this linter which lines were changed
|
||||
final public function setPathChangedLines($path, $changed) {
|
||||
$this->changedLines[$path] = $changed;
|
||||
}
|
||||
|
||||
final public function willLintPaths(array $paths) {
|
||||
$futures = array();
|
||||
foreach ($paths as $path) {
|
||||
if (!$this->shouldLintPath($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$changed = $this->changedLines[$path];
|
||||
if (!isset($changed)) {
|
||||
// do not run linter if there are no changes
|
||||
continue;
|
||||
}
|
||||
|
||||
$futures[$path] = $this->getFormatFuture($path, $changed);
|
||||
}
|
||||
|
||||
foreach (id(new FutureIterator($futures))->limit(8) as $p => $f) {
|
||||
$this->rawLintOutput[$p] = $f->resolvex();
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function getFormatFuture($path, array $changed);
|
||||
abstract protected function getLintMessage($diff);
|
||||
|
||||
final public function lintPath($path) {
|
||||
if (!isset($this->rawLintOutput[$path])) {
|
||||
return;
|
||||
}
|
||||
|
||||
list($new_content) = $this->rawLintOutput[$path];
|
||||
$old_content = $this->getData($path);
|
||||
|
||||
if ($new_content != $old_content) {
|
||||
$diff = ArcanistDiffUtils::renderDifferences($old_content, $new_content);
|
||||
$this->raiseLintAtOffset(
|
||||
0,
|
||||
self::LINT_FORMATTING,
|
||||
$this->getLintMessage($diff),
|
||||
$old_content,
|
||||
$new_content);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
// Copyright 2015-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
final class FacebookHowtoevenLinter extends ArcanistLinter {
|
||||
|
||||
const VERSION = 'fd9192f324c36d28136d14380f0b552a1385b59b';
|
||||
|
||||
private $parsedTargets = array();
|
||||
|
||||
public function getLinterName() {
|
||||
return 'Howtoeven';
|
||||
}
|
||||
|
||||
protected function getSeverity($code) {
|
||||
$severities = array(
|
||||
ArcanistLintSeverity::SEVERITY_DISABLED,
|
||||
ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
ArcanistLintSeverity::SEVERITY_WARNING,
|
||||
ArcanistLintSeverity::SEVERITY_ERROR,
|
||||
);
|
||||
return idx($severities, $code, ArcanistLintSeverity::SEVERITY_WARNING);
|
||||
}
|
||||
|
||||
public function willLintPaths(array $paths) {
|
||||
// Cleanup previous runs.
|
||||
$this->localExecx("rm -rf _build/_lint");
|
||||
|
||||
// Build compilation database.
|
||||
$lintable_paths = $this->getLintablePaths($paths);
|
||||
$interesting_paths = $this->getInterestingPaths($lintable_paths);
|
||||
|
||||
if (!$lintable_paths) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Run lint.
|
||||
try {
|
||||
$this->localExecx(
|
||||
"%C %C -p _build/dev/ %Ls",
|
||||
$this->getBinaryPath(),
|
||||
$this->getFilteredIssues(),
|
||||
$lintable_paths);
|
||||
} catch (CommandException $exception) {
|
||||
PhutilConsole::getConsole()->writeErr($exception->getMessage());
|
||||
}
|
||||
|
||||
// Load results.
|
||||
$result = id(
|
||||
new SQLite3(
|
||||
$this->getProjectRoot().'/_build/_lint/lint.db',
|
||||
SQLITE3_OPEN_READONLY))
|
||||
->query("SELECT * FROM raised_issues");
|
||||
|
||||
while ($issue = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
// Skip issues not part of the linted file.
|
||||
if (in_array($issue['file'], $interesting_paths)) {
|
||||
$this->addLintMessage(id(new ArcanistLintMessage())
|
||||
->setPath($issue['file'])
|
||||
->setLine($issue['line'])
|
||||
->setChar($issue['column'])
|
||||
->setCode('Howtoeven')
|
||||
->setSeverity($this->getSeverity($issue['severity']))
|
||||
->setName('Hte-'.$issue['name'])
|
||||
->setDescription(
|
||||
sprintf(
|
||||
"%s\n\n%s",
|
||||
($issue['message']) ? $issue['message'] : $issue['description'],
|
||||
$issue['explanation']))
|
||||
->setOriginalText(idx($issue, 'original', ''))
|
||||
->setReplacementText(idx($issue, 'replacement', '')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function lintPath($path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the paths that we know how to lint.
|
||||
*
|
||||
* The strategy is to first look whether there's an existing compilation
|
||||
* database and use that if it's exhaustive. We generate our own only if
|
||||
* necessary.
|
||||
*/
|
||||
private function getLintablePaths($paths) {
|
||||
// Replace headers with existing sources.
|
||||
for ($i = 0; $i < count($paths); $i++) {
|
||||
if (preg_match("/\.h$/", $paths[$i])) {
|
||||
$header = preg_replace("/\.h$/", ".cpp", $paths[$i]);
|
||||
if (file_exists($header)) {
|
||||
$paths[$i] = $header;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if database exists and is exhaustive.
|
||||
$available_paths = $this->getAvailablePaths();
|
||||
$lintable_paths = array_intersect($paths, $available_paths);
|
||||
if ($paths === $lintable_paths) {
|
||||
return $lintable_paths;
|
||||
}
|
||||
|
||||
// Generate our own database.
|
||||
$targets = $this->getTargetsFor($paths);
|
||||
if (!$targets) {
|
||||
PhutilConsole::getConsole()->writeErr(
|
||||
"No build targets found for %s\n",
|
||||
implode(', ', $paths));
|
||||
return array();
|
||||
}
|
||||
|
||||
$this->localExecx("./tools/build/bin/fbconfig.par -r %Ls", $targets);
|
||||
$this->localExecx("./tools/build/bin/fbmake.par gen_cdb");
|
||||
|
||||
$available_paths = $this->getAvailablePaths();
|
||||
$lintable_paths = array_intersect($paths, $available_paths);
|
||||
if ($paths != $lintable_paths) {
|
||||
PhutilConsole::getConsole()->writeErr(
|
||||
"Can't lint %s\n",
|
||||
implode(', ', array_diff($paths, $available_paths)));
|
||||
}
|
||||
|
||||
// Return what we know how to lint.
|
||||
return $lintable_paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available paths in the current compilation database.
|
||||
*/
|
||||
private function getAvailablePaths() {
|
||||
$database_path = $this->getProjectRoot()
|
||||
.'/_build/dev/compile_commands.json';
|
||||
if (!file_exists($database_path)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$entries = json_decode(file_get_contents($database_path), true);
|
||||
$paths = array();
|
||||
foreach ($entries as $entry) {
|
||||
$paths[] = $entry['file'];
|
||||
}
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the targets directories for the given files.
|
||||
*/
|
||||
private static function getTargetsFor($paths) {
|
||||
$targets = array();
|
||||
foreach ($paths as $path) {
|
||||
while (($path = dirname($path)) !== '.') {
|
||||
if (in_array('TARGETS', scandir($path))) {
|
||||
$contents = file_get_contents($path.'/TARGETS');
|
||||
if (strpos($contents, 'cpp_binary') !== false) {
|
||||
$targets[] = $path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_unique($targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* The paths that we actually want to report on.
|
||||
*/
|
||||
private function getInterestingPaths($paths) {
|
||||
$headers = array();
|
||||
foreach ($paths as $path) {
|
||||
$headers[] = preg_replace("/\.cpp$/", ".h", $path);
|
||||
}
|
||||
return array_merge($paths, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* The path where the binary is located. Will return the current dewey binary
|
||||
* unless the `HOWTOEVEN_BUILD` environment variable is set.
|
||||
*/
|
||||
private function getBinaryPath() {
|
||||
$path = sprintf(
|
||||
"/mnt/dewey/fbcode/.commits/%s/builds/howtoeven/client",
|
||||
self::VERSION);
|
||||
|
||||
$build = getenv('HOWTOEVEN_BUILD');
|
||||
if ($build) {
|
||||
$path = sprintf(
|
||||
"./_build/%s/tools/howtoeven/client",
|
||||
$build);
|
||||
if (!file_exists($path)) {
|
||||
PhutilConsole::getConsole()->writeErr(">> %s does not exist\n", $path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command in the root directory.
|
||||
*/
|
||||
private function localExecx($command /* , ... */) {
|
||||
$arguments = func_get_args();
|
||||
return newv('ExecFuture', $arguments)
|
||||
->setCWD($this->getProjectRoot())
|
||||
->resolvex();
|
||||
}
|
||||
|
||||
/**
|
||||
* The root of the project.
|
||||
*/
|
||||
private function getProjectRoot() {
|
||||
return $this->getEngine()->getWorkingCopy()->getProjectRoot();
|
||||
}
|
||||
|
||||
private function getFilteredIssues() {
|
||||
$issues = getenv('HOWTOEVEN_ISSUES');
|
||||
return ($issues) ? csprintf('-issues %s', $issues) : '';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
final class FbcodeClangFormatLinter extends BaseDirectoryScopedFormatLinter {
|
||||
|
||||
const LINT_FORMATTING = 1;
|
||||
const CLANG_FORMAT_BINARY = '/mnt/vol/engshare/admin/scripts/clang-format';
|
||||
|
||||
protected function getPathsToLint() {
|
||||
return array('');
|
||||
}
|
||||
|
||||
public function getLinterName() {
|
||||
return 'CLANG_FORMAT';
|
||||
}
|
||||
|
||||
public function getLintSeverityMap() {
|
||||
return array(
|
||||
self::LINT_FORMATTING => ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
);
|
||||
}
|
||||
|
||||
public function getLintNameMap() {
|
||||
return array(
|
||||
self::LINT_FORMATTING => pht('Changes are not clang-formatted'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getFormatFuture($path, array $changed) {
|
||||
$args = "";
|
||||
foreach ($changed as $key => $value) {
|
||||
$args .= " --lines=$key:$key";
|
||||
}
|
||||
|
||||
$binary = self::CLANG_FORMAT_BINARY;
|
||||
if (!file_exists($binary)) {
|
||||
// trust the $PATH
|
||||
$binary = "clang-format";
|
||||
}
|
||||
|
||||
return new ExecFuture(
|
||||
"%s %s $args",
|
||||
$binary,
|
||||
$this->getEngine()->getFilePathOnDisk($path));
|
||||
}
|
||||
|
||||
protected function getLintMessage($diff) {
|
||||
$link_to_clang_format =
|
||||
"[[ http://fburl.com/clang-format | clang-format ]]";
|
||||
return <<<LINT_MSG
|
||||
Changes in this file were not formatted using $link_to_clang_format.
|
||||
Please run build_tools/format-diff.sh or `make format`
|
||||
LINT_MSG;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All rights reserved.
|
||||
|
||||
class FbcodeCppLinter extends ArcanistLinter {
|
||||
const FLINT = "/home/engshare/tools/flint";
|
||||
const LINT_ERROR = 1;
|
||||
const LINT_WARNING = 2;
|
||||
const LINT_ADVICE = 3;
|
||||
const C_FLAG = "--c_mode=true";
|
||||
|
||||
private $rawLintOutput = array();
|
||||
|
||||
public function willLintPaths(array $paths) {
|
||||
if (!file_exists(self::FLINT)) {
|
||||
return;
|
||||
}
|
||||
$futures = array();
|
||||
foreach ($paths as $p) {
|
||||
$lpath = $this->getEngine()->getFilePathOnDisk($p);
|
||||
$lpath_file = file($lpath);
|
||||
if (preg_match('/\.(c)$/', $lpath) ||
|
||||
preg_match('/-\*-.*Mode: C[; ].*-\*-/', $lpath_file[0]) ||
|
||||
preg_match('/vim(:.*)*:\s*(set\s+)?filetype=c\s*:/', $lpath_file[0])
|
||||
) {
|
||||
$futures[$p] = new ExecFuture("%s %s %s 2>&1",
|
||||
self::FLINT, self::C_FLAG,
|
||||
$this->getEngine()->getFilePathOnDisk($p));
|
||||
} else {
|
||||
$futures[$p] = new ExecFuture("%s %s 2>&1",
|
||||
self::FLINT, $this->getEngine()->getFilePathOnDisk($p));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Futures($futures)->limit(8) as $p => $f) {
|
||||
$this->rawLintOutput[$p] = $f->resolvex();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function getLinterName() {
|
||||
return "FBCPP";
|
||||
}
|
||||
|
||||
public function lintPath($path) {
|
||||
$this->runCppLint($path);
|
||||
}
|
||||
|
||||
private function runCppLint($path) {
|
||||
$msgs = $this->getCppLintOutput($path);
|
||||
foreach ($msgs as $m) {
|
||||
$this->raiseLintAtLine($m['line'], 0, $m['severity'], $m['msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function adviseOnEachPattern(
|
||||
$path,
|
||||
$regex,
|
||||
$message,
|
||||
$lint_type = self::LINT_ADVICE,
|
||||
$match_idx = 0) {
|
||||
$file_data = $this->getData($path);
|
||||
$matches = array();
|
||||
if (!preg_match_all($regex, $file_data, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($matches[$match_idx] as $match) {
|
||||
list($match_str, $offset) = $match;
|
||||
$this->raiseLintAtOffset($offset, $lint_type, $message, $match_str);
|
||||
}
|
||||
}
|
||||
|
||||
public function getLintSeverityMap() {
|
||||
return array(
|
||||
self::LINT_WARNING => ArcanistLintSeverity::SEVERITY_WARNING,
|
||||
self::LINT_ADVICE => ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
self::LINT_ERROR => ArcanistLintSeverity::SEVERITY_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
public function getLintNameMap() {
|
||||
return array(
|
||||
self::LINT_ADVICE => "CppLint Advice",
|
||||
self::LINT_WARNING => "CppLint Warning",
|
||||
self::LINT_ERROR => "CppLint Error"
|
||||
);
|
||||
}
|
||||
|
||||
private function getCppLintOutput($path) {
|
||||
if (!array_key_exists($path, $this->rawLintOutput)) {
|
||||
return array();
|
||||
}
|
||||
list($output) = $this->rawLintOutput[$path];
|
||||
|
||||
$msgs = array();
|
||||
$current = null;
|
||||
$matches = array();
|
||||
foreach (explode("\n", $output) as $line) {
|
||||
if (preg_match('/.*?:(\d+):(.*)/', $line, $matches)) {
|
||||
if ($current) {
|
||||
$msgs[] = $current;
|
||||
}
|
||||
$line = $matches[1];
|
||||
$text = $matches[2];
|
||||
if (preg_match('/.*Warning.*/', $text)) {
|
||||
$sev = self::LINT_WARNING;
|
||||
} else if (preg_match('/.*Advice.*/', $text)) {
|
||||
$sev = self::LINT_ADVICE;
|
||||
} else {
|
||||
$sev = self::LINT_ERROR;
|
||||
}
|
||||
$current = array('line' => $line,
|
||||
'msg' => $text,
|
||||
'severity' => $sev);
|
||||
} else if ($current) {
|
||||
$current['msg'] .= ' ' . $line;
|
||||
}
|
||||
}
|
||||
if ($current) {
|
||||
$msgs[] = $current;
|
||||
}
|
||||
|
||||
return $msgs;
|
||||
}
|
||||
}
|
||||
+4767
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
class FacebookFbcodeLintEngine extends ArcanistLintEngine {
|
||||
|
||||
public function buildLinters() {
|
||||
$linters = array();
|
||||
$paths = $this->getPaths();
|
||||
|
||||
// Remove all deleted files, which are not checked by the
|
||||
// following linters.
|
||||
foreach ($paths as $key => $path) {
|
||||
if (!Filesystem::pathExists($this->getFilePathOnDisk($path))) {
|
||||
unset($paths[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$generated_linter = new ArcanistGeneratedLinter();
|
||||
$linters[] = $generated_linter;
|
||||
|
||||
$nolint_linter = new ArcanistNoLintLinter();
|
||||
$linters[] = $nolint_linter;
|
||||
|
||||
$text_linter = new ArcanistTextLinter();
|
||||
$text_linter->setCustomSeverityMap(array(
|
||||
ArcanistTextLinter::LINT_LINE_WRAP
|
||||
=> ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
));
|
||||
$linters[] = $text_linter;
|
||||
|
||||
$java_text_linter = new ArcanistTextLinter();
|
||||
$java_text_linter->setMaxLineLength(100);
|
||||
$java_text_linter->setCustomSeverityMap(array(
|
||||
ArcanistTextLinter::LINT_LINE_WRAP
|
||||
=> ArcanistLintSeverity::SEVERITY_ADVICE,
|
||||
));
|
||||
$linters[] = $java_text_linter;
|
||||
|
||||
$python_linter = new ArcanistPEP8Linter();
|
||||
$linters[] = $python_linter;
|
||||
|
||||
$cpp_linters = array();
|
||||
$cpp_linters[] = $linters[] = new ArcanistCpplintLinter();
|
||||
$cpp_linters[] = $linters[] = new FbcodeCppLinter();
|
||||
|
||||
$clang_format_linter = new FbcodeClangFormatLinter();
|
||||
$linters[] = $clang_format_linter;
|
||||
|
||||
$spelling_linter = new ArcanistSpellingLinter();
|
||||
$linters[] = $spelling_linter;
|
||||
|
||||
foreach ($paths as $path) {
|
||||
$is_text = false;
|
||||
|
||||
$text_extensions = (
|
||||
'/\.('.
|
||||
'cpp|cxx|c|cc|h|hpp|hxx|tcc|'.
|
||||
'py|rb|hs|pl|pm|tw|'.
|
||||
'php|phpt|css|js|'.
|
||||
'java|'.
|
||||
'thrift|'.
|
||||
'lua|'.
|
||||
'siv|'.
|
||||
'txt'.
|
||||
')$/'
|
||||
);
|
||||
if (preg_match($text_extensions, $path)) {
|
||||
$is_text = true;
|
||||
}
|
||||
if ($is_text) {
|
||||
$nolint_linter->addPath($path);
|
||||
|
||||
$generated_linter->addPath($path);
|
||||
$generated_linter->addData($path, $this->loadData($path));
|
||||
|
||||
if (preg_match('/\.java$/', $path)) {
|
||||
$java_text_linter->addPath($path);
|
||||
$java_text_linter->addData($path, $this->loadData($path));
|
||||
} else {
|
||||
$text_linter->addPath($path);
|
||||
$text_linter->addData($path, $this->loadData($path));
|
||||
}
|
||||
|
||||
$spelling_linter->addPath($path);
|
||||
$spelling_linter->addData($path, $this->loadData($path));
|
||||
}
|
||||
if (preg_match('/\.(cpp|c|cc|cxx|h|hh|hpp|hxx|tcc)$/', $path)
|
||||
&& !preg_match('/third-party/', $path)) {
|
||||
foreach ($cpp_linters as &$linter) {
|
||||
$linter->addPath($path);
|
||||
$linter->addData($path, $this->loadData($path));
|
||||
}
|
||||
|
||||
$clang_format_linter->addPath($path);
|
||||
$clang_format_linter->addData($path, $this->loadData($path));
|
||||
$clang_format_linter->setPathChangedLines(
|
||||
$path, $this->getPathChangedLines($path));
|
||||
}
|
||||
|
||||
// Match *.py and contbuild config files
|
||||
if (preg_match('/(\.(py|tw|smcprops)|^contbuild\/configs\/[^\/]*)$/',
|
||||
$path)) {
|
||||
$space_count = 4;
|
||||
$real_path = $this->getFilePathOnDisk($path);
|
||||
$dir = dirname($real_path);
|
||||
do {
|
||||
if (file_exists($dir.'/.python2space')) {
|
||||
$space_count = 2;
|
||||
break;
|
||||
}
|
||||
$dir = dirname($dir);
|
||||
} while ($dir != '/' && $dir != '.');
|
||||
|
||||
$cur_path_linter = $python_linter;
|
||||
$cur_path_linter->addPath($path);
|
||||
$cur_path_linter->addData($path, $this->loadData($path));
|
||||
|
||||
if (preg_match('/\.tw$/', $path)) {
|
||||
$cur_path_linter->setCustomSeverityMap(array(
|
||||
'E251' => ArcanistLintSeverity::SEVERITY_DISABLED,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$name_linter = new ArcanistFilenameLinter();
|
||||
$linters[] = $name_linter;
|
||||
foreach ($paths as $path) {
|
||||
$name_linter->addPath($path);
|
||||
}
|
||||
|
||||
return $linters;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// Copyright 2015-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
final class FacebookHowtoevenLintEngine extends ArcanistLintEngine {
|
||||
|
||||
public function buildLinters() {
|
||||
$paths = array();
|
||||
|
||||
foreach ($this->getPaths() as $path) {
|
||||
// Don't try to lint deleted files or changed directories.
|
||||
if (!Filesystem::pathExists($path) || is_dir($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/\.(cpp|c|cc|cxx|h|hh|hpp|hxx|tcc)$/', $path)) {
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
$howtoeven = new FacebookHowtoevenLinter();
|
||||
$howtoeven->setPaths($paths);
|
||||
return array($howtoeven);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
class FacebookFbcodeUnitTestEngine extends ArcanistUnitTestEngine {
|
||||
|
||||
public function run() {
|
||||
// For a call to `arc call-conduit differential.updateunitresults` to
|
||||
// succeed we need at least one entry here.
|
||||
$result = new ArcanistUnitTestResult();
|
||||
$result->setName("dummy_placeholder_entry");
|
||||
$result->setResult(ArcanistUnitTestResult::RESULT_PASS);
|
||||
return array($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
class FacebookFbcodeUnitTestEngine extends ArcanistBaseUnitTestEngine {
|
||||
|
||||
public function run() {
|
||||
// For a call to `arc call-conduit differential.updateunitresults` to
|
||||
// succeed we need at least one entry here.
|
||||
$result = new ArcanistUnitTestResult();
|
||||
$result->setName("dummy_placeholder_entry");
|
||||
$result->setResult(ArcanistUnitTestResult::RESULT_PASS);
|
||||
return array($result);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ def parse_src_mk(repo_path):
|
||||
# get all .cc / .c files
|
||||
def get_cc_files(repo_path):
|
||||
cc_files = []
|
||||
for root, dirnames, filenames in os.walk(repo_path): # noqa: B007 T25377293 Grandfathered in
|
||||
for root, dirnames, filenames in os.walk(repo_path):
|
||||
root = root[(len(repo_path) + 1):]
|
||||
if "java" in root:
|
||||
# Skip java
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# Create a tmp directory for the test to use
|
||||
TEST_DIR=$(mktemp -d /dev/shm/fbcode_rocksdb_XXXXXXX)
|
||||
# shellcheck disable=SC2068
|
||||
TEST_TMPDIR="$TEST_DIR" $@ && rm -rf "$TEST_DIR"
|
||||
|
||||
@@ -3,17 +3,19 @@ from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import targets_cfg
|
||||
import pprint
|
||||
|
||||
def pretty_list(lst, indent=8):
|
||||
# TODO(tec): replace this with PrettyPrinter
|
||||
def pretty_list(lst, indent=6):
|
||||
if lst is None or len(lst) == 0:
|
||||
return ""
|
||||
|
||||
if len(lst) == 1:
|
||||
return "\"%s\"" % lst[0]
|
||||
|
||||
|
||||
separator = "\",\n%s\"" % (" " * indent)
|
||||
res = separator.join(sorted(lst))
|
||||
res = "\n" + (" " * indent) + "\"" + res + "\",\n" + (" " * (indent - 4))
|
||||
res = separator.join(lst)
|
||||
res = "\n" + (" " * indent) + "\"" + res + "\",\n" + (" " * (indent - 2))
|
||||
return res
|
||||
|
||||
|
||||
@@ -25,7 +27,7 @@ class TARGETSBuilder:
|
||||
self.total_lib = 0
|
||||
self.total_bin = 0
|
||||
self.total_test = 0
|
||||
self.tests_cfg = ""
|
||||
self.tests_cfg = []
|
||||
|
||||
def __del__(self):
|
||||
self.targets_file.close()
|
||||
@@ -35,8 +37,8 @@ class TARGETSBuilder:
|
||||
headers = "AutoHeaders.RECURSIVE_GLOB"
|
||||
self.targets_file.write(targets_cfg.library_template % (
|
||||
name,
|
||||
pretty_list(srcs),
|
||||
headers,
|
||||
pretty_list(srcs),
|
||||
pretty_list(deps)))
|
||||
self.total_lib = self.total_lib + 1
|
||||
|
||||
@@ -51,13 +53,13 @@ class TARGETSBuilder:
|
||||
exec_mode = "serial"
|
||||
if is_parallel:
|
||||
exec_mode = "parallel"
|
||||
self.tests_cfg += targets_cfg.test_cfg_template % (
|
||||
test_name,
|
||||
str(src),
|
||||
str(exec_mode))
|
||||
self.tests_cfg.append([test_name, str(src), str(exec_mode)])
|
||||
|
||||
self.total_test = self.total_test + 1
|
||||
|
||||
def flush_tests(self):
|
||||
self.targets_file.write(targets_cfg.unittests_template % self.tests_cfg)
|
||||
self.tests_cfg = ""
|
||||
self.targets_file.write(targets_cfg.unittests_template % (
|
||||
pprint.PrettyPrinter().pformat(self.tests_cfg)
|
||||
))
|
||||
|
||||
self.tests_cfg = []
|
||||
|
||||
+71
-100
@@ -2,148 +2,119 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
rocksdb_target_header = """REPO_PATH = package_name() + "/"
|
||||
rocksdb_target_header = """
|
||||
import os
|
||||
|
||||
TARGETS_PATH = os.path.dirname(__file__)
|
||||
REPO_PATH = TARGETS_PATH[(TARGETS_PATH.find('fbcode/') + len('fbcode/')):] + "/"
|
||||
BUCK_BINS = "buck-out/gen/" + REPO_PATH
|
||||
|
||||
TEST_RUNNER = REPO_PATH + "buckifier/rocks_test_runner.sh"
|
||||
|
||||
rocksdb_compiler_flags = [
|
||||
"-fno-builtin-memcmp",
|
||||
"-DROCKSDB_PLATFORM_POSIX",
|
||||
"-DROCKSDB_LIB_IO_POSIX",
|
||||
"-DROCKSDB_FALLOCATE_PRESENT",
|
||||
"-DROCKSDB_MALLOC_USABLE_SIZE",
|
||||
"-DROCKSDB_RANGESYNC_PRESENT",
|
||||
"-DROCKSDB_SCHED_GETCPU_PRESENT",
|
||||
"-DROCKSDB_SUPPORT_THREAD_LOCAL",
|
||||
"-DOS_LINUX",
|
||||
# Flags to enable libs we include
|
||||
"-DSNAPPY",
|
||||
"-DZLIB",
|
||||
"-DBZIP2",
|
||||
"-DLZ4",
|
||||
"-DZSTD",
|
||||
"-DGFLAGS=gflags",
|
||||
"-DNUMA",
|
||||
"-DTBB",
|
||||
# Needed to compile in fbcode
|
||||
"-Wno-expansion-to-defined",
|
||||
# Added missing flags from output of build_detect_platform
|
||||
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
|
||||
"-DROCKSDB_BACKTRACE",
|
||||
"-Wshorten-64-to-32",
|
||||
"-msse",
|
||||
"-msse4.2",
|
||||
"-fno-builtin-memcmp",
|
||||
"-DROCKSDB_PLATFORM_POSIX",
|
||||
"-DROCKSDB_LIB_IO_POSIX",
|
||||
"-DROCKSDB_FALLOCATE_PRESENT",
|
||||
"-DROCKSDB_MALLOC_USABLE_SIZE",
|
||||
"-DROCKSDB_RANGESYNC_PRESENT",
|
||||
"-DROCKSDB_SCHED_GETCPU_PRESENT",
|
||||
"-DROCKSDB_SUPPORT_THREAD_LOCAL",
|
||||
"-DHAVE_SSE42",
|
||||
"-DOS_LINUX",
|
||||
# Flags to enable libs we include
|
||||
"-DSNAPPY",
|
||||
"-DZLIB",
|
||||
"-DBZIP2",
|
||||
"-DLZ4",
|
||||
"-DZSTD",
|
||||
"-DGFLAGS=gflags",
|
||||
"-DNUMA",
|
||||
"-DTBB",
|
||||
# Needed to compile in fbcode
|
||||
"-Wno-expansion-to-defined",
|
||||
]
|
||||
|
||||
rocksdb_external_deps = [
|
||||
("bzip2", None, "bz2"),
|
||||
("snappy", None, "snappy"),
|
||||
("zlib", None, "z"),
|
||||
("gflags", None, "gflags"),
|
||||
("lz4", None, "lz4"),
|
||||
("zstd", None),
|
||||
("tbb", None),
|
||||
("numa", None, "numa"),
|
||||
("googletest", None, "gtest"),
|
||||
('bzip2', None, 'bz2'),
|
||||
('snappy', None, "snappy"),
|
||||
('zlib', None, 'z'),
|
||||
('gflags', None, 'gflags'),
|
||||
('lz4', None, 'lz4'),
|
||||
('zstd', None),
|
||||
('tbb', None),
|
||||
("numa", None, "numa"),
|
||||
("googletest", None, "gtest"),
|
||||
]
|
||||
|
||||
rocksdb_preprocessor_flags = [
|
||||
# Directories with files for #include
|
||||
"-I" + REPO_PATH + "include/",
|
||||
"-I" + REPO_PATH,
|
||||
# Directories with files for #include
|
||||
"-I" + REPO_PATH + "include/",
|
||||
"-I" + REPO_PATH,
|
||||
]
|
||||
|
||||
rocksdb_arch_preprocessor_flags = {
|
||||
"x86_64": [
|
||||
"-DHAVE_SSE42",
|
||||
"-DHAVE_PCLMUL",
|
||||
],
|
||||
}
|
||||
|
||||
build_mode = read_config("fbcode", "build_mode")
|
||||
|
||||
is_opt_mode = build_mode.startswith("opt")
|
||||
|
||||
# -DNDEBUG is added by default in opt mode in fbcode. But adding it twice
|
||||
# doesn't harm and avoid forgetting to add it.
|
||||
if is_opt_mode:
|
||||
rocksdb_compiler_flags.append("-DNDEBUG")
|
||||
"""
|
||||
|
||||
|
||||
library_template = """
|
||||
cpp_library(
|
||||
name = "%s",
|
||||
srcs = [%s],
|
||||
headers = %s,
|
||||
arch_preprocessor_flags = rocksdb_arch_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
srcs = [%s],
|
||||
deps = [%s],
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
external_deps = rocksdb_external_deps,
|
||||
)
|
||||
"""
|
||||
|
||||
binary_template = """
|
||||
cpp_binary(
|
||||
name = "%s",
|
||||
srcs = [%s],
|
||||
arch_preprocessor_flags = rocksdb_arch_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
deps = [%s],
|
||||
external_deps = rocksdb_external_deps,
|
||||
name = "%s",
|
||||
srcs = [%s],
|
||||
deps = [%s],
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
external_deps = rocksdb_external_deps,
|
||||
)
|
||||
"""
|
||||
|
||||
test_cfg_template = """ [
|
||||
"%s",
|
||||
"%s",
|
||||
"%s",
|
||||
],
|
||||
"""
|
||||
|
||||
unittests_template = """
|
||||
# [test_name, test_src, test_type]
|
||||
ROCKS_TESTS = [
|
||||
%s]
|
||||
ROCKS_TESTS = %s
|
||||
|
||||
|
||||
# Generate a test rule for each entry in ROCKS_TESTS
|
||||
# Do not build the tests in opt mode, since SyncPoint and other test code
|
||||
# will not be included.
|
||||
if not is_opt_mode:
|
||||
for test_cfg in ROCKS_TESTS:
|
||||
test_name = test_cfg[0]
|
||||
test_cc = test_cfg[1]
|
||||
ttype = "gtest" if test_cfg[2] == "parallel" else "simple"
|
||||
test_bin = test_name + "_bin"
|
||||
for test_cfg in ROCKS_TESTS:
|
||||
test_name = test_cfg[0]
|
||||
test_cc = test_cfg[1]
|
||||
ttype = "gtest" if test_cfg[2] == "parallel" else "simple"
|
||||
test_bin = test_name + "_bin"
|
||||
|
||||
cpp_binary (
|
||||
name = test_bin,
|
||||
srcs = [test_cc],
|
||||
deps = [":rocksdb_test_lib"],
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
arch_preprocessor_flags = rocksdb_arch_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
external_deps = rocksdb_external_deps,
|
||||
)
|
||||
cpp_binary (
|
||||
name = test_bin,
|
||||
srcs = [test_cc],
|
||||
deps = [":rocksdb_test_lib"],
|
||||
preprocessor_flags = rocksdb_preprocessor_flags,
|
||||
compiler_flags = rocksdb_compiler_flags,
|
||||
external_deps = rocksdb_external_deps,
|
||||
)
|
||||
|
||||
custom_unittest(
|
||||
name = test_name,
|
||||
type = ttype,
|
||||
deps = [":" + test_bin],
|
||||
command = [TEST_RUNNER, BUCK_BINS + test_bin]
|
||||
)
|
||||
custom_unittest(
|
||||
name = test_name,
|
||||
type = ttype,
|
||||
deps = [":" + test_bin],
|
||||
command = [TEST_RUNNER, BUCK_BINS + test_bin]
|
||||
)
|
||||
|
||||
custom_unittest(
|
||||
name = "make_rocksdbjavastatic",
|
||||
command = ["internal_repo_rocksdb/make_rocksdbjavastatic.sh"],
|
||||
type = "simple",
|
||||
command = ["internal_repo_rocksdb/make_rocksdbjavastatic.sh"],
|
||||
)
|
||||
|
||||
custom_unittest(
|
||||
name = "make_rocksdb_lite_release",
|
||||
command = ["internal_repo_rocksdb/make_rocksdb_lite_release.sh"],
|
||||
type = "simple",
|
||||
command = ["internal_repo_rocksdb/make_rocksdb_lite_release.sh"],
|
||||
)
|
||||
"""
|
||||
|
||||
+154
-250
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
#
|
||||
# Detects OS we're compiling on and outputs a file specified by the first
|
||||
# argument, which in turn gets read while processing Makefile.
|
||||
@@ -16,8 +16,6 @@
|
||||
# PLATFORM_CXXFLAGS C++ compiler flags. Will contain:
|
||||
# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports versioned
|
||||
# shared libraries, empty otherwise.
|
||||
# FIND Command for the find utility
|
||||
# WATCH Command for the watch utility
|
||||
#
|
||||
# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the following:
|
||||
#
|
||||
@@ -66,23 +64,11 @@ rm -f "$OUTPUT"
|
||||
touch "$OUTPUT"
|
||||
|
||||
if test -z "$CC"; then
|
||||
if [ -x "$(command -v cc)" ]; then
|
||||
CC=cc
|
||||
elif [ -x "$(command -v clang)" ]; then
|
||||
CC=clang
|
||||
else
|
||||
CC=cc
|
||||
fi
|
||||
CC=cc
|
||||
fi
|
||||
|
||||
if test -z "$CXX"; then
|
||||
if [ -x "$(command -v g++)" ]; then
|
||||
CXX=g++
|
||||
elif [ -x "$(command -v clang++)" ]; then
|
||||
CXX=clang++
|
||||
else
|
||||
CXX=g++
|
||||
fi
|
||||
CXX=g++
|
||||
fi
|
||||
|
||||
# Detect OS
|
||||
@@ -99,15 +85,7 @@ if test -z "$CLANG_SCAN_BUILD"; then
|
||||
fi
|
||||
|
||||
if test -z "$CLANG_ANALYZER"; then
|
||||
CLANG_ANALYZER=$(command -v clang++ 2> /dev/null)
|
||||
fi
|
||||
|
||||
if test -z "$FIND"; then
|
||||
FIND=find
|
||||
fi
|
||||
|
||||
if test -z "$WATCH"; then
|
||||
WATCH=watch
|
||||
CLANG_ANALYZER=$(which clang++ 2> /dev/null)
|
||||
fi
|
||||
|
||||
COMMON_FLAGS="$COMMON_FLAGS ${CFLAGS}"
|
||||
@@ -144,8 +122,6 @@ case "$TARGET_OS" in
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DOS_LINUX"
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
|
||||
else
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -latomic"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt"
|
||||
# PORT_FILES=port/linux/linux_specific.cc
|
||||
@@ -165,7 +141,6 @@ case "$TARGET_OS" in
|
||||
;;
|
||||
FreeBSD)
|
||||
PLATFORM=OS_FREEBSD
|
||||
CXX=clang++
|
||||
COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp -D_REENTRANT -DOS_FREEBSD"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread"
|
||||
# PORT_FILES=port/freebsd/freebsd_specific.cc
|
||||
@@ -178,12 +153,9 @@ case "$TARGET_OS" in
|
||||
;;
|
||||
OpenBSD)
|
||||
PLATFORM=OS_OPENBSD
|
||||
CXX=clang++
|
||||
COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp -D_REENTRANT -DOS_OPENBSD"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -pthread"
|
||||
# PORT_FILES=port/openbsd/openbsd_specific.cc
|
||||
FIND=gfind
|
||||
WATCH=gnuwatch
|
||||
;;
|
||||
DragonFly)
|
||||
PLATFORM=OS_DRAGONFLYBSD
|
||||
@@ -198,8 +170,6 @@ case "$TARGET_OS" in
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DCYGWIN"
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
|
||||
else
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -latomic"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt"
|
||||
# PORT_FILES=port/linux/linux_specific.cc
|
||||
@@ -240,137 +210,117 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SNAPPY; then
|
||||
# Test whether Snappy library is installed
|
||||
# http://code.google.com/p/snappy/
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <snappy.h>
|
||||
int main() {}
|
||||
# Test whether Snappy library is installed
|
||||
# http://code.google.com/p/snappy/
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <snappy.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lsnappy"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lsnappy"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lsnappy"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lsnappy"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_GFLAGS; then
|
||||
# Test whether gflags library is installed
|
||||
# http://gflags.github.io/gflags/
|
||||
# check if the namespace is gflags
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null << EOF
|
||||
#include <gflags/gflags.h>
|
||||
int main() {}
|
||||
# Test whether gflags library is installed
|
||||
# http://gflags.github.io/gflags/
|
||||
# check if the namespace is gflags
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null << EOF
|
||||
#include <gflags/gflags.h>
|
||||
using namespace gflags;
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DGFLAGS=1"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lgflags"
|
||||
else
|
||||
# check if namespace is google
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null << EOF
|
||||
#include <gflags/gflags.h>
|
||||
using namespace google;
|
||||
int main() {}
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DGFLAGS=gflags"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lgflags"
|
||||
else
|
||||
# check if namespace is google
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null << EOF
|
||||
#include <gflags/gflags.h>
|
||||
using namespace google;
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DGFLAGS=google"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lgflags"
|
||||
fi
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DGFLAGS=google"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lgflags"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZLIB; then
|
||||
# Test whether zlib library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <zlib.h>
|
||||
int main() {}
|
||||
# Test whether zlib library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <zlib.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DZLIB"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lz"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lz"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DZLIB"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lz"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lz"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_BZIP; then
|
||||
# Test whether bzip library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <bzlib.h>
|
||||
int main() {}
|
||||
# Test whether bzip library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <bzlib.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DBZIP2"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lbz2"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lbz2"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DBZIP2"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lbz2"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lbz2"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_LZ4; then
|
||||
# Test whether lz4 library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
int main() {}
|
||||
# Test whether lz4 library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DLZ4"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -llz4"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -llz4"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DLZ4"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -llz4"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -llz4"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZSTD; then
|
||||
# Test whether zstd library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <zstd.h>
|
||||
int main() {}
|
||||
# Test whether zstd library is installed
|
||||
$CXX $CFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <zstd.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DZSTD"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lzstd"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lzstd"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DZSTD"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lzstd"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lzstd"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_NUMA; then
|
||||
# Test whether numa is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null -lnuma 2>/dev/null <<EOF
|
||||
#include <numa.h>
|
||||
#include <numaif.h>
|
||||
int main() {}
|
||||
# Test whether numa is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null -lnuma 2>/dev/null <<EOF
|
||||
#include <numa.h>
|
||||
#include <numaif.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DNUMA"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lnuma"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lnuma"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DNUMA"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lnuma"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lnuma"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_TBB; then
|
||||
# Test whether tbb is available
|
||||
$CXX $CFLAGS $LDFLAGS -x c++ - -o /dev/null -ltbb 2>/dev/null <<EOF
|
||||
#include <tbb/tbb.h>
|
||||
int main() {}
|
||||
# Test whether tbb is available
|
||||
$CXX $CFLAGS $LDFLAGS -x c++ - -o /dev/null -ltbb 2>/dev/null <<EOF
|
||||
#include <tbb/tbb.h>
|
||||
int main() {}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DTBB"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ltbb"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -ltbb"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DTBB"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ltbb"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -ltbb"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_JEMALLOC; then
|
||||
# Test whether jemalloc is available
|
||||
if echo 'int main() {}' | $CXX $CFLAGS -x c++ - -o /dev/null -ljemalloc \
|
||||
2>/dev/null; then
|
||||
# This will enable some preprocessor identifiers in the Makefile
|
||||
JEMALLOC=1
|
||||
# JEMALLOC can be enabled either using the flag (like here) or by
|
||||
# providing direct link to the jemalloc library
|
||||
WITH_JEMALLOC_FLAG=1
|
||||
fi
|
||||
fi
|
||||
if ! test $JEMALLOC && ! test $ROCKSDB_DISABLE_TCMALLOC; then
|
||||
# Test whether jemalloc is available
|
||||
if echo 'int main() {}' | $CXX $CFLAGS -x c++ - -o /dev/null -ljemalloc \
|
||||
2>/dev/null; then
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ljemalloc"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -ljemalloc"
|
||||
JEMALLOC=1
|
||||
else
|
||||
# jemalloc is not available. Let's try tcmalloc
|
||||
if echo 'int main() {}' | $CXX $CFLAGS -x c++ - -o /dev/null \
|
||||
-ltcmalloc 2>/dev/null; then
|
||||
@@ -379,100 +329,88 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_MALLOC_USABLE_SIZE; then
|
||||
# Test whether malloc_usable_size is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <malloc.h>
|
||||
int main() {
|
||||
size_t res = malloc_usable_size(0);
|
||||
return 0;
|
||||
}
|
||||
# Test whether malloc_usable_size is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <malloc.h>
|
||||
int main() {
|
||||
size_t res = malloc_usable_size(0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_MALLOC_USABLE_SIZE"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_MALLOC_USABLE_SIZE"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_PTHREAD_MUTEX_ADAPTIVE_NP; then
|
||||
# Test whether PTHREAD_MUTEX_ADAPTIVE_NP mutex type is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <pthread.h>
|
||||
int main() {
|
||||
int x = PTHREAD_MUTEX_ADAPTIVE_NP;
|
||||
return 0;
|
||||
}
|
||||
# Test whether PTHREAD_MUTEX_ADAPTIVE_NP mutex type is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <pthread.h>
|
||||
int main() {
|
||||
int x = PTHREAD_MUTEX_ADAPTIVE_NP;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_PTHREAD_ADAPTIVE_MUTEX"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_PTHREAD_ADAPTIVE_MUTEX"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_BACKTRACE; then
|
||||
# Test whether backtrace is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <execinfo.h>>
|
||||
# Test whether backtrace is available
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <execinfo.h>>
|
||||
int main() {
|
||||
void* frames[1];
|
||||
backtrace_symbols(frames, backtrace(frames, 1));
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_BACKTRACE"
|
||||
else
|
||||
# Test whether execinfo library is installed
|
||||
$CXX $CFLAGS -lexecinfo -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <execinfo.h>
|
||||
int main() {
|
||||
void* frames[1];
|
||||
backtrace_symbols(frames, backtrace(frames, 1));
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_BACKTRACE"
|
||||
else
|
||||
# Test whether execinfo library is installed
|
||||
$CXX $CFLAGS -lexecinfo -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <execinfo.h>
|
||||
int main() {
|
||||
void* frames[1];
|
||||
backtrace_symbols(frames, backtrace(frames, 1));
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_BACKTRACE"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lexecinfo"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lexecinfo"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lexecinfo"
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS -lexecinfo"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_PG; then
|
||||
# Test if -pg is supported
|
||||
$CXX $CFLAGS -pg -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
# Test if -pg is supported
|
||||
$CXX $CFLAGS -pg -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
PROFILING_FLAGS=-pg
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
PROFILING_FLAGS=-pg
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SYNC_FILE_RANGE; then
|
||||
# Test whether sync_file_range is supported for compatibility with an old glibc
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <fcntl.h>
|
||||
int main() {
|
||||
int fd = open("/dev/null", 0);
|
||||
sync_file_range(fd, 0, 1024, SYNC_FILE_RANGE_WRITE);
|
||||
}
|
||||
# Test whether sync_file_range is supported for compatibility with an old glibc
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <fcntl.h>
|
||||
int main() {
|
||||
int fd = open("/dev/null", 0);
|
||||
sync_file_range(fd, 0, 1024, SYNC_FILE_RANGE_WRITE);
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_RANGESYNC_PRESENT"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_RANGESYNC_PRESENT"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SCHED_GETCPU; then
|
||||
# Test whether sched_getcpu is supported
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <sched.h>
|
||||
int main() {
|
||||
int cpuid = sched_getcpu();
|
||||
}
|
||||
# Test whether sched_getcpu is supported
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <sched.h>
|
||||
int main() {
|
||||
int cpuid = sched_getcpu();
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_SCHED_GETCPU_PRESENT"
|
||||
fi
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_SCHED_GETCPU_PRESENT"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -504,28 +442,21 @@ if test "$USE_HDFS"; then
|
||||
JAVA_LDFLAGS="$JAVA_LDFLAGS $HDFS_LDFLAGS"
|
||||
fi
|
||||
|
||||
if test -z "$PORTABLE"; then
|
||||
if test "$USE_SSE"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -msse4.2"
|
||||
elif test -z "$PORTABLE"; then
|
||||
if test -n "`echo $TARGET_ARCHITECTURE | grep ^ppc64`"; then
|
||||
# Tune for this POWER processor, treating '+' models as base models
|
||||
POWER=`LD_SHOW_AUXV=1 /bin/true | grep AT_PLATFORM | grep -E -o power[0-9]+`
|
||||
COMMON_FLAGS="$COMMON_FLAGS -mcpu=$POWER -mtune=$POWER "
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^s390x`"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=z10 "
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^arm`"; then
|
||||
# TODO: Handle this with approprite options.
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" == "IOS" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" != "AIX" ] && [ "$TARGET_OS" != "SunOS" ]; then
|
||||
elif [ "$TARGET_OS" != AIX ] && [ "$TARGET_OS" != SunOS ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=native "
|
||||
elif test "$USE_SSE"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -msse4.2 -mpclmul"
|
||||
fi
|
||||
elif test "$USE_SSE"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -msse4.2 -mpclmul"
|
||||
fi
|
||||
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
$CXX $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <cstdint>
|
||||
#include <nmmintrin.h>
|
||||
int main() {
|
||||
@@ -536,24 +467,6 @@ if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DHAVE_SSE42"
|
||||
elif test "$USE_SSE"; then
|
||||
echo "warning: USE_SSE specified but compiler could not use SSE intrinsics, disabling"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <cstdint>
|
||||
#include <wmmintrin.h>
|
||||
int main() {
|
||||
const auto a = _mm_set_epi64x(0, 0);
|
||||
const auto b = _mm_set_epi64x(0, 0);
|
||||
const auto c = _mm_clmulepi64_si128(a, b, 0x00);
|
||||
auto d = _mm_cvtsi128_si64(c);
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DHAVE_PCLMUL"
|
||||
elif test "$USE_SSE"; then
|
||||
echo "warning: USE_SSE specified but compiler could not use PCLMUL intrinsics, disabling"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# iOS doesn't support thread-local storage, but this check would erroneously
|
||||
@@ -604,16 +517,7 @@ echo "ROCKSDB_PATCH=$ROCKSDB_PATCH" >> "$OUTPUT"
|
||||
echo "CLANG_SCAN_BUILD=$CLANG_SCAN_BUILD" >> "$OUTPUT"
|
||||
echo "CLANG_ANALYZER=$CLANG_ANALYZER" >> "$OUTPUT"
|
||||
echo "PROFILING_FLAGS=$PROFILING_FLAGS" >> "$OUTPUT"
|
||||
echo "FIND=$FIND" >> "$OUTPUT"
|
||||
echo "WATCH=$WATCH" >> "$OUTPUT"
|
||||
# This will enable some related identifiers for the preprocessor
|
||||
if test -n "$JEMALLOC"; then
|
||||
echo "JEMALLOC=1" >> "$OUTPUT"
|
||||
fi
|
||||
# Indicates that jemalloc should be enabled using -ljemalloc flag
|
||||
# The alternative is to porvide a direct link to the library via JEMALLOC_LIB
|
||||
# and JEMALLOC_INCLUDE
|
||||
if test -n "$WITH_JEMALLOC_FLAG"; then
|
||||
echo "WITH_JEMALLOC_FLAG=$WITH_JEMALLOC_FLAG" >> "$OUTPUT"
|
||||
fi
|
||||
echo "LUA_PATH=$LUA_PATH" >> "$OUTPUT"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2016, Facebook. All rights reserved.
|
||||
#
|
||||
@@ -13,12 +13,10 @@ error=0
|
||||
|
||||
function log {
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
# shellcheck disable=SC2068
|
||||
echo $DATE $@
|
||||
}
|
||||
|
||||
function log_err {
|
||||
# shellcheck disable=SC2145
|
||||
log "ERROR: $@ Error code: $error."
|
||||
}
|
||||
|
||||
@@ -69,7 +67,7 @@ function update_repo_status {
|
||||
#
|
||||
|
||||
# Path to the determinator from the root of the RocksDB repo.
|
||||
CONTRUN_DETERMINATOR=./build_tools/RocksDBCommonHelper.php
|
||||
CONTRUN_DETERMINATOR=./arcanist_util/config/RocksDBCommonHelper.php
|
||||
|
||||
# Value of the previous commit.
|
||||
PREV_COMMIT=
|
||||
|
||||
+18
-19
@@ -1,19 +1,18 @@
|
||||
# shellcheck disable=SC2148
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/8219ec1bcedf8ad9da05e121e193364de2cc4f61/5.x/centos6-native/c447969
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/64d8d58e3d84f8bde7a029763d4f5baf39d0d5b9/stable/centos6-native/6aaf4de
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/ba9be983c81de7299b59fe71950c664a84dcb5f8/5.x/gcc-5-glibc-2.23/339d858
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/f20197cf3d4bd50339c9777aaa0b2ccadad9e2cb/2.23/gcc-5-glibc-2.23/ca1d1c0
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/6427ce8c7496e4ab06c2da81543b94c0de8be3d0/1.1.3/gcc-5-glibc-2.23/9bc6787
|
||||
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/8f1e8b867d26efef93eac2fabbdb2e1d512665d7/1.2.8/gcc-5-glibc-2.23/9bc6787
|
||||
BZIP2_BASE=/mnt/gvfs/third-party2/bzip2/70471c0571559fe0af7db6d7e8860b93a7eadfe1/1.0.6/gcc-5-glibc-2.23/9bc6787
|
||||
LZ4_BASE=/mnt/gvfs/third-party2/lz4/453c89d6f0e68cdf1c151c769197fabedad9cac8/r131/gcc-5-glibc-2.23/9bc6787
|
||||
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/00a40fa5f8bd2cd0622f2e868552793aef37ccf4/1.3.0/gcc-5-glibc-2.23/03859b5
|
||||
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/47eef08f9acb77de982fbda6047c26d330739538/2.2.0/gcc-5-glibc-2.23/9bc6787
|
||||
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/4414ddc78df8008b35cc4adac23590ad29148584/master/gcc-5-glibc-2.23/d506c82
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/9d7ae2693d05d62f9a579cb21e6b717cf257a75d/2.0.11/gcc-5-glibc-2.23/9bc6787
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/2b2dd58e3a52ccf2c1d827def59e5f740de0ad15/1.2/gcc-5-glibc-2.23/b443de1
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/379addf7ab2468a2b4293b47456cfcd1c9cb318d/4.3/gcc-5-glibc-2.23/9bc6787
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/3f68f5fe65a85b7c2d3e66852268fbd1efdb3151/4.0.9-36_fbk5_2933_gd092e3f/gcc-5-glibc-2.23/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/b9fab0aec99d9c36408e810b2677e91c12807afd/2.28/centos6-native/da39a3e
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/423431d61786b20bcc3bde8972901130cb29e6b3/3.11.0/gcc-5-glibc-2.23/9bc6787
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/3b0bb3bd9a0f690a069c479fcc0f7424fc7456d2/5.2.3/gcc-5-glibc-2.23/65372bd
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/2928bb3ed95bf64f5b388ee88c30dc74710c3b35/5.x/centos6-native/f4950a1
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/a5fea028cb7ba43498976e1f8054b0b2e790c295/stable/centos6-native/6aaf4de
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/7a9099f6587ee4378c0b1fa32bb8934019d30ca4/5.x/gcc-5-glibc-2.23/339d858
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/3b7c6469854dfc7832a1c3cc5b86919a84e5f865/2.23/gcc-5-glibc-2.23/ca1d1c0
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/8c38a4c1e52b4c2cc8a9cdc31b9c947ed7dbfcb4/1.1.3/gcc-5-glibc-2.23/9bc6787
|
||||
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/d7861abe6f0e27ab98c9303b95a662f0e4cdedb5/1.2.8/gcc-5-glibc-2.23/9bc6787
|
||||
BZIP2_BASE=/mnt/gvfs/third-party2/bzip2/740325875f6729f42d28deaa2147b0854f3a347e/1.0.6/gcc-5-glibc-2.23/9bc6787
|
||||
LZ4_BASE=/mnt/gvfs/third-party2/lz4/0815d59804160c96caac5f27ca004f51af893dc6/r131/gcc-5-glibc-2.23/9bc6787
|
||||
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/c15a4f5f619a2930478d01e2e34dc1e0652b0873/1.1.4/gcc-5-glibc-2.23/03859b5
|
||||
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/f905a5e1032fb30c05db3d3752319857388c0c49/2.2.0/gcc-5-glibc-2.23/9bc6787
|
||||
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/8d60633d822a2a55849c73db24e74a25e52b71db/master/gcc-5-glibc-2.23/1c32b4b
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/17c514c4d102a25ca15f4558be564eeed76f4b6a/2.0.8/gcc-5-glibc-2.23/9bc6787
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/8db74270cd6d0212ac92d69e7fc7beefe617d772/trunk/gcc-5-glibc-2.23/b1847cb
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/9d9a554877d0c5bef330fe818ab7178806dd316a/4.0_update2/gcc-5-glibc-2.23/9bc6787
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/90c9734afc5579c9d1db529fa788d09f97763b85/4.0.9-36_fbk5_2933_gd092e3f/gcc-5-glibc-2.23/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/9e829389ef61b92c62de8748c80169aaf25ce1f0/2.26.1/centos6-native/da39a3e
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/d7f4d4d86674a57668e3a96f76f0e17dd0eb8765/3.11.0/gcc-5-glibc-2.23/9bc6787
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/61e4abf5813bbc39bc4f548757ccfcadde175a48/5.2.3/gcc-5-glibc-2.23/65372bd
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# shellcheck disable=SC2148
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/cf7d14c625ce30bae1a4661c2319c5a283e4dd22/4.8.1/centos6-native/cc6c9dc
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/8598c375b0e94e1448182eb3df034704144a838d/stable/centos6-native/3f16ddd
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/d6e0a7da6faba45f5e5b1638f9edd7afc2f34e7d/4.8.1/gcc-4.8.1-glibc-2.17/8aac7fc
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
docker run -v $PWD:/rocks -w /rocks buildpack-deps make
|
||||
|
||||
@@ -83,7 +83,6 @@ CFLAGS+=" -DTBB"
|
||||
|
||||
# use Intel SSE support for checksum calculations
|
||||
export USE_SSE=1
|
||||
export PORTABLE=1
|
||||
|
||||
BINUTILS="$BINUTILS_BASE/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
|
||||
@@ -54,7 +54,6 @@ TBB_LIBS="$TBB_BASE/lib/libtbb.a"
|
||||
|
||||
# use Intel SSE support for checksum calculations
|
||||
export USE_SSE=1
|
||||
export PORTABLE=1
|
||||
|
||||
BINUTILS="$BINUTILS_BASE/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# If clang_format_diff.py command is not specfied, we assume we are able to
|
||||
# access directly without any path.
|
||||
if [ -z $CLANG_FORMAT_DIFF ]
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
set -e
|
||||
if [ -z "$GIT" ]
|
||||
then
|
||||
GIT="git"
|
||||
fi
|
||||
|
||||
# Print out the colored progress info so that it can be brainlessly
|
||||
# distinguished by users.
|
||||
function title() {
|
||||
echo -e "\033[1;32m$*\033[0m"
|
||||
}
|
||||
|
||||
usage="Create new RocksDB version and prepare it for the release process\n"
|
||||
usage+="USAGE: ./make_new_version.sh <version> [<remote>]\n"
|
||||
usage+=" version: specify a version without '.fb' suffix (e.g. 5.4).\n"
|
||||
usage+=" remote: name of the remote to push the branch to (default: origin)."
|
||||
|
||||
# -- Pre-check
|
||||
if [[ $# < 1 ]]; then
|
||||
echo -e $usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROCKSDB_VERSION=$1
|
||||
|
||||
REMOTE="origin"
|
||||
if [[ $# > 1 ]]; then
|
||||
REMOTE=$2
|
||||
fi
|
||||
|
||||
GIT_BRANCH=`git rev-parse --abbrev-ref HEAD`
|
||||
echo $GIT_BRANCH
|
||||
|
||||
if [ $GIT_BRANCH != "master" ]; then
|
||||
echo "Error: Current branch is '$GIT_BRANCH', Please switch to master branch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
title "Adding new tag for this release ..."
|
||||
BRANCH="$ROCKSDB_VERSION.fb"
|
||||
$GIT checkout -b $BRANCH
|
||||
|
||||
# Setting up the proxy for remote repo access
|
||||
title "Pushing new branch to remote repo ..."
|
||||
git push $REMOTE --set-upstream $BRANCH
|
||||
|
||||
title "Branch $BRANCH is pushed to github;"
|
||||
@@ -1,4 +1,3 @@
|
||||
# shellcheck disable=SC1113
|
||||
#/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
@@ -29,14 +28,12 @@ function package() {
|
||||
if dpkg --get-selections | grep --quiet $1; then
|
||||
log "$1 is already installed. skipping."
|
||||
else
|
||||
# shellcheck disable=SC2068
|
||||
apt-get install $@ -y
|
||||
fi
|
||||
elif [[ $OS = "centos" ]]; then
|
||||
if rpm -qa | grep --quiet $1; then
|
||||
log "$1 is already installed. skipping."
|
||||
else
|
||||
# shellcheck disable=SC2068
|
||||
yum install $@ -y
|
||||
fi
|
||||
fi
|
||||
@@ -55,7 +52,6 @@ function gem_install() {
|
||||
if gem list | grep --quiet $1; then
|
||||
log "$1 is already installed. skipping."
|
||||
else
|
||||
# shellcheck disable=SC2068
|
||||
gem install $@
|
||||
fi
|
||||
}
|
||||
@@ -129,5 +125,4 @@ function main() {
|
||||
include $LIB_DIR
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2068
|
||||
main $@
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# This script is executed by Sandcastle
|
||||
# to determine next steps to run
|
||||
|
||||
@@ -343,7 +343,7 @@ LITE_BUILD_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB debug version',
|
||||
'shell':'$LITE make J=1 all check || $CONTRUN_NAME=lite $TASK_CREATION_TOOL',
|
||||
'shell':'$LITE make J=1 static_lib || $CONTRUN_NAME=lite_static_lib $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -353,19 +353,23 @@ LITE_BUILD_COMMANDS="[
|
||||
]"
|
||||
|
||||
#
|
||||
# Report RocksDB lite binary size to scuba
|
||||
REPORT_LITE_BINARY_SIZE_COMMANDS="[
|
||||
# RocksDB lite tests
|
||||
#
|
||||
LITE_UNIT_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb Lite Binary Size',
|
||||
'name':'Rocksdb Lite Unit Test',
|
||||
'oncall':'$ONCALL',
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Report RocksDB Lite binary size to scuba',
|
||||
'shell':'tools/report_lite_binary_size.sh',
|
||||
'name':'Build RocksDB debug version',
|
||||
'shell':'$SHM $LITE make J=1 check || $CONTRUN_NAME=lite_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
@@ -560,7 +564,7 @@ TSAN_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN CRASH_TEST_KILL_ODD=1887 CRASH_TEST_EXT_ARGS=--log2_keys_per_lock=22 make J=1 crash_test || $CONTRUN_NAME=tsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN CRASH_TEST_KILL_ODD=1887 make J=1 crash_test || $CONTRUN_NAME=tsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -579,7 +583,39 @@ run_format_compatible()
|
||||
rm -rf /dev/shm/rocksdb
|
||||
mkdir /dev/shm/rocksdb
|
||||
|
||||
tools/check_format_compatible.sh
|
||||
echo '
|
||||
if [ -e "build_tools/build_detect_platform" ]
|
||||
then
|
||||
sed "s/tcmalloc/nothingnothingnothing/g" build_tools/build_detect_platform > $TEST_TMPDIR/temp_build_file
|
||||
rm -rf build_tools/build_detect_platform
|
||||
cp $TEST_TMPDIR/temp_build_file build_tools/build_detect_platform
|
||||
chmod +x build_tools/build_detect_platform
|
||||
fi
|
||||
|
||||
if [ -e "build_detect_platform" ]
|
||||
then
|
||||
sed "s/tcmalloc/nothingnothingnothing/g" build_detect_platform > $TEST_TMPDIR/temp_build_file
|
||||
rm -rf build_detect_platform
|
||||
cp $TEST_TMPDIR/temp_build_file build_detect_platform
|
||||
chmod +x build_detect_platform
|
||||
fi
|
||||
|
||||
make ldb -j32
|
||||
|
||||
if [ -e "build_detect_platform" ]
|
||||
then
|
||||
git checkout -- build_detect_platform
|
||||
fi
|
||||
|
||||
if [ -e "build_tools/build_detect_platform" ]
|
||||
then
|
||||
git checkout -- build_tools/build_detect_platform
|
||||
fi
|
||||
' > temp_build_ldb.sh
|
||||
|
||||
sed "s/make ldb -j32/source temp_build_ldb.sh/g" tools/check_format_compatible.sh > tools/temp_check_format_compatible.sh
|
||||
chmod +x tools/temp_check_format_compatible.sh
|
||||
tools/temp_check_format_compatible.sh
|
||||
}
|
||||
|
||||
FORMAT_COMPATIBLE_COMMANDS="[
|
||||
@@ -744,8 +780,8 @@ case $1 in
|
||||
lite)
|
||||
echo $LITE_BUILD_COMMANDS
|
||||
;;
|
||||
report_lite_binary_size)
|
||||
echo $REPORT_LITE_BINARY_SIZE_COMMANDS
|
||||
lite_test)
|
||||
echo $LITE_UNIT_TEST_COMMANDS
|
||||
;;
|
||||
stress_crash)
|
||||
echo $STRESS_CRASH_TEST_COMMANDS
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
# This script enables you running RocksDB tests by running
|
||||
# All the tests concurrently and utilizing all the cores
|
||||
Param(
|
||||
[switch]$EnableJE = $false, # Look for and use test executable, append _je to listed exclusions
|
||||
[switch]$EnableJE = $false, # Look for and use _je executable, append _je to listed exclusions
|
||||
[switch]$RunAll = $false, # Will attempt discover all *_test[_je].exe binaries and run all
|
||||
# of them as Google suites. I.e. It will run test cases concurrently
|
||||
# except those mentioned as $Run, those will run as individual test cases
|
||||
# And any execlued with $ExcludeExes or $ExcludeCases
|
||||
# It will also not run any individual test cases
|
||||
# excluded but $ExcludeCasese
|
||||
[switch]$RunAllExe = $false, # Look for and use test exdcutables, append _je to exclusions automatically
|
||||
# It will attempt to run them in parallel w/o breaking them up on individual
|
||||
# test cases. Those listed with $ExcludeExes will be excluded
|
||||
[string]$SuiteRun = "", # Split test suites in test cases and run in parallel, not compatible with $RunAll
|
||||
[string]$Run = "", # Run specified executables in parallel but do not split to test cases
|
||||
[string]$ExcludeCases = "", # Exclude test cases, expects a comma separated list, no spaces
|
||||
@@ -42,18 +39,13 @@ $RunOnly.Add("compact_on_deletion_collector_test") | Out-Null
|
||||
$RunOnly.Add("merge_test") | Out-Null
|
||||
$RunOnly.Add("stringappend_test") | Out-Null # Apparently incorrectly written
|
||||
$RunOnly.Add("backupable_db_test") | Out-Null # Disabled
|
||||
$RunOnly.Add("timer_queue_test") | Out-Null # Not a gtest
|
||||
|
||||
|
||||
if($RunAll -and $SuiteRun -ne "") {
|
||||
Write-Error "$RunAll and $SuiteRun are not compatible"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if($RunAllExe -and $Run -ne "") {
|
||||
Write-Error "$RunAllExe and $Run are not compatible"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# If running under Appveyor assume that root
|
||||
[string]$Appveyor = $Env:APPVEYOR_BUILD_FOLDER
|
||||
if($Appveyor -ne "") {
|
||||
@@ -139,8 +131,12 @@ function ExtractTestCases([string]$GTestExe, $HashTable) {
|
||||
|
||||
# Leading whitespace is fine
|
||||
$l = $l -replace '^\s+',''
|
||||
# but no whitespace any other place
|
||||
if($l -match "\s+") {
|
||||
continue
|
||||
}
|
||||
# Trailing dot is a test group but no whitespace
|
||||
if ($l -match "\.$" -and $l -notmatch "\s+") {
|
||||
elseif ( $l -match "\.$" ) {
|
||||
$Group = $l
|
||||
} else {
|
||||
# Otherwise it is a test name, remove leading space
|
||||
@@ -227,11 +223,13 @@ $TestExes = [ordered]@{}
|
||||
if($Run -ne "") {
|
||||
|
||||
$test_list = $Run -split ' '
|
||||
|
||||
ForEach($t in $test_list) {
|
||||
|
||||
if($EnableJE) {
|
||||
$t += "_je"
|
||||
}
|
||||
|
||||
MakeAndAdd -token $t -HashTable $TestExes
|
||||
}
|
||||
|
||||
@@ -239,38 +237,6 @@ if($Run -ne "") {
|
||||
Write-Error "Failed to extract tests from $Run"
|
||||
exit 1
|
||||
}
|
||||
} elseif($RunAllExe) {
|
||||
# Discover all the test binaries
|
||||
if($EnableJE) {
|
||||
$pattern = "*_test_je.exe"
|
||||
} else {
|
||||
$pattern = "*_test.exe"
|
||||
}
|
||||
|
||||
$search_path = -join ($BinariesFolder, $pattern)
|
||||
Write-Host "Binaries Search Path: $search_path"
|
||||
|
||||
$DiscoveredExe = @()
|
||||
dir -Path $search_path | ForEach-Object {
|
||||
$DiscoveredExe += ($_.Name)
|
||||
}
|
||||
|
||||
# Remove exclusions
|
||||
ForEach($e in $DiscoveredExe) {
|
||||
$e = $e -replace '.exe$', ''
|
||||
$bare_name = $e -replace '_je$', ''
|
||||
|
||||
if($ExcludeExesSet.Contains($bare_name)) {
|
||||
Write-Warning "Test $e is excluded"
|
||||
continue
|
||||
}
|
||||
MakeAndAdd -token $e -HashTable $TestExes
|
||||
}
|
||||
|
||||
if($TestExes.Count -lt 1) {
|
||||
Write-Error "Failed to discover test executables"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Ordered by exe @{ Exe = @{ TestCase = LogName }}
|
||||
@@ -279,7 +245,9 @@ $CasesToRun = [ordered]@{}
|
||||
if($SuiteRun -ne "") {
|
||||
$suite_list = $SuiteRun -split ' '
|
||||
ProcessSuites -ListOfSuites $suite_list -HashOfHashes $CasesToRun
|
||||
} elseif ($RunAll) {
|
||||
}
|
||||
|
||||
if($RunAll) {
|
||||
# Discover all the test binaries
|
||||
if($EnableJE) {
|
||||
$pattern = "*_test_je.exe"
|
||||
@@ -287,6 +255,7 @@ if($SuiteRun -ne "") {
|
||||
$pattern = "*_test.exe"
|
||||
}
|
||||
|
||||
|
||||
$search_path = -join ($BinariesFolder, $pattern)
|
||||
Write-Host "Binaries Search Path: $search_path"
|
||||
|
||||
@@ -318,6 +287,8 @@ if($SuiteRun -ne "") {
|
||||
}
|
||||
|
||||
|
||||
Write-Host "Attempting to start: $NumTestsToStart tests"
|
||||
|
||||
# Invoke a test with a filter and redirect all output
|
||||
$InvokeTestCase = {
|
||||
param($exe, $test, $log);
|
||||
@@ -336,7 +307,7 @@ $InvokeTestAsync = {
|
||||
# Test limiting factor here
|
||||
[int]$count = 0
|
||||
# Overall status
|
||||
[bool]$script:success = $true;
|
||||
[bool]$success = $true;
|
||||
|
||||
function RunJobs($Suites, $TestCmds, [int]$ConcurrencyVal)
|
||||
{
|
||||
@@ -394,7 +365,6 @@ function RunJobs($Suites, $TestCmds, [int]$ConcurrencyVal)
|
||||
break
|
||||
}
|
||||
|
||||
Write-Host "Starting $exe_name"
|
||||
[string]$Exe = -Join ($BinariesFolder, $exe_name)
|
||||
$job = Start-Job -Name $exe_name -ScriptBlock $InvokeTestAsync -ArgumentList @($Exe,$log_path)
|
||||
$JobToLog.Add($job, $log_path)
|
||||
@@ -425,7 +395,7 @@ function RunJobs($Suites, $TestCmds, [int]$ConcurrencyVal)
|
||||
$log_content = @(Get-Content $log)
|
||||
|
||||
if($completed.State -ne "Completed") {
|
||||
$script:success = $false
|
||||
$success = $false
|
||||
Write-Warning $message
|
||||
$log_content | Write-Warning
|
||||
} else {
|
||||
@@ -449,7 +419,7 @@ function RunJobs($Suites, $TestCmds, [int]$ConcurrencyVal)
|
||||
}
|
||||
|
||||
if(!$pass_found) {
|
||||
$script:success = $false;
|
||||
$success = $false;
|
||||
Write-Warning $message
|
||||
$log_content | Write-Warning
|
||||
} else {
|
||||
@@ -473,7 +443,7 @@ New-TimeSpan -Start $StartDate -End $EndDate |
|
||||
}
|
||||
|
||||
|
||||
if(!$script:success) {
|
||||
if(!$success) {
|
||||
# This does not succeed killing off jobs quick
|
||||
# So we simply exit
|
||||
# Remove-Job -Job $jobs -Force
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
ROCKSDB_VERSION="5.10.3"
|
||||
ZSTD_VERSION="1.1.3"
|
||||
|
||||
echo "This script configures CentOS with everything needed to build and run RocksDB"
|
||||
|
||||
yum update -y && yum install epel-release -y
|
||||
|
||||
yum install -y \
|
||||
wget \
|
||||
gcc-c++ \
|
||||
snappy snappy-devel \
|
||||
zlib zlib-devel \
|
||||
bzip2 bzip2-devel \
|
||||
lz4-devel \
|
||||
libasan \
|
||||
gflags
|
||||
|
||||
mkdir -pv /usr/local/rocksdb-${ROCKSDB_VERSION}
|
||||
ln -sfT /usr/local/rocksdb-${ROCKSDB_VERSION} /usr/local/rocksdb
|
||||
|
||||
wget -qO /tmp/zstd-${ZSTD_VERSION}.tar.gz https://github.com/facebook/zstd/archive/v${ZSTD_VERSION}.tar.gz
|
||||
wget -qO /tmp/rocksdb-${ROCKSDB_VERSION}.tar.gz https://github.com/facebook/rocksdb/archive/v${ROCKSDB_VERSION}.tar.gz
|
||||
|
||||
cd /tmp
|
||||
|
||||
tar xzvf zstd-${ZSTD_VERSION}.tar.gz
|
||||
tar xzvf rocksdb-${ROCKSDB_VERSION}.tar.gz -C /usr/local/
|
||||
|
||||
echo "Installing ZSTD..."
|
||||
pushd zstd-${ZSTD_VERSION}
|
||||
make && make install
|
||||
popd
|
||||
|
||||
echo "Compiling RocksDB..."
|
||||
cd /usr/local/rocksdb
|
||||
chown -R vagrant:vagrant /usr/local/rocksdb/
|
||||
sudo -u vagrant make static_lib
|
||||
cd examples/
|
||||
sudo -u vagrant make all
|
||||
sudo -u vagrant ./c_simple_example
|
||||
@@ -38,7 +38,6 @@ function get_lib_base()
|
||||
# platform is not provided, use latest gcc
|
||||
result=`ls -dr1v $result/gcc-*[^fb]/ | head -n1`
|
||||
else
|
||||
echo $lib_platform
|
||||
result="$result/$lib_platform/"
|
||||
fi
|
||||
|
||||
@@ -72,22 +71,22 @@ log_variable GCC_BASE
|
||||
log_variable CLANG_BASE
|
||||
|
||||
# Libraries locations
|
||||
get_lib_base libgcc 5.x gcc-5-glibc-2.23
|
||||
get_lib_base glibc 2.23 gcc-5-glibc-2.23
|
||||
get_lib_base snappy LATEST gcc-5-glibc-2.23
|
||||
get_lib_base zlib LATEST gcc-5-glibc-2.23
|
||||
get_lib_base bzip2 LATEST gcc-5-glibc-2.23
|
||||
get_lib_base lz4 LATEST gcc-5-glibc-2.23
|
||||
get_lib_base zstd LATEST gcc-5-glibc-2.23
|
||||
get_lib_base gflags LATEST gcc-5-glibc-2.23
|
||||
get_lib_base jemalloc LATEST gcc-5-glibc-2.23
|
||||
get_lib_base numa LATEST gcc-5-glibc-2.23
|
||||
get_lib_base libunwind LATEST gcc-5-glibc-2.23
|
||||
get_lib_base tbb LATEST gcc-5-glibc-2.23
|
||||
get_lib_base libgcc 5.x
|
||||
get_lib_base glibc 2.23
|
||||
get_lib_base snappy LATEST gcc-5-glibc-2.23
|
||||
get_lib_base zlib LATEST
|
||||
get_lib_base bzip2 LATEST
|
||||
get_lib_base lz4 LATEST
|
||||
get_lib_base zstd LATEST
|
||||
get_lib_base gflags LATEST
|
||||
get_lib_base jemalloc LATEST
|
||||
get_lib_base numa LATEST
|
||||
get_lib_base libunwind LATEST
|
||||
get_lib_base tbb 4.0_update2 gcc-5-glibc-2.23
|
||||
|
||||
get_lib_base kernel-headers 4.0.9-36_fbk5_2933_gd092e3f gcc-5-glibc-2.23
|
||||
get_lib_base kernel-headers LATEST
|
||||
get_lib_base binutils LATEST centos6-native
|
||||
get_lib_base valgrind LATEST gcc-5-glibc-2.23
|
||||
get_lib_base valgrind 3.10.0 gcc-5-glibc-2.23
|
||||
get_lib_base lua 5.2.3 gcc-5-glibc-2.23
|
||||
|
||||
git diff $OUTPUT
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
if [ "$#" = "0" ]; then
|
||||
echo "Usage: $0 major|minor|patch|full"
|
||||
exit 1
|
||||
|
||||
Vendored
+5
-5
@@ -17,16 +17,16 @@ int main() {
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/gflags_compat.h"
|
||||
#include "port/port.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "util/random.h"
|
||||
|
||||
using GFLAGS_NAMESPACE::ParseCommandLineFlags;
|
||||
using GFLAGS::ParseCommandLineFlags;
|
||||
|
||||
static const uint32_t KB = 1024;
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace rocksdb {
|
||||
|
||||
class CacheBench;
|
||||
namespace {
|
||||
void deleter(const Slice& /*key*/, void* value) {
|
||||
void deleter(const Slice& key, void* value) {
|
||||
delete reinterpret_cast<char *>(value);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -40,9 +40,9 @@ static int DecodeValue(void* v) {
|
||||
const std::string kLRU = "lru";
|
||||
const std::string kClock = "clock";
|
||||
|
||||
void dumbDeleter(const Slice& /*key*/, void* /*value*/) {}
|
||||
void dumbDeleter(const Slice& key, void* value) {}
|
||||
|
||||
void eraseDeleter(const Slice& /*key*/, void* value) {
|
||||
void eraseDeleter(const Slice& key, void* value) {
|
||||
Cache* cache = reinterpret_cast<Cache*>(value);
|
||||
cache->Erase("foo");
|
||||
}
|
||||
@@ -470,7 +470,7 @@ class Value {
|
||||
};
|
||||
|
||||
namespace {
|
||||
void deleter(const Slice& /*key*/, void* value) {
|
||||
void deleter(const Slice& key, void* value) {
|
||||
delete static_cast<Value *>(value);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Vendored
+4
-11
@@ -13,8 +13,8 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
std::shared_ptr<Cache> NewClockCache(size_t /*capacity*/, int /*num_shard_bits*/,
|
||||
bool /*strict_capacity_limit*/) {
|
||||
std::shared_ptr<Cache> NewClockCache(size_t capacity, int num_shard_bits,
|
||||
bool strict_capacity_limit) {
|
||||
// Clock cache not supported.
|
||||
return nullptr;
|
||||
}
|
||||
@@ -27,11 +27,6 @@ std::shared_ptr<Cache> NewClockCache(size_t /*capacity*/, int /*num_shard_bits*/
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
|
||||
// "tbb/concurrent_hash_map.h" requires RTTI if exception is enabled.
|
||||
// Disable it so users can chooose to disable RTTI.
|
||||
#ifndef ROCKSDB_USE_RTTI
|
||||
#define TBB_USE_EXCEPTIONS 0
|
||||
#endif
|
||||
#include "tbb/concurrent_hash_map.h"
|
||||
|
||||
#include "cache/sharded_cache.h"
|
||||
@@ -367,9 +362,7 @@ ClockCacheShard::~ClockCacheShard() {
|
||||
for (auto& handle : list_) {
|
||||
uint32_t flags = handle.flags.load(std::memory_order_relaxed);
|
||||
if (InCache(flags) || CountRefs(flags) > 0) {
|
||||
if (handle.deleter != nullptr) {
|
||||
(*handle.deleter)(handle.key, handle.value);
|
||||
}
|
||||
(*handle.deleter)(handle.key, handle.value);
|
||||
delete[] handle.key.data();
|
||||
}
|
||||
}
|
||||
@@ -588,7 +581,7 @@ Status ClockCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
|
||||
size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value),
|
||||
Cache::Handle** out_handle,
|
||||
Cache::Priority /*priority*/) {
|
||||
Cache::Priority priority) {
|
||||
CleanupContext context;
|
||||
HashTable::accessor accessor;
|
||||
char* key_data = new char[key.size()];
|
||||
|
||||
Vendored
+11
-80
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
LRUHandleTable::LRUHandleTable() : list_(nullptr), length_(0), elems_(0) {
|
||||
LRUHandleTable::LRUHandleTable() : length_(0), elems_(0), list_(nullptr) {
|
||||
Resize();
|
||||
}
|
||||
|
||||
@@ -99,20 +99,12 @@ void LRUHandleTable::Resize() {
|
||||
length_ = new_length;
|
||||
}
|
||||
|
||||
LRUCacheShard::LRUCacheShard(size_t capacity, bool strict_capacity_limit,
|
||||
double high_pri_pool_ratio)
|
||||
: capacity_(0),
|
||||
high_pri_pool_usage_(0),
|
||||
strict_capacity_limit_(strict_capacity_limit),
|
||||
high_pri_pool_ratio_(high_pri_pool_ratio),
|
||||
high_pri_pool_capacity_(0),
|
||||
usage_(0),
|
||||
lru_usage_(0) {
|
||||
LRUCacheShard::LRUCacheShard()
|
||||
: usage_(0), lru_usage_(0), high_pri_pool_usage_(0) {
|
||||
// Make empty circular linked list
|
||||
lru_.next = &lru_;
|
||||
lru_.prev = &lru_;
|
||||
lru_low_pri_ = &lru_;
|
||||
SetCapacity(capacity);
|
||||
}
|
||||
|
||||
LRUCacheShard::~LRUCacheShard() {}
|
||||
@@ -165,21 +157,6 @@ void LRUCacheShard::TEST_GetLRUList(LRUHandle** lru, LRUHandle** lru_low_pri) {
|
||||
*lru_low_pri = lru_low_pri_;
|
||||
}
|
||||
|
||||
size_t LRUCacheShard::TEST_GetLRUSize() {
|
||||
LRUHandle* lru_handle = lru_.next;
|
||||
size_t lru_size = 0;
|
||||
while (lru_handle != &lru_) {
|
||||
lru_size++;
|
||||
lru_handle = lru_handle->next;
|
||||
}
|
||||
return lru_size;
|
||||
}
|
||||
|
||||
double LRUCacheShard::GetHighPriPoolRatio() {
|
||||
MutexLock l(&mutex_);
|
||||
return high_pri_pool_ratio_;
|
||||
}
|
||||
|
||||
void LRUCacheShard::LRU_Remove(LRUHandle* e) {
|
||||
assert(e->next != nullptr);
|
||||
assert(e->prev != nullptr);
|
||||
@@ -246,18 +223,6 @@ void LRUCacheShard::EvictFromLRU(size_t charge,
|
||||
}
|
||||
}
|
||||
|
||||
void* LRUCacheShard::operator new(size_t size) {
|
||||
return port::cacheline_aligned_alloc(size);
|
||||
}
|
||||
|
||||
void* LRUCacheShard::operator new(size_t /*size*/, void* ptr) { return ptr; }
|
||||
|
||||
void LRUCacheShard::operator delete(void *memblock) {
|
||||
port::cacheline_aligned_free(memblock);
|
||||
}
|
||||
|
||||
void LRUCacheShard::operator delete(void* /*memblock*/, void* /*ptr*/) {}
|
||||
|
||||
void LRUCacheShard::SetCapacity(size_t capacity) {
|
||||
autovector<LRUHandle*> last_reference_list;
|
||||
{
|
||||
@@ -362,7 +327,6 @@ Status LRUCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
|
||||
e->deleter = deleter;
|
||||
e->charge = charge;
|
||||
e->key_length = key.size();
|
||||
e->flags = 0;
|
||||
e->hash = hash;
|
||||
e->refs = (handle == nullptr
|
||||
? 1
|
||||
@@ -474,22 +438,16 @@ std::string LRUCacheShard::GetPrintableOptions() const {
|
||||
LRUCache::LRUCache(size_t capacity, int num_shard_bits,
|
||||
bool strict_capacity_limit, double high_pri_pool_ratio)
|
||||
: ShardedCache(capacity, num_shard_bits, strict_capacity_limit) {
|
||||
num_shards_ = 1 << num_shard_bits;
|
||||
shards_ = reinterpret_cast<LRUCacheShard*>(
|
||||
port::cacheline_aligned_alloc(sizeof(LRUCacheShard) * num_shards_));
|
||||
size_t per_shard = (capacity + (num_shards_ - 1)) / num_shards_;
|
||||
for (int i = 0; i < num_shards_; i++) {
|
||||
new (&shards_[i])
|
||||
LRUCacheShard(per_shard, strict_capacity_limit, high_pri_pool_ratio);
|
||||
int num_shards = 1 << num_shard_bits;
|
||||
shards_ = new LRUCacheShard[num_shards];
|
||||
SetCapacity(capacity);
|
||||
SetStrictCapacityLimit(strict_capacity_limit);
|
||||
for (int i = 0; i < num_shards; i++) {
|
||||
shards_[i].SetHighPriorityPoolRatio(high_pri_pool_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
LRUCache::~LRUCache() {
|
||||
for (int i = 0; i < num_shards_; i++) {
|
||||
shards_[i].~LRUCacheShard();
|
||||
}
|
||||
port::cacheline_aligned_free(shards_);
|
||||
}
|
||||
LRUCache::~LRUCache() { delete[] shards_; }
|
||||
|
||||
CacheShard* LRUCache::GetShard(int shard) {
|
||||
return reinterpret_cast<CacheShard*>(&shards_[shard]);
|
||||
@@ -511,34 +469,7 @@ uint32_t LRUCache::GetHash(Handle* handle) const {
|
||||
return reinterpret_cast<const LRUHandle*>(handle)->hash;
|
||||
}
|
||||
|
||||
void LRUCache::DisownData() {
|
||||
// Do not drop data if compile with ASAN to suppress leak warning.
|
||||
#ifndef __SANITIZE_ADDRESS__
|
||||
shards_ = nullptr;
|
||||
#endif // !__SANITIZE_ADDRESS__
|
||||
}
|
||||
|
||||
size_t LRUCache::TEST_GetLRUSize() {
|
||||
size_t lru_size_of_all_shards = 0;
|
||||
for (int i = 0; i < num_shards_; i++) {
|
||||
lru_size_of_all_shards += shards_[i].TEST_GetLRUSize();
|
||||
}
|
||||
return lru_size_of_all_shards;
|
||||
}
|
||||
|
||||
double LRUCache::GetHighPriPoolRatio() {
|
||||
double result = 0.0;
|
||||
if (num_shards_ > 0) {
|
||||
result = shards_[0].GetHighPriPoolRatio();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Cache> NewLRUCache(const LRUCacheOptions& cache_opts) {
|
||||
return NewLRUCache(cache_opts.capacity, cache_opts.num_shard_bits,
|
||||
cache_opts.strict_capacity_limit,
|
||||
cache_opts.high_pri_pool_ratio);
|
||||
}
|
||||
void LRUCache::DisownData() { shards_ = nullptr; }
|
||||
|
||||
std::shared_ptr<Cache> NewLRUCache(size_t capacity, int num_shard_bits,
|
||||
bool strict_capacity_limit,
|
||||
|
||||
Vendored
+15
-52
@@ -57,7 +57,7 @@ struct LRUHandle {
|
||||
// Include the following flags:
|
||||
// in_cache: whether this entry is referenced by the hash table.
|
||||
// is_high_pri: whether this entry is high priority entry.
|
||||
// in_high_pri_pool: whether this entry is in high-pri pool.
|
||||
// in_high_pro_pool: whether this entry is in high-pri pool.
|
||||
char flags;
|
||||
|
||||
uint32_t hash; // Hash of key(); used for fast sharding and comparisons
|
||||
@@ -148,16 +148,15 @@ class LRUHandleTable {
|
||||
|
||||
// The table consists of an array of buckets where each bucket is
|
||||
// a linked list of cache entries that hash into the bucket.
|
||||
LRUHandle** list_;
|
||||
uint32_t length_;
|
||||
uint32_t elems_;
|
||||
LRUHandle** list_;
|
||||
};
|
||||
|
||||
// A single shard of sharded cache.
|
||||
class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
|
||||
class LRUCacheShard : public CacheShard {
|
||||
public:
|
||||
LRUCacheShard(size_t capacity, bool strict_capacity_limit,
|
||||
double high_pri_pool_ratio);
|
||||
LRUCacheShard();
|
||||
virtual ~LRUCacheShard();
|
||||
|
||||
// Separate from constructor so caller can easily make an array of LRUCache
|
||||
@@ -199,25 +198,6 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
|
||||
|
||||
void TEST_GetLRUList(LRUHandle** lru, LRUHandle** lru_low_pri);
|
||||
|
||||
// Retrieves number of elements in LRU, for unit test purpose only
|
||||
// not threadsafe
|
||||
size_t TEST_GetLRUSize();
|
||||
|
||||
// Retrives high pri pool ratio
|
||||
double GetHighPriPoolRatio();
|
||||
|
||||
// Overloading to aligned it to cache line size
|
||||
// They are used by tests.
|
||||
void* operator new(size_t);
|
||||
|
||||
// placement new
|
||||
void* operator new(size_t, void*);
|
||||
|
||||
void operator delete(void *);
|
||||
|
||||
// placement delete, does nothing.
|
||||
void operator delete(void*, void*);
|
||||
|
||||
private:
|
||||
void LRU_Remove(LRUHandle* e);
|
||||
void LRU_Insert(LRUHandle* e);
|
||||
@@ -239,6 +219,12 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
|
||||
// Initialized before use.
|
||||
size_t capacity_;
|
||||
|
||||
// Memory size for entries residing in the cache
|
||||
size_t usage_;
|
||||
|
||||
// Memory size for entries residing only in the LRU list
|
||||
size_t lru_usage_;
|
||||
|
||||
// Memory size for entries in high-pri pool.
|
||||
size_t high_pri_pool_usage_;
|
||||
|
||||
@@ -252,6 +238,11 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
|
||||
// Remember the value to avoid recomputing each time.
|
||||
double high_pri_pool_capacity_;
|
||||
|
||||
// mutex_ protects the following state.
|
||||
// We don't count mutex_ as the cache's internal state so semantically we
|
||||
// don't mind mutex_ invoking the non-const actions.
|
||||
mutable port::Mutex mutex_;
|
||||
|
||||
// Dummy head of LRU list.
|
||||
// lru.prev is newest entry, lru.next is oldest entry.
|
||||
// LRU contains items which can be evicted, ie reference only by cache
|
||||
@@ -260,29 +251,7 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
|
||||
// Pointer to head of low-pri pool in LRU list.
|
||||
LRUHandle* lru_low_pri_;
|
||||
|
||||
// ------------^^^^^^^^^^^^^-----------
|
||||
// Not frequently modified data members
|
||||
// ------------------------------------
|
||||
//
|
||||
// We separate data members that are updated frequently from the ones that
|
||||
// are not frequently updated so that they don't share the same cache line
|
||||
// which will lead into false cache sharing
|
||||
//
|
||||
// ------------------------------------
|
||||
// Frequently modified data members
|
||||
// ------------vvvvvvvvvvvvv-----------
|
||||
LRUHandleTable table_;
|
||||
|
||||
// Memory size for entries residing in the cache
|
||||
size_t usage_;
|
||||
|
||||
// Memory size for entries residing only in the LRU list
|
||||
size_t lru_usage_;
|
||||
|
||||
// mutex_ protects the following state.
|
||||
// We don't count mutex_ as the cache's internal state so semantically we
|
||||
// don't mind mutex_ invoking the non-const actions.
|
||||
mutable port::Mutex mutex_;
|
||||
};
|
||||
|
||||
class LRUCache : public ShardedCache {
|
||||
@@ -298,14 +267,8 @@ class LRUCache : public ShardedCache {
|
||||
virtual uint32_t GetHash(Handle* handle) const override;
|
||||
virtual void DisownData() override;
|
||||
|
||||
// Retrieves number of elements in LRU, for unit test purpose only
|
||||
size_t TEST_GetLRUSize();
|
||||
// Retrives high pri pool ratio
|
||||
double GetHighPriPoolRatio();
|
||||
|
||||
private:
|
||||
LRUCacheShard* shards_;
|
||||
int num_shards_ = 0;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
Vendored
+5
-4
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "port/port.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace rocksdb {
|
||||
@@ -18,8 +17,10 @@ class LRUCacheTest : public testing::Test {
|
||||
~LRUCacheTest() {}
|
||||
|
||||
void NewCache(size_t capacity, double high_pri_pool_ratio = 0.0) {
|
||||
cache_.reset(new LRUCacheShard(capacity, false /*strict_capcity_limit*/,
|
||||
high_pri_pool_ratio));
|
||||
cache_.reset(new LRUCacheShard());
|
||||
cache_->SetCapacity(capacity);
|
||||
cache_->SetStrictCapacityLimit(false);
|
||||
cache_->SetHighPriorityPoolRatio(high_pri_pool_ratio);
|
||||
}
|
||||
|
||||
void Insert(const std::string& key,
|
||||
@@ -104,7 +105,7 @@ TEST_F(LRUCacheTest, BasicLRU) {
|
||||
ValidateLRUList({"e", "z", "d", "u", "v"});
|
||||
}
|
||||
|
||||
TEST_F(LRUCacheTest, EntriesWithPriority) {
|
||||
TEST_F(LRUCacheTest, MidPointInsertion) {
|
||||
// Allocate 2 cache entries to high-pri pool.
|
||||
NewCache(5, 0.45);
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -53,7 +53,7 @@ Status ShardedCache::Insert(const Slice& key, void* value, size_t charge,
|
||||
->Insert(key, hash, value, charge, deleter, handle, priority);
|
||||
}
|
||||
|
||||
Cache::Handle* ShardedCache::Lookup(const Slice& key, Statistics* /*stats*/) {
|
||||
Cache::Handle* ShardedCache::Lookup(const Slice& key, Statistics* stats) {
|
||||
uint32_t hash = HashSlice(key);
|
||||
return GetShard(Shard(hash))->Lookup(key, hash);
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/RocksDBTargets.cmake")
|
||||
check_required_components(RocksDB)
|
||||
@@ -1,21 +0,0 @@
|
||||
# - Find NUMA
|
||||
# Find the NUMA library and includes
|
||||
#
|
||||
# NUMA_INCLUDE_DIR - where to find numa.h, etc.
|
||||
# NUMA_LIBRARIES - List of libraries when using NUMA.
|
||||
# NUMA_FOUND - True if NUMA found.
|
||||
|
||||
find_path(NUMA_INCLUDE_DIR
|
||||
NAMES numa.h numaif.h
|
||||
HINTS ${NUMA_ROOT_DIR}/include)
|
||||
|
||||
find_library(NUMA_LIBRARIES
|
||||
NAMES numa
|
||||
HINTS ${NUMA_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(NUMA DEFAULT_MSG NUMA_LIBRARIES NUMA_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
NUMA_LIBRARIES
|
||||
NUMA_INCLUDE_DIR)
|
||||
@@ -1,25 +0,0 @@
|
||||
# - Find TBB
|
||||
# Find the Thread Building Blocks library and includes
|
||||
#
|
||||
# TBB_INCLUDE_DIR - where to find tbb.h, etc.
|
||||
# TBB_LIBRARIES - List of libraries when using TBB.
|
||||
# TBB_FOUND - True if TBB found.
|
||||
|
||||
if(NOT DEFINED TBB_ROOT_DIR)
|
||||
set(TBB_ROOT_DIR "$ENV{TBBROOT}")
|
||||
endif()
|
||||
|
||||
find_path(TBB_INCLUDE_DIR
|
||||
NAMES tbb/tbb.h
|
||||
HINTS ${TBB_ROOT_DIR}/include)
|
||||
|
||||
find_library(TBB_LIBRARIES
|
||||
NAMES tbb
|
||||
HINTS ${TBB_ROOT_DIR}/lib ENV LIBRARY_PATH)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(TBB DEFAULT_MSG TBB_LIBRARIES TBB_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
TBB_LIBRARIES
|
||||
TBB_INCLUDE_DIR)
|
||||
@@ -1,21 +0,0 @@
|
||||
# - Find Bzip2
|
||||
# Find the bzip2 compression library and includes
|
||||
#
|
||||
# BZIP2_INCLUDE_DIR - where to find bzlib.h, etc.
|
||||
# BZIP2_LIBRARIES - List of libraries when using bzip2.
|
||||
# BZIP2_FOUND - True if bzip2 found.
|
||||
|
||||
find_path(BZIP2_INCLUDE_DIR
|
||||
NAMES bzlib.h
|
||||
HINTS ${BZIP2_ROOT_DIR}/include)
|
||||
|
||||
find_library(BZIP2_LIBRARIES
|
||||
NAMES bz2
|
||||
HINTS ${BZIP2_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(bzip2 DEFAULT_MSG BZIP2_LIBRARIES BZIP2_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
BZIP2_LIBRARIES
|
||||
BZIP2_INCLUDE_DIR)
|
||||
@@ -1,21 +0,0 @@
|
||||
# - Find Lz4
|
||||
# Find the lz4 compression library and includes
|
||||
#
|
||||
# LZ4_INCLUDE_DIR - where to find lz4.h, etc.
|
||||
# LZ4_LIBRARIES - List of libraries when using lz4.
|
||||
# LZ4_FOUND - True if lz4 found.
|
||||
|
||||
find_path(LZ4_INCLUDE_DIR
|
||||
NAMES lz4.h
|
||||
HINTS ${LZ4_ROOT_DIR}/include)
|
||||
|
||||
find_library(LZ4_LIBRARIES
|
||||
NAMES lz4
|
||||
HINTS ${LZ4_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(lz4 DEFAULT_MSG LZ4_LIBRARIES LZ4_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
LZ4_LIBRARIES
|
||||
LZ4_INCLUDE_DIR)
|
||||
@@ -1,21 +0,0 @@
|
||||
# - Find zlib
|
||||
# Find the zlib compression library and includes
|
||||
#
|
||||
# ZLIB_INCLUDE_DIR - where to find zlib.h, etc.
|
||||
# ZLIB_LIBRARIES - List of libraries when using zlib.
|
||||
# ZLIB_FOUND - True if zlib found.
|
||||
|
||||
find_path(ZLIB_INCLUDE_DIR
|
||||
NAMES zlib.h
|
||||
HINTS ${ZLIB_ROOT_DIR}/include)
|
||||
|
||||
find_library(ZLIB_LIBRARIES
|
||||
NAMES z
|
||||
HINTS ${ZLIB_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(zlib DEFAULT_MSG ZLIB_LIBRARIES ZLIB_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
ZLIB_LIBRARIES
|
||||
ZLIB_INCLUDE_DIR)
|
||||
@@ -1,21 +0,0 @@
|
||||
# - Find zstd
|
||||
# Find the zstd compression library and includes
|
||||
#
|
||||
# ZSTD_INCLUDE_DIR - where to find zstd.h, etc.
|
||||
# ZSTD_LIBRARIES - List of libraries when using zstd.
|
||||
# ZSTD_FOUND - True if zstd found.
|
||||
|
||||
find_path(ZSTD_INCLUDE_DIR
|
||||
NAMES zstd.h
|
||||
HINTS ${ZSTD_ROOT_DIR}/include)
|
||||
|
||||
find_library(ZSTD_LIBRARIES
|
||||
NAMES zstd
|
||||
HINTS ${ZSTD_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(zstd DEFAULT_MSG ZSTD_LIBRARIES ZSTD_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
ZSTD_LIBRARIES
|
||||
ZSTD_INCLUDE_DIR)
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error.
|
||||
set -e
|
||||
|
||||
@@ -72,7 +72,7 @@ def display_file_coverage(per_file_coverage, total_coverage):
|
||||
header_template = \
|
||||
"%" + str(max_file_name_length) + "s\t%s\t%s"
|
||||
separator = "-" * (max_file_name_length + 10 + 20)
|
||||
print header_template % ("Filename", "Coverage", "Lines") # noqa: E999 T25377293 Grandfathered in
|
||||
print header_template % ("Filename", "Coverage", "Lines")
|
||||
print separator
|
||||
|
||||
# -- Print body
|
||||
|
||||
+16
-20
@@ -39,7 +39,7 @@ namespace rocksdb {
|
||||
class TableFactory;
|
||||
|
||||
TableBuilder* NewTableBuilder(
|
||||
const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
|
||||
const ImmutableCFOptions& ioptions,
|
||||
const InternalKeyComparator& internal_comparator,
|
||||
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
|
||||
int_tbl_prop_collector_factories,
|
||||
@@ -47,16 +47,15 @@ TableBuilder* NewTableBuilder(
|
||||
WritableFileWriter* file, const CompressionType compression_type,
|
||||
const CompressionOptions& compression_opts, int level,
|
||||
const std::string* compression_dict, const bool skip_filters,
|
||||
const uint64_t creation_time, const uint64_t oldest_key_time) {
|
||||
const uint64_t creation_time) {
|
||||
assert((column_family_id ==
|
||||
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
|
||||
column_family_name.empty());
|
||||
return ioptions.table_factory->NewTableBuilder(
|
||||
TableBuilderOptions(ioptions, moptions, internal_comparator,
|
||||
TableBuilderOptions(ioptions, internal_comparator,
|
||||
int_tbl_prop_collector_factories, compression_type,
|
||||
compression_opts, compression_dict, skip_filters,
|
||||
column_family_name, level, creation_time,
|
||||
oldest_key_time),
|
||||
column_family_name, level, creation_time),
|
||||
column_family_id, file);
|
||||
}
|
||||
|
||||
@@ -71,12 +70,12 @@ Status BuildTable(
|
||||
uint32_t column_family_id, const std::string& column_family_name,
|
||||
std::vector<SequenceNumber> snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
SnapshotChecker* snapshot_checker, const CompressionType compression,
|
||||
const CompressionType compression,
|
||||
const CompressionOptions& compression_opts, bool paranoid_file_checks,
|
||||
InternalStats* internal_stats, TableFileCreationReason reason,
|
||||
EventLogger* event_logger, int job_id, const Env::IOPriority io_priority,
|
||||
TableProperties* table_properties, int level, const uint64_t creation_time,
|
||||
const uint64_t oldest_key_time, Env::WriteLifeTimeHint write_hint) {
|
||||
TableProperties* table_properties, int level,
|
||||
const uint64_t creation_time) {
|
||||
assert((column_family_id ==
|
||||
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
|
||||
column_family_name.empty());
|
||||
@@ -93,7 +92,7 @@ Status BuildTable(
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string fname = TableFileName(ioptions.cf_paths, meta->fd.GetNumber(),
|
||||
std::string fname = TableFileName(ioptions.db_paths, meta->fd.GetNumber(),
|
||||
meta->fd.GetPathId());
|
||||
#ifndef ROCKSDB_LITE
|
||||
EventHelpers::NotifyTableFileCreationStarted(
|
||||
@@ -118,27 +117,25 @@ Status BuildTable(
|
||||
return s;
|
||||
}
|
||||
file->SetIOPriority(io_priority);
|
||||
file->SetWriteLifeTimeHint(write_hint);
|
||||
|
||||
file_writer.reset(new WritableFileWriter(std::move(file), env_options,
|
||||
ioptions.statistics));
|
||||
|
||||
builder = NewTableBuilder(
|
||||
ioptions, mutable_cf_options, internal_comparator,
|
||||
int_tbl_prop_collector_factories, column_family_id,
|
||||
column_family_name, file_writer.get(), compression, compression_opts,
|
||||
level, nullptr /* compression_dict */, false /* skip_filters */,
|
||||
creation_time, oldest_key_time);
|
||||
ioptions, internal_comparator, int_tbl_prop_collector_factories,
|
||||
column_family_id, column_family_name, file_writer.get(), compression,
|
||||
compression_opts, level, nullptr /* compression_dict */,
|
||||
false /* skip_filters */, creation_time);
|
||||
}
|
||||
|
||||
MergeHelper merge(env, internal_comparator.user_comparator(),
|
||||
ioptions.merge_operator, nullptr, ioptions.info_log,
|
||||
true /* internal key corruption is not ok */,
|
||||
snapshots.empty() ? 0 : snapshots.back(),
|
||||
snapshot_checker);
|
||||
snapshots.empty() ? 0 : snapshots.back());
|
||||
|
||||
CompactionIterator c_iter(
|
||||
iter, internal_comparator.user_comparator(), &merge, kMaxSequenceNumber,
|
||||
&snapshots, earliest_write_conflict_snapshot, snapshot_checker, env,
|
||||
&snapshots, earliest_write_conflict_snapshot, env,
|
||||
true /* internal key corruption is not ok */, range_del_agg.get());
|
||||
c_iter.SeekToFirst();
|
||||
for (; c_iter.Valid(); c_iter.Next()) {
|
||||
@@ -197,8 +194,7 @@ Status BuildTable(
|
||||
// to cache it here for further user reads
|
||||
std::unique_ptr<InternalIterator> it(table_cache->NewIterator(
|
||||
ReadOptions(), env_options, internal_comparator, meta->fd,
|
||||
nullptr /* range_del_agg */,
|
||||
mutable_cf_options.prefix_extractor.get(), nullptr,
|
||||
nullptr /* range_del_agg */, nullptr,
|
||||
(internal_stats == nullptr) ? nullptr
|
||||
: internal_stats->GetFileReadHist(0),
|
||||
false /* for_compaction */, nullptr /* arena */,
|
||||
|
||||
+4
-7
@@ -29,7 +29,6 @@ struct FileMetaData;
|
||||
class Env;
|
||||
struct EnvOptions;
|
||||
class Iterator;
|
||||
class SnapshotChecker;
|
||||
class TableCache;
|
||||
class VersionEdit;
|
||||
class TableBuilder;
|
||||
@@ -43,7 +42,7 @@ class InternalIterator;
|
||||
// @param compression_dict Data for presetting the compression library's
|
||||
// dictionary, or nullptr.
|
||||
TableBuilder* NewTableBuilder(
|
||||
const ImmutableCFOptions& options, const MutableCFOptions& moptions,
|
||||
const ImmutableCFOptions& options,
|
||||
const InternalKeyComparator& internal_comparator,
|
||||
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
|
||||
int_tbl_prop_collector_factories,
|
||||
@@ -51,8 +50,7 @@ TableBuilder* NewTableBuilder(
|
||||
WritableFileWriter* file, const CompressionType compression_type,
|
||||
const CompressionOptions& compression_opts, int level,
|
||||
const std::string* compression_dict = nullptr,
|
||||
const bool skip_filters = false, const uint64_t creation_time = 0,
|
||||
const uint64_t oldest_key_time = 0);
|
||||
const bool skip_filters = false, const uint64_t creation_time = 0);
|
||||
|
||||
// Build a Table file from the contents of *iter. The generated file
|
||||
// will be named according to number specified in meta. On success, the rest of
|
||||
@@ -73,13 +71,12 @@ extern Status BuildTable(
|
||||
uint32_t column_family_id, const std::string& column_family_name,
|
||||
std::vector<SequenceNumber> snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
SnapshotChecker* snapshot_checker, const CompressionType compression,
|
||||
const CompressionType compression,
|
||||
const CompressionOptions& compression_opts, bool paranoid_file_checks,
|
||||
InternalStats* internal_stats, TableFileCreationReason reason,
|
||||
EventLogger* event_logger = nullptr, int job_id = 0,
|
||||
const Env::IOPriority io_priority = Env::IO_HIGH,
|
||||
TableProperties* table_properties = nullptr, int level = -1,
|
||||
const uint64_t creation_time = 0, const uint64_t oldest_key_time = 0,
|
||||
Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET);
|
||||
const uint64_t creation_time = 0);
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
+7
-244
@@ -41,7 +41,6 @@ static char dbname[200];
|
||||
static char sstfilename[200];
|
||||
static char dbbackupname[200];
|
||||
static char dbcheckpointname[200];
|
||||
static char dbpathname[200];
|
||||
|
||||
static void StartPhase(const char* name) {
|
||||
fprintf(stderr, "=== Test %s\n", name);
|
||||
@@ -192,11 +191,10 @@ static void CheckDel(void* ptr, const char* k, size_t klen) {
|
||||
(*state)++;
|
||||
}
|
||||
|
||||
static void CmpDestroy(void* arg) { (void)arg; }
|
||||
static void CmpDestroy(void* arg) { }
|
||||
|
||||
static int CmpCompare(void* arg, const char* a, size_t alen,
|
||||
const char* b, size_t blen) {
|
||||
(void)arg;
|
||||
size_t n = (alen < blen) ? alen : blen;
|
||||
int r = memcmp(a, b, n);
|
||||
if (r == 0) {
|
||||
@@ -207,15 +205,13 @@ static int CmpCompare(void* arg, const char* a, size_t alen,
|
||||
}
|
||||
|
||||
static const char* CmpName(void* arg) {
|
||||
(void)arg;
|
||||
return "foo";
|
||||
}
|
||||
|
||||
// Custom filter policy
|
||||
static unsigned char fake_filter_result = 1;
|
||||
static void FilterDestroy(void* arg) { (void)arg; }
|
||||
static void FilterDestroy(void* arg) { }
|
||||
static const char* FilterName(void* arg) {
|
||||
(void)arg;
|
||||
return "TestFilter";
|
||||
}
|
||||
static char* FilterCreate(
|
||||
@@ -223,10 +219,6 @@ static char* FilterCreate(
|
||||
const char* const* key_array, const size_t* key_length_array,
|
||||
int num_keys,
|
||||
size_t* filter_length) {
|
||||
(void)arg;
|
||||
(void)key_array;
|
||||
(void)key_length_array;
|
||||
(void)num_keys;
|
||||
*filter_length = 4;
|
||||
char* result = malloc(4);
|
||||
memcpy(result, "fake", 4);
|
||||
@@ -236,30 +228,20 @@ static unsigned char FilterKeyMatch(
|
||||
void* arg,
|
||||
const char* key, size_t length,
|
||||
const char* filter, size_t filter_length) {
|
||||
(void)arg;
|
||||
(void)key;
|
||||
(void)length;
|
||||
CheckCondition(filter_length == 4);
|
||||
CheckCondition(memcmp(filter, "fake", 4) == 0);
|
||||
return fake_filter_result;
|
||||
}
|
||||
|
||||
// Custom compaction filter
|
||||
static void CFilterDestroy(void* arg) { (void)arg; }
|
||||
static const char* CFilterName(void* arg) {
|
||||
(void)arg;
|
||||
return "foo";
|
||||
}
|
||||
static void CFilterDestroy(void* arg) {}
|
||||
static const char* CFilterName(void* arg) { return "foo"; }
|
||||
static unsigned char CFilterFilter(void* arg, int level, const char* key,
|
||||
size_t key_length,
|
||||
const char* existing_value,
|
||||
size_t value_length, char** new_value,
|
||||
size_t* new_value_length,
|
||||
unsigned char* value_changed) {
|
||||
(void)arg;
|
||||
(void)level;
|
||||
(void)existing_value;
|
||||
(void)value_length;
|
||||
if (key_length == 3) {
|
||||
if (memcmp(key, "bar", key_length) == 0) {
|
||||
return 1;
|
||||
@@ -273,15 +255,10 @@ static unsigned char CFilterFilter(void* arg, int level, const char* key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CFilterFactoryDestroy(void* arg) { (void)arg; }
|
||||
static const char* CFilterFactoryName(void* arg) {
|
||||
(void)arg;
|
||||
return "foo";
|
||||
}
|
||||
static void CFilterFactoryDestroy(void* arg) {}
|
||||
static const char* CFilterFactoryName(void* arg) { return "foo"; }
|
||||
static rocksdb_compactionfilter_t* CFilterCreate(
|
||||
void* arg, rocksdb_compactionfiltercontext_t* context) {
|
||||
(void)arg;
|
||||
(void)context;
|
||||
return rocksdb_compactionfilter_create(NULL, CFilterDestroy, CFilterFilter,
|
||||
CFilterName);
|
||||
}
|
||||
@@ -312,9 +289,8 @@ static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options,
|
||||
}
|
||||
|
||||
// Custom merge operator
|
||||
static void MergeOperatorDestroy(void* arg) { (void)arg; }
|
||||
static void MergeOperatorDestroy(void* arg) { }
|
||||
static const char* MergeOperatorName(void* arg) {
|
||||
(void)arg;
|
||||
return "TestMergeOperator";
|
||||
}
|
||||
static char* MergeOperatorFullMerge(
|
||||
@@ -324,14 +300,6 @@ static char* MergeOperatorFullMerge(
|
||||
const char* const* operands_list, const size_t* operands_list_length,
|
||||
int num_operands,
|
||||
unsigned char* success, size_t* new_value_length) {
|
||||
(void)arg;
|
||||
(void)key;
|
||||
(void)key_length;
|
||||
(void)existing_value;
|
||||
(void)existing_value_length;
|
||||
(void)operands_list;
|
||||
(void)operands_list_length;
|
||||
(void)num_operands;
|
||||
*new_value_length = 4;
|
||||
*success = 1;
|
||||
char* result = malloc(4);
|
||||
@@ -344,12 +312,6 @@ static char* MergeOperatorPartialMerge(
|
||||
const char* const* operands_list, const size_t* operands_list_length,
|
||||
int num_operands,
|
||||
unsigned char* success, size_t* new_value_length) {
|
||||
(void)arg;
|
||||
(void)key;
|
||||
(void)key_length;
|
||||
(void)operands_list;
|
||||
(void)operands_list_length;
|
||||
(void)num_operands;
|
||||
*new_value_length = 4;
|
||||
*success = 1;
|
||||
char* result = malloc(4);
|
||||
@@ -371,20 +333,6 @@ static void CheckTxnGet(
|
||||
Free(&val);
|
||||
}
|
||||
|
||||
static void CheckTxnGetCF(rocksdb_transaction_t* txn,
|
||||
const rocksdb_readoptions_t* options,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
const char* key, const char* expected) {
|
||||
char* err = NULL;
|
||||
size_t val_len;
|
||||
char* val;
|
||||
val = rocksdb_transaction_get_cf(txn, options, column_family, key,
|
||||
strlen(key), &val_len, &err);
|
||||
CheckNoError(err);
|
||||
CheckEqual(expected, val, val_len);
|
||||
Free(&val);
|
||||
}
|
||||
|
||||
static void CheckTxnDBGet(
|
||||
rocksdb_transactiondb_t* txn_db,
|
||||
const rocksdb_readoptions_t* options,
|
||||
@@ -399,27 +347,10 @@ static void CheckTxnDBGet(
|
||||
Free(&val);
|
||||
}
|
||||
|
||||
static void CheckTxnDBGetCF(rocksdb_transactiondb_t* txn_db,
|
||||
const rocksdb_readoptions_t* options,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
const char* key, const char* expected) {
|
||||
char* err = NULL;
|
||||
size_t val_len;
|
||||
char* val;
|
||||
val = rocksdb_transactiondb_get_cf(txn_db, options, column_family, key,
|
||||
strlen(key), &val_len, &err);
|
||||
CheckNoError(err);
|
||||
CheckEqual(expected, val, val_len);
|
||||
Free(&val);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
rocksdb_t* db;
|
||||
rocksdb_comparator_t* cmp;
|
||||
rocksdb_cache_t* cache;
|
||||
rocksdb_dbpath_t *dbpath;
|
||||
rocksdb_env_t* env;
|
||||
rocksdb_options_t* options;
|
||||
rocksdb_compactoptions_t* coptions;
|
||||
@@ -431,8 +362,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_transactiondb_options_t* txn_db_options;
|
||||
rocksdb_transaction_t* txn;
|
||||
rocksdb_transaction_options_t* txn_options;
|
||||
rocksdb_optimistictransactiondb_t* otxn_db;
|
||||
rocksdb_optimistictransaction_options_t* otxn_options;
|
||||
char* err = NULL;
|
||||
int run = -1;
|
||||
|
||||
@@ -456,14 +385,8 @@ int main(int argc, char** argv) {
|
||||
GetTempDir(),
|
||||
((int)geteuid()));
|
||||
|
||||
snprintf(dbpathname, sizeof(dbpathname),
|
||||
"%s/rocksdb_c_test-%d-dbpath",
|
||||
GetTempDir(),
|
||||
((int) geteuid()));
|
||||
|
||||
StartPhase("create_objects");
|
||||
cmp = rocksdb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);
|
||||
dbpath = rocksdb_dbpath_create(dbpathname, 1024 * 1024);
|
||||
env = rocksdb_create_default_env();
|
||||
cache = rocksdb_cache_create_lru(100000);
|
||||
|
||||
@@ -1434,18 +1357,6 @@ int main(int argc, char** argv) {
|
||||
CheckNoError(err);
|
||||
CheckTxnDBGet(txn_db, roptions, "foo", NULL);
|
||||
|
||||
// write batch into TransactionDB
|
||||
rocksdb_writebatch_t* wb = rocksdb_writebatch_create();
|
||||
rocksdb_writebatch_put(wb, "foo", 3, "a", 1);
|
||||
rocksdb_writebatch_clear(wb);
|
||||
rocksdb_writebatch_put(wb, "bar", 3, "b", 1);
|
||||
rocksdb_writebatch_put(wb, "box", 3, "c", 1);
|
||||
rocksdb_writebatch_delete(wb, "bar", 3);
|
||||
rocksdb_transactiondb_write(txn_db, woptions, wb, &err);
|
||||
rocksdb_writebatch_destroy(wb);
|
||||
CheckTxnDBGet(txn_db, roptions, "box", "c");
|
||||
CheckNoError(err);
|
||||
|
||||
// begin a transaction
|
||||
txn = rocksdb_transaction_begin(txn_db, woptions, txn_options, NULL);
|
||||
// put
|
||||
@@ -1502,42 +1413,6 @@ int main(int argc, char** argv) {
|
||||
CheckNoError(err);
|
||||
CheckTxnDBGet(txn_db, roptions, "bar", NULL);
|
||||
|
||||
// save point
|
||||
rocksdb_transaction_put(txn, "foo1", 4, "hi1", 3, &err);
|
||||
rocksdb_transaction_set_savepoint(txn);
|
||||
CheckTxnGet(txn, roptions, "foo1", "hi1");
|
||||
rocksdb_transaction_put(txn, "foo2", 4, "hi2", 3, &err);
|
||||
CheckTxnGet(txn, roptions, "foo2", "hi2");
|
||||
|
||||
// rollback to savepoint
|
||||
rocksdb_transaction_rollback_to_savepoint(txn, &err);
|
||||
CheckNoError(err);
|
||||
CheckTxnGet(txn, roptions, "foo2", NULL);
|
||||
CheckTxnGet(txn, roptions, "foo1", "hi1");
|
||||
CheckTxnDBGet(txn_db, roptions, "foo1", NULL);
|
||||
CheckTxnDBGet(txn_db, roptions, "foo2", NULL);
|
||||
rocksdb_transaction_commit(txn, &err);
|
||||
CheckNoError(err);
|
||||
CheckTxnDBGet(txn_db, roptions, "foo1", "hi1");
|
||||
CheckTxnDBGet(txn_db, roptions, "foo2", NULL);
|
||||
|
||||
// Column families.
|
||||
rocksdb_column_family_handle_t* cfh;
|
||||
cfh = rocksdb_transactiondb_create_column_family(txn_db, options,
|
||||
"txn_db_cf", &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_transactiondb_put_cf(txn_db, woptions, cfh, "cf_foo", 6, "cf_hello",
|
||||
8, &err);
|
||||
CheckNoError(err);
|
||||
CheckTxnDBGetCF(txn_db, roptions, cfh, "cf_foo", "cf_hello");
|
||||
|
||||
rocksdb_transactiondb_delete_cf(txn_db, woptions, cfh, "cf_foo", 6, &err);
|
||||
CheckNoError(err);
|
||||
CheckTxnDBGetCF(txn_db, roptions, cfh, "cf_foo", NULL);
|
||||
|
||||
rocksdb_column_family_handle_destroy(cfh);
|
||||
|
||||
// close and destroy
|
||||
rocksdb_transaction_destroy(txn);
|
||||
rocksdb_transactiondb_close(txn_db);
|
||||
@@ -1547,105 +1422,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_transactiondb_options_destroy(txn_db_options);
|
||||
}
|
||||
|
||||
StartPhase("optimistic_transactions");
|
||||
{
|
||||
rocksdb_options_t* db_options = rocksdb_options_create();
|
||||
rocksdb_options_set_create_if_missing(db_options, 1);
|
||||
rocksdb_options_set_allow_concurrent_memtable_write(db_options, 1);
|
||||
otxn_db = rocksdb_optimistictransactiondb_open(db_options, dbname, &err);
|
||||
otxn_options = rocksdb_optimistictransaction_options_create();
|
||||
rocksdb_transaction_t* txn1 = rocksdb_optimistictransaction_begin(
|
||||
otxn_db, woptions, otxn_options, NULL);
|
||||
rocksdb_transaction_t* txn2 = rocksdb_optimistictransaction_begin(
|
||||
otxn_db, woptions, otxn_options, NULL);
|
||||
rocksdb_transaction_put(txn1, "key", 3, "value", 5, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_put(txn2, "key1", 4, "value1", 6, &err);
|
||||
CheckNoError(err);
|
||||
CheckTxnGet(txn1, roptions, "key", "value");
|
||||
rocksdb_transaction_commit(txn1, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_commit(txn2, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_destroy(txn1);
|
||||
rocksdb_transaction_destroy(txn2);
|
||||
|
||||
// Check column family
|
||||
db = rocksdb_optimistictransactiondb_get_base_db(otxn_db);
|
||||
rocksdb_put(db, woptions, "key", 3, "value", 5, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_column_family_handle_t *cfh1, *cfh2;
|
||||
cfh1 = rocksdb_create_column_family(db, db_options, "txn_db_cf1", &err);
|
||||
cfh2 = rocksdb_create_column_family(db, db_options, "txn_db_cf2", &err);
|
||||
txn = rocksdb_optimistictransaction_begin(otxn_db, woptions, otxn_options,
|
||||
NULL);
|
||||
rocksdb_transaction_put_cf(txn, cfh1, "key_cf1", 7, "val_cf1", 7, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_put_cf(txn, cfh2, "key_cf2", 7, "val_cf2", 7, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_commit(txn, &err);
|
||||
CheckNoError(err);
|
||||
txn = rocksdb_optimistictransaction_begin(otxn_db, woptions, otxn_options,
|
||||
txn);
|
||||
CheckGetCF(db, roptions, cfh1, "key_cf1", "val_cf1");
|
||||
CheckTxnGetCF(txn, roptions, cfh1, "key_cf1", "val_cf1");
|
||||
|
||||
// Check iterator with column family
|
||||
rocksdb_transaction_put_cf(txn, cfh1, "key1_cf", 7, "val1_cf", 7, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iterator_t* iter =
|
||||
rocksdb_transaction_create_iterator_cf(txn, roptions, cfh1);
|
||||
CheckCondition(!rocksdb_iter_valid(iter));
|
||||
rocksdb_iter_seek_to_first(iter);
|
||||
CheckCondition(rocksdb_iter_valid(iter));
|
||||
CheckIter(iter, "key1_cf", "val1_cf");
|
||||
rocksdb_iter_get_error(iter, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iter_destroy(iter);
|
||||
|
||||
rocksdb_transaction_destroy(txn);
|
||||
rocksdb_column_family_handle_destroy(cfh1);
|
||||
rocksdb_column_family_handle_destroy(cfh2);
|
||||
rocksdb_optimistictransactiondb_close_base_db(db);
|
||||
rocksdb_optimistictransactiondb_close(otxn_db);
|
||||
|
||||
// Check open optimistic transaction db with column families
|
||||
size_t cf_len;
|
||||
char** column_fams =
|
||||
rocksdb_list_column_families(db_options, dbname, &cf_len, &err);
|
||||
CheckNoError(err);
|
||||
CheckEqual("default", column_fams[0], 7);
|
||||
CheckEqual("txn_db_cf1", column_fams[1], 10);
|
||||
CheckEqual("txn_db_cf2", column_fams[2], 10);
|
||||
CheckCondition(cf_len == 3);
|
||||
rocksdb_list_column_families_destroy(column_fams, cf_len);
|
||||
|
||||
const char* cf_names[3] = {"default", "txn_db_cf1", "txn_db_cf2"};
|
||||
rocksdb_options_t* cf_options = rocksdb_options_create();
|
||||
const rocksdb_options_t* cf_opts[3] = {cf_options, cf_options, cf_options};
|
||||
|
||||
rocksdb_options_set_error_if_exists(cf_options, 0);
|
||||
rocksdb_column_family_handle_t* cf_handles[3];
|
||||
otxn_db = rocksdb_optimistictransactiondb_open_column_families(
|
||||
db_options, dbname, 3, cf_names, cf_opts, cf_handles, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_transaction_t* txn_cf = rocksdb_optimistictransaction_begin(
|
||||
otxn_db, woptions, otxn_options, NULL);
|
||||
CheckTxnGetCF(txn_cf, roptions, cf_handles[0], "key", "value");
|
||||
CheckTxnGetCF(txn_cf, roptions, cf_handles[1], "key_cf1", "val_cf1");
|
||||
CheckTxnGetCF(txn_cf, roptions, cf_handles[2], "key_cf2", "val_cf2");
|
||||
rocksdb_transaction_destroy(txn_cf);
|
||||
rocksdb_options_destroy(cf_options);
|
||||
rocksdb_column_family_handle_destroy(cf_handles[0]);
|
||||
rocksdb_column_family_handle_destroy(cf_handles[1]);
|
||||
rocksdb_column_family_handle_destroy(cf_handles[2]);
|
||||
rocksdb_optimistictransactiondb_close(otxn_db);
|
||||
rocksdb_destroy_db(db_options, dbname, &err);
|
||||
rocksdb_options_destroy(db_options);
|
||||
rocksdb_optimistictransaction_options_destroy(otxn_options);
|
||||
CheckNoError(err);
|
||||
}
|
||||
|
||||
// Simple sanity check that setting memtable rep works.
|
||||
StartPhase("memtable_reps");
|
||||
{
|
||||
@@ -1664,18 +1440,6 @@ int main(int argc, char** argv) {
|
||||
CheckNoError(err);
|
||||
}
|
||||
|
||||
// Simple sanity check that options setting db_paths work.
|
||||
StartPhase("open_db_paths");
|
||||
{
|
||||
rocksdb_close(db);
|
||||
rocksdb_destroy_db(options, dbname, &err);
|
||||
|
||||
const rocksdb_dbpath_t* paths[1] = {dbpath};
|
||||
rocksdb_options_set_db_paths(options, paths, 1);
|
||||
db = rocksdb_open(options, dbname, &err);
|
||||
CheckNoError(err);
|
||||
}
|
||||
|
||||
StartPhase("cleanup");
|
||||
rocksdb_close(db);
|
||||
rocksdb_options_destroy(options);
|
||||
@@ -1685,7 +1449,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_compactoptions_destroy(coptions);
|
||||
rocksdb_cache_destroy(cache);
|
||||
rocksdb_comparator_destroy(cmp);
|
||||
rocksdb_dbpath_destroy(dbpath);
|
||||
rocksdb_env_destroy(env);
|
||||
|
||||
fprintf(stderr, "PASS\n");
|
||||
|
||||
+70
-309
@@ -31,10 +31,8 @@
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "table/block_based_table_factory.h"
|
||||
#include "table/merging_iterator.h"
|
||||
#include "util/autovector.h"
|
||||
#include "util/compression.h"
|
||||
#include "util/sst_file_manager_impl.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@@ -55,9 +53,6 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
|
||||
#endif // ROCKSDB_LITE
|
||||
// Job id == 0 means that this is not our background process, but rather
|
||||
// user thread
|
||||
// Need to hold some shared pointers owned by the initial_cf_options
|
||||
// before final cleaning up finishes.
|
||||
ColumnFamilyOptions initial_cf_options_copy = cfd_->initial_cf_options();
|
||||
JobContext job_context(0);
|
||||
mutex_->Lock();
|
||||
if (cfd_->Unref()) {
|
||||
@@ -85,7 +80,6 @@ Status ColumnFamilyHandleImpl::GetDescriptor(ColumnFamilyDescriptor* desc) {
|
||||
*desc = ColumnFamilyDescriptor(cfd()->GetName(), cfd()->GetLatestCFOptions());
|
||||
return Status::OK();
|
||||
#else
|
||||
(void)desc;
|
||||
return Status::NotSupported();
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
@@ -129,22 +123,6 @@ Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options) {
|
||||
" is not linked with the binary.");
|
||||
}
|
||||
}
|
||||
if (cf_options.compression_opts.zstd_max_train_bytes > 0) {
|
||||
if (!CompressionTypeSupported(CompressionType::kZSTD)) {
|
||||
// Dictionary trainer is available since v0.6.1, but ZSTD was marked
|
||||
// stable only since v0.8.0. For now we enable the feature in stable
|
||||
// versions only.
|
||||
return Status::InvalidArgument(
|
||||
"zstd dictionary trainer cannot be used because " +
|
||||
CompressionTypeToString(CompressionType::kZSTD) +
|
||||
" is not linked with the binary.");
|
||||
}
|
||||
if (cf_options.compression_opts.max_dict_bytes == 0) {
|
||||
return Status::InvalidArgument(
|
||||
"The dictionary size limit (`CompressionOptions::max_dict_bytes`) "
|
||||
"should be nonzero if we're using zstd's dictionary generator.");
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -161,28 +139,6 @@ Status CheckConcurrentWritesSupported(const ColumnFamilyOptions& cf_options) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
const ColumnFamilyOptions& cf_options) {
|
||||
// More than one cf_paths are supported only in universal
|
||||
// and level compaction styles. This function also checks the case
|
||||
// in which cf_paths is not specified, which results in db_paths
|
||||
// being used.
|
||||
if ((cf_options.compaction_style != kCompactionStyleUniversal) &&
|
||||
(cf_options.compaction_style != kCompactionStyleLevel)) {
|
||||
if (cf_options.cf_paths.size() > 1) {
|
||||
return Status::NotSupported(
|
||||
"More than one CF paths are only supported in "
|
||||
"universal and level compaction styles. ");
|
||||
} else if (cf_options.cf_paths.empty() &&
|
||||
db_options.db_paths.size() > 1) {
|
||||
return Status::NotSupported(
|
||||
"More than one DB paths are only supported in "
|
||||
"universal and level compaction styles. ");
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
const ColumnFamilyOptions& src) {
|
||||
ColumnFamilyOptions result = src;
|
||||
@@ -301,24 +257,9 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
result.hard_pending_compaction_bytes_limit;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
// When the DB is stopped, it's possible that there are some .trash files that
|
||||
// were not deleted yet, when we open the DB we will find these .trash files
|
||||
// and schedule them to be deleted (or delete immediately if SstFileManager
|
||||
// was not used)
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(db_options.sst_file_manager.get());
|
||||
for (size_t i = 0; i < result.cf_paths.size(); i++) {
|
||||
DeleteScheduler::CleanupDirectory(db_options.env, sfm, result.cf_paths[i].path);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result.cf_paths.empty()) {
|
||||
result.cf_paths = db_options.db_paths;
|
||||
}
|
||||
|
||||
if (result.level_compaction_dynamic_level_bytes) {
|
||||
if (result.compaction_style != kCompactionStyleLevel ||
|
||||
result.cf_paths.size() > 1U) {
|
||||
db_options.db_paths.size() > 1U) {
|
||||
// 1. level_compaction_dynamic_level_bytes only makes sense for
|
||||
// level-based compaction.
|
||||
// 2. we don't yet know how to make both of this feature and multiple
|
||||
@@ -387,13 +328,12 @@ void SuperVersionUnrefHandle(void* ptr) {
|
||||
// When latter happens, we are in ~ColumnFamilyData(), no get should happen as
|
||||
// well.
|
||||
SuperVersion* sv = static_cast<SuperVersion*>(ptr);
|
||||
bool was_last_ref __attribute__((__unused__));
|
||||
was_last_ref = sv->Unref();
|
||||
// Thread-local SuperVersions can't outlive ColumnFamilyData::super_version_.
|
||||
// This is important because we can't do SuperVersion cleanup here.
|
||||
// That would require locking DB mutex, which would deadlock because
|
||||
// SuperVersionUnrefHandle is called with locked ThreadLocalPtr mutex.
|
||||
assert(!was_last_ref);
|
||||
if (sv->Unref()) {
|
||||
sv->db_mutex->Lock();
|
||||
sv->Cleanup();
|
||||
sv->db_mutex->Unlock();
|
||||
delete sv;
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -425,13 +365,11 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
next_(nullptr),
|
||||
prev_(nullptr),
|
||||
log_number_(0),
|
||||
flush_reason_(FlushReason::kOthers),
|
||||
column_family_set_(column_family_set),
|
||||
queued_for_flush_(false),
|
||||
queued_for_compaction_(false),
|
||||
pending_flush_(false),
|
||||
pending_compaction_(false),
|
||||
prev_compaction_needed_bytes_(0),
|
||||
allow_2pc_(db_options.allow_2pc),
|
||||
last_memtable_id_(0) {
|
||||
allow_2pc_(db_options.allow_2pc) {
|
||||
Ref();
|
||||
|
||||
// Convert user defined table properties collector factories to internal ones.
|
||||
@@ -504,8 +442,8 @@ ColumnFamilyData::~ColumnFamilyData() {
|
||||
|
||||
// It would be wrong if this ColumnFamilyData is in flush_queue_ or
|
||||
// compaction_queue_ and we destroyed it
|
||||
assert(!queued_for_flush_);
|
||||
assert(!queued_for_compaction_);
|
||||
assert(!pending_flush_);
|
||||
assert(!pending_compaction_);
|
||||
|
||||
if (super_version_ != nullptr) {
|
||||
// Release SuperVersion reference kept in ThreadLocalPtr.
|
||||
@@ -514,7 +452,7 @@ ColumnFamilyData::~ColumnFamilyData() {
|
||||
local_sv_.reset();
|
||||
super_version_->db_mutex->Lock();
|
||||
|
||||
bool is_last_reference __attribute__((__unused__));
|
||||
bool is_last_reference __attribute__((unused));
|
||||
is_last_reference = super_version_->Unref();
|
||||
assert(is_last_reference);
|
||||
super_version_->Cleanup();
|
||||
@@ -525,8 +463,7 @@ ColumnFamilyData::~ColumnFamilyData() {
|
||||
if (dummy_versions_ != nullptr) {
|
||||
// List must be empty
|
||||
assert(dummy_versions_->TEST_Next() == dummy_versions_);
|
||||
bool deleted __attribute__((__unused__));
|
||||
deleted = dummy_versions_->Unref();
|
||||
bool deleted __attribute__((unused)) = dummy_versions_->Unref();
|
||||
assert(deleted);
|
||||
}
|
||||
|
||||
@@ -558,9 +495,7 @@ uint64_t ColumnFamilyData::OldestLogToKeep() {
|
||||
auto current_log = GetLogNumber();
|
||||
|
||||
if (allow_2pc_) {
|
||||
autovector<MemTable*> empty_list;
|
||||
auto imm_prep_log =
|
||||
imm()->PrecomputeMinLogContainingPrepSection(empty_list);
|
||||
auto imm_prep_log = imm()->GetMinLogContainingPrepSection();
|
||||
auto mem_prep_log = mem()->GetMinLogContainingPrepSection();
|
||||
|
||||
if (imm_prep_log > 0 && imm_prep_log < current_log) {
|
||||
@@ -678,97 +613,58 @@ int GetL0ThresholdSpeedupCompaction(int level0_file_num_compaction_trigger,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::pair<WriteStallCondition, ColumnFamilyData::WriteStallCause>
|
||||
ColumnFamilyData::GetWriteStallConditionAndCause(
|
||||
int num_unflushed_memtables, int num_l0_files,
|
||||
uint64_t num_compaction_needed_bytes,
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
if (num_unflushed_memtables >= mutable_cf_options.max_write_buffer_number) {
|
||||
return {WriteStallCondition::kStopped, WriteStallCause::kMemtableLimit};
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
num_l0_files >= mutable_cf_options.level0_stop_writes_trigger) {
|
||||
return {WriteStallCondition::kStopped, WriteStallCause::kL0FileCountLimit};
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit > 0 &&
|
||||
num_compaction_needed_bytes >=
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit) {
|
||||
return {WriteStallCondition::kStopped,
|
||||
WriteStallCause::kPendingCompactionBytes};
|
||||
} else if (mutable_cf_options.max_write_buffer_number > 3 &&
|
||||
num_unflushed_memtables >=
|
||||
mutable_cf_options.max_write_buffer_number - 1) {
|
||||
return {WriteStallCondition::kDelayed, WriteStallCause::kMemtableLimit};
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.level0_slowdown_writes_trigger >= 0 &&
|
||||
num_l0_files >=
|
||||
mutable_cf_options.level0_slowdown_writes_trigger) {
|
||||
return {WriteStallCondition::kDelayed, WriteStallCause::kL0FileCountLimit};
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit > 0 &&
|
||||
num_compaction_needed_bytes >=
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit) {
|
||||
return {WriteStallCondition::kDelayed,
|
||||
WriteStallCause::kPendingCompactionBytes};
|
||||
}
|
||||
return {WriteStallCondition::kNormal, WriteStallCause::kNone};
|
||||
}
|
||||
|
||||
WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
void ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
auto write_stall_condition = WriteStallCondition::kNormal;
|
||||
if (current_ != nullptr) {
|
||||
auto* vstorage = current_->storage_info();
|
||||
auto write_controller = column_family_set_->write_controller_;
|
||||
uint64_t compaction_needed_bytes =
|
||||
vstorage->estimated_compaction_needed_bytes();
|
||||
|
||||
auto write_stall_condition_and_cause = GetWriteStallConditionAndCause(
|
||||
imm()->NumNotFlushed(), vstorage->l0_delay_trigger_count(),
|
||||
vstorage->estimated_compaction_needed_bytes(), mutable_cf_options);
|
||||
write_stall_condition = write_stall_condition_and_cause.first;
|
||||
auto write_stall_cause = write_stall_condition_and_cause.second;
|
||||
|
||||
bool was_stopped = write_controller->IsStopped();
|
||||
bool needed_delay = write_controller->NeedsDelay();
|
||||
|
||||
if (write_stall_condition == WriteStallCondition::kStopped &&
|
||||
write_stall_cause == WriteStallCause::kMemtableLimit) {
|
||||
if (imm()->NumNotFlushed() >= mutable_cf_options.max_write_buffer_number) {
|
||||
write_controller_token_ = write_controller->GetStopToken();
|
||||
internal_stats_->AddCFStats(InternalStats::MEMTABLE_LIMIT_STOPS, 1);
|
||||
internal_stats_->AddCFStats(InternalStats::MEMTABLE_COMPACTION, 1);
|
||||
ROCKS_LOG_WARN(
|
||||
ioptions_.info_log,
|
||||
"[%s] Stopping writes because we have %d immutable memtables "
|
||||
"(waiting for flush), max_write_buffer_number is set to %d",
|
||||
name_.c_str(), imm()->NumNotFlushed(),
|
||||
mutable_cf_options.max_write_buffer_number);
|
||||
} else if (write_stall_condition == WriteStallCondition::kStopped &&
|
||||
write_stall_cause == WriteStallCause::kL0FileCountLimit) {
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
vstorage->l0_delay_trigger_count() >=
|
||||
mutable_cf_options.level0_stop_writes_trigger) {
|
||||
write_controller_token_ = write_controller->GetStopToken();
|
||||
internal_stats_->AddCFStats(InternalStats::L0_FILE_COUNT_LIMIT_STOPS, 1);
|
||||
internal_stats_->AddCFStats(InternalStats::LEVEL0_NUM_FILES_TOTAL, 1);
|
||||
if (compaction_picker_->IsLevel0CompactionInProgress()) {
|
||||
internal_stats_->AddCFStats(
|
||||
InternalStats::LOCKED_L0_FILE_COUNT_LIMIT_STOPS, 1);
|
||||
InternalStats::LEVEL0_NUM_FILES_WITH_COMPACTION, 1);
|
||||
}
|
||||
ROCKS_LOG_WARN(ioptions_.info_log,
|
||||
"[%s] Stopping writes because we have %d level-0 files",
|
||||
name_.c_str(), vstorage->l0_delay_trigger_count());
|
||||
} else if (write_stall_condition == WriteStallCondition::kStopped &&
|
||||
write_stall_cause == WriteStallCause::kPendingCompactionBytes) {
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit > 0 &&
|
||||
compaction_needed_bytes >=
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit) {
|
||||
write_controller_token_ = write_controller->GetStopToken();
|
||||
internal_stats_->AddCFStats(
|
||||
InternalStats::PENDING_COMPACTION_BYTES_LIMIT_STOPS, 1);
|
||||
InternalStats::HARD_PENDING_COMPACTION_BYTES_LIMIT, 1);
|
||||
ROCKS_LOG_WARN(
|
||||
ioptions_.info_log,
|
||||
"[%s] Stopping writes because of estimated pending compaction "
|
||||
"bytes %" PRIu64,
|
||||
name_.c_str(), compaction_needed_bytes);
|
||||
} else if (write_stall_condition == WriteStallCondition::kDelayed &&
|
||||
write_stall_cause == WriteStallCause::kMemtableLimit) {
|
||||
} else if (mutable_cf_options.max_write_buffer_number > 3 &&
|
||||
imm()->NumNotFlushed() >=
|
||||
mutable_cf_options.max_write_buffer_number - 1) {
|
||||
write_controller_token_ =
|
||||
SetupDelay(write_controller, compaction_needed_bytes,
|
||||
prev_compaction_needed_bytes_, was_stopped,
|
||||
mutable_cf_options.disable_auto_compactions);
|
||||
internal_stats_->AddCFStats(InternalStats::MEMTABLE_LIMIT_SLOWDOWNS, 1);
|
||||
internal_stats_->AddCFStats(InternalStats::MEMTABLE_SLOWDOWN, 1);
|
||||
ROCKS_LOG_WARN(
|
||||
ioptions_.info_log,
|
||||
"[%s] Stalling writes because we have %d immutable memtables "
|
||||
@@ -777,8 +673,10 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
name_.c_str(), imm()->NumNotFlushed(),
|
||||
mutable_cf_options.max_write_buffer_number,
|
||||
write_controller->delayed_write_rate());
|
||||
} else if (write_stall_condition == WriteStallCondition::kDelayed &&
|
||||
write_stall_cause == WriteStallCause::kL0FileCountLimit) {
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.level0_slowdown_writes_trigger >= 0 &&
|
||||
vstorage->l0_delay_trigger_count() >=
|
||||
mutable_cf_options.level0_slowdown_writes_trigger) {
|
||||
// L0 is the last two files from stopping.
|
||||
bool near_stop = vstorage->l0_delay_trigger_count() >=
|
||||
mutable_cf_options.level0_stop_writes_trigger - 2;
|
||||
@@ -786,19 +684,20 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
SetupDelay(write_controller, compaction_needed_bytes,
|
||||
prev_compaction_needed_bytes_, was_stopped || near_stop,
|
||||
mutable_cf_options.disable_auto_compactions);
|
||||
internal_stats_->AddCFStats(InternalStats::L0_FILE_COUNT_LIMIT_SLOWDOWNS,
|
||||
1);
|
||||
internal_stats_->AddCFStats(InternalStats::LEVEL0_SLOWDOWN_TOTAL, 1);
|
||||
if (compaction_picker_->IsLevel0CompactionInProgress()) {
|
||||
internal_stats_->AddCFStats(
|
||||
InternalStats::LOCKED_L0_FILE_COUNT_LIMIT_SLOWDOWNS, 1);
|
||||
InternalStats::LEVEL0_SLOWDOWN_WITH_COMPACTION, 1);
|
||||
}
|
||||
ROCKS_LOG_WARN(ioptions_.info_log,
|
||||
"[%s] Stalling writes because we have %d level-0 files "
|
||||
"rate %" PRIu64,
|
||||
name_.c_str(), vstorage->l0_delay_trigger_count(),
|
||||
write_controller->delayed_write_rate());
|
||||
} else if (write_stall_condition == WriteStallCondition::kDelayed &&
|
||||
write_stall_cause == WriteStallCause::kPendingCompactionBytes) {
|
||||
} else if (!mutable_cf_options.disable_auto_compactions &&
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit > 0 &&
|
||||
vstorage->estimated_compaction_needed_bytes() >=
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit) {
|
||||
// If the distance to hard limit is less than 1/4 of the gap between soft
|
||||
// and
|
||||
// hard bytes limit, we think it is near stop and speed up the slowdown.
|
||||
@@ -815,7 +714,7 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
prev_compaction_needed_bytes_, was_stopped || near_stop,
|
||||
mutable_cf_options.disable_auto_compactions);
|
||||
internal_stats_->AddCFStats(
|
||||
InternalStats::PENDING_COMPACTION_BYTES_LIMIT_SLOWDOWNS, 1);
|
||||
InternalStats::SOFT_PENDING_COMPACTION_BYTES_LIMIT, 1);
|
||||
ROCKS_LOG_WARN(
|
||||
ioptions_.info_log,
|
||||
"[%s] Stalling writes because of estimated pending compaction "
|
||||
@@ -823,7 +722,6 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
name_.c_str(), vstorage->estimated_compaction_needed_bytes(),
|
||||
write_controller->delayed_write_rate());
|
||||
} else {
|
||||
assert(write_stall_condition == WriteStallCondition::kNormal);
|
||||
if (vstorage->l0_delay_trigger_count() >=
|
||||
GetL0ThresholdSpeedupCompaction(
|
||||
mutable_cf_options.level0_file_num_compaction_trigger,
|
||||
@@ -871,7 +769,6 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
}
|
||||
prev_compaction_needed_bytes_ = compaction_needed_bytes;
|
||||
}
|
||||
return write_stall_condition;
|
||||
}
|
||||
|
||||
const EnvOptions* ColumnFamilyData::soptions() const {
|
||||
@@ -890,10 +787,6 @@ uint64_t ColumnFamilyData::GetTotalSstFilesSize() const {
|
||||
return VersionSet::GetTotalSstFilesSize(dummy_versions_);
|
||||
}
|
||||
|
||||
uint64_t ColumnFamilyData::GetLiveSstFilesSize() const {
|
||||
return current_->GetSstFilesSize();
|
||||
}
|
||||
|
||||
MemTable* ColumnFamilyData::ConstructNewMemtable(
|
||||
const MutableCFOptions& mutable_cf_options, SequenceNumber earliest_seq) {
|
||||
return new MemTable(internal_comparator_, ioptions_, mutable_cf_options,
|
||||
@@ -930,80 +823,16 @@ bool ColumnFamilyData::RangeOverlapWithCompaction(
|
||||
smallest_user_key, largest_user_key, level);
|
||||
}
|
||||
|
||||
Status ColumnFamilyData::RangesOverlapWithMemtables(
|
||||
const autovector<Range>& ranges, SuperVersion* super_version,
|
||||
bool* overlap) {
|
||||
assert(overlap != nullptr);
|
||||
*overlap = false;
|
||||
// Create an InternalIterator over all unflushed memtables
|
||||
Arena arena;
|
||||
ReadOptions read_opts;
|
||||
read_opts.total_order_seek = true;
|
||||
MergeIteratorBuilder merge_iter_builder(&internal_comparator_, &arena);
|
||||
merge_iter_builder.AddIterator(
|
||||
super_version->mem->NewIterator(read_opts, &arena));
|
||||
super_version->imm->AddIterators(read_opts, &merge_iter_builder);
|
||||
ScopedArenaIterator memtable_iter(merge_iter_builder.Finish());
|
||||
|
||||
std::vector<InternalIterator*> memtable_range_del_iters;
|
||||
auto* active_range_del_iter =
|
||||
super_version->mem->NewRangeTombstoneIterator(read_opts);
|
||||
if (active_range_del_iter != nullptr) {
|
||||
memtable_range_del_iters.push_back(active_range_del_iter);
|
||||
}
|
||||
super_version->imm->AddRangeTombstoneIterators(read_opts,
|
||||
&memtable_range_del_iters);
|
||||
RangeDelAggregator range_del_agg(internal_comparator_, {} /* snapshots */,
|
||||
false /* collapse_deletions */);
|
||||
Status status;
|
||||
{
|
||||
std::unique_ptr<InternalIterator> memtable_range_del_iter(
|
||||
NewMergingIterator(&internal_comparator_,
|
||||
memtable_range_del_iters.empty()
|
||||
? nullptr
|
||||
: &memtable_range_del_iters[0],
|
||||
static_cast<int>(memtable_range_del_iters.size())));
|
||||
status = range_del_agg.AddTombstones(std::move(memtable_range_del_iter));
|
||||
}
|
||||
for (size_t i = 0; i < ranges.size() && status.ok() && !*overlap; ++i) {
|
||||
auto* vstorage = super_version->current->storage_info();
|
||||
auto* ucmp = vstorage->InternalComparator()->user_comparator();
|
||||
InternalKey range_start(ranges[i].start, kMaxSequenceNumber,
|
||||
kValueTypeForSeek);
|
||||
memtable_iter->Seek(range_start.Encode());
|
||||
status = memtable_iter->status();
|
||||
ParsedInternalKey seek_result;
|
||||
if (status.ok()) {
|
||||
if (memtable_iter->Valid() &&
|
||||
!ParseInternalKey(memtable_iter->key(), &seek_result)) {
|
||||
status = Status::Corruption("DB have corrupted keys");
|
||||
}
|
||||
}
|
||||
if (status.ok()) {
|
||||
if (memtable_iter->Valid() &&
|
||||
ucmp->Compare(seek_result.user_key, ranges[i].limit) <= 0) {
|
||||
*overlap = true;
|
||||
} else if (range_del_agg.IsRangeOverlapped(ranges[i].start,
|
||||
ranges[i].limit)) {
|
||||
*overlap = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
const int ColumnFamilyData::kCompactAllLevels = -1;
|
||||
const int ColumnFamilyData::kCompactToBaseLevel = -2;
|
||||
|
||||
Compaction* ColumnFamilyData::CompactRange(
|
||||
const MutableCFOptions& mutable_cf_options, int input_level,
|
||||
int output_level, uint32_t output_path_id, uint32_t max_subcompactions,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* conflict) {
|
||||
int output_level, uint32_t output_path_id, const InternalKey* begin,
|
||||
const InternalKey* end, InternalKey** compaction_end, bool* conflict) {
|
||||
auto* result = compaction_picker_->CompactRange(
|
||||
GetName(), mutable_cf_options, current_->storage_info(), input_level,
|
||||
output_level, output_path_id, max_subcompactions, begin, end,
|
||||
compaction_end, conflict);
|
||||
output_level, output_path_id, begin, end, compaction_end, conflict);
|
||||
if (result != nullptr) {
|
||||
result->SetInputVersion(current_);
|
||||
}
|
||||
@@ -1012,13 +841,10 @@ Compaction* ColumnFamilyData::CompactRange(
|
||||
|
||||
SuperVersion* ColumnFamilyData::GetReferencedSuperVersion(
|
||||
InstrumentedMutex* db_mutex) {
|
||||
SuperVersion* sv = GetThreadLocalSuperVersion(db_mutex);
|
||||
SuperVersion* sv = nullptr;
|
||||
sv = GetThreadLocalSuperVersion(db_mutex);
|
||||
sv->Ref();
|
||||
if (!ReturnThreadLocalSuperVersion(sv)) {
|
||||
// This Unref() corresponds to the Ref() in GetThreadLocalSuperVersion()
|
||||
// when the thread-local pointer was populated. So, the Ref() earlier in
|
||||
// this function still prevents the returned SuperVersion* from being
|
||||
// deleted out from under the caller.
|
||||
sv->Unref();
|
||||
}
|
||||
return sv;
|
||||
@@ -1026,6 +852,7 @@ SuperVersion* ColumnFamilyData::GetReferencedSuperVersion(
|
||||
|
||||
SuperVersion* ColumnFamilyData::GetThreadLocalSuperVersion(
|
||||
InstrumentedMutex* db_mutex) {
|
||||
SuperVersion* sv = nullptr;
|
||||
// The SuperVersion is cached in thread local storage to avoid acquiring
|
||||
// mutex when SuperVersion does not change since the last use. When a new
|
||||
// SuperVersion is installed, the compaction or flush thread cleans up
|
||||
@@ -1044,7 +871,7 @@ SuperVersion* ColumnFamilyData::GetThreadLocalSuperVersion(
|
||||
// should only keep kSVInUse before ReturnThreadLocalSuperVersion call
|
||||
// (if no Scrape happens).
|
||||
assert(ptr != SuperVersion::kSVInUse);
|
||||
SuperVersion* sv = static_cast<SuperVersion*>(ptr);
|
||||
sv = static_cast<SuperVersion*>(ptr);
|
||||
if (sv == SuperVersion::kSVObsolete ||
|
||||
sv->version_number != super_version_number_.load()) {
|
||||
RecordTick(ioptions_.statistics, NUMBER_SUPERVERSION_ACQUIRES);
|
||||
@@ -1087,16 +914,15 @@ bool ColumnFamilyData::ReturnThreadLocalSuperVersion(SuperVersion* sv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ColumnFamilyData::InstallSuperVersion(
|
||||
SuperVersionContext* sv_context, InstrumentedMutex* db_mutex) {
|
||||
SuperVersion* ColumnFamilyData::InstallSuperVersion(
|
||||
SuperVersion* new_superversion, InstrumentedMutex* db_mutex) {
|
||||
db_mutex->AssertHeld();
|
||||
return InstallSuperVersion(sv_context, db_mutex, mutable_cf_options_);
|
||||
return InstallSuperVersion(new_superversion, db_mutex, mutable_cf_options_);
|
||||
}
|
||||
|
||||
void ColumnFamilyData::InstallSuperVersion(
|
||||
SuperVersionContext* sv_context, InstrumentedMutex* db_mutex,
|
||||
SuperVersion* ColumnFamilyData::InstallSuperVersion(
|
||||
SuperVersion* new_superversion, InstrumentedMutex* db_mutex,
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
SuperVersion* new_superversion = sv_context->new_superversion.release();
|
||||
new_superversion->db_mutex = db_mutex;
|
||||
new_superversion->mutable_cf_options = mutable_cf_options;
|
||||
new_superversion->Init(mem_, imm_.current(), current_);
|
||||
@@ -1104,31 +930,16 @@ void ColumnFamilyData::InstallSuperVersion(
|
||||
super_version_ = new_superversion;
|
||||
++super_version_number_;
|
||||
super_version_->version_number = super_version_number_;
|
||||
super_version_->write_stall_condition =
|
||||
RecalculateWriteStallConditions(mutable_cf_options);
|
||||
// Reset SuperVersions cached in thread local storage
|
||||
ResetThreadLocalSuperVersions();
|
||||
|
||||
if (old_superversion != nullptr) {
|
||||
// Reset SuperVersions cached in thread local storage.
|
||||
// This should be done before old_superversion->Unref(). That's to ensure
|
||||
// that local_sv_ never holds the last reference to SuperVersion, since
|
||||
// it has no means to safely do SuperVersion cleanup.
|
||||
ResetThreadLocalSuperVersions();
|
||||
RecalculateWriteStallConditions(mutable_cf_options);
|
||||
|
||||
if (old_superversion->mutable_cf_options.write_buffer_size !=
|
||||
mutable_cf_options.write_buffer_size) {
|
||||
mem_->UpdateWriteBufferSize(mutable_cf_options.write_buffer_size);
|
||||
}
|
||||
if (old_superversion->write_stall_condition !=
|
||||
new_superversion->write_stall_condition) {
|
||||
sv_context->PushWriteStallNotification(
|
||||
old_superversion->write_stall_condition,
|
||||
new_superversion->write_stall_condition, GetName(), ioptions());
|
||||
}
|
||||
if (old_superversion->Unref()) {
|
||||
old_superversion->Cleanup();
|
||||
sv_context->superversions_to_free.push_back(old_superversion);
|
||||
}
|
||||
if (old_superversion != nullptr && old_superversion->Unref()) {
|
||||
old_superversion->Cleanup();
|
||||
return old_superversion; // will let caller delete outside of mutex
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ColumnFamilyData::ResetThreadLocalSuperVersions() {
|
||||
@@ -1140,12 +951,10 @@ void ColumnFamilyData::ResetThreadLocalSuperVersions() {
|
||||
continue;
|
||||
}
|
||||
auto sv = static_cast<SuperVersion*>(ptr);
|
||||
bool was_last_ref __attribute__((__unused__));
|
||||
was_last_ref = sv->Unref();
|
||||
// sv couldn't have been the last reference because
|
||||
// ResetThreadLocalSuperVersions() is called before
|
||||
// unref'ing super_version_.
|
||||
assert(!was_last_ref);
|
||||
if (sv->Unref()) {
|
||||
sv->Cleanup();
|
||||
delete sv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1153,9 +962,8 @@ void ColumnFamilyData::ResetThreadLocalSuperVersions() {
|
||||
Status ColumnFamilyData::SetOptions(
|
||||
const std::unordered_map<std::string, std::string>& options_map) {
|
||||
MutableCFOptions new_mutable_cf_options;
|
||||
Status s =
|
||||
GetMutableOptionsFromStrings(mutable_cf_options_, options_map,
|
||||
ioptions_.info_log, &new_mutable_cf_options);
|
||||
Status s = GetMutableOptionsFromStrings(mutable_cf_options_, options_map,
|
||||
&new_mutable_cf_options);
|
||||
if (s.ok()) {
|
||||
mutable_cf_options_ = new_mutable_cf_options;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
@@ -1164,49 +972,6 @@ Status ColumnFamilyData::SetOptions(
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// REQUIRES: DB mutex held
|
||||
Env::WriteLifeTimeHint ColumnFamilyData::CalculateSSTWriteHint(int level) {
|
||||
if (initial_cf_options_.compaction_style != kCompactionStyleLevel) {
|
||||
return Env::WLTH_NOT_SET;
|
||||
}
|
||||
if (level == 0) {
|
||||
return Env::WLTH_MEDIUM;
|
||||
}
|
||||
int base_level = current_->storage_info()->base_level();
|
||||
|
||||
// L1: medium, L2: long, ...
|
||||
if (level - base_level >= 2) {
|
||||
return Env::WLTH_EXTREME;
|
||||
}
|
||||
return static_cast<Env::WriteLifeTimeHint>(level - base_level +
|
||||
static_cast<int>(Env::WLTH_MEDIUM));
|
||||
}
|
||||
|
||||
Status ColumnFamilyData::AddDirectories() {
|
||||
Status s;
|
||||
assert(data_dirs_.empty());
|
||||
for (auto& p : ioptions_.cf_paths) {
|
||||
std::unique_ptr<Directory> path_directory;
|
||||
s = DBImpl::CreateAndNewDirectory(ioptions_.env, p.path, &path_directory);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
assert(path_directory != nullptr);
|
||||
data_dirs_.emplace_back(path_directory.release());
|
||||
}
|
||||
assert(data_dirs_.size() == ioptions_.cf_paths.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
Directory* ColumnFamilyData::GetDataDir(size_t path_id) const {
|
||||
if (data_dirs_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(path_id < data_dirs_.size());
|
||||
return data_dirs_[path_id].get();
|
||||
}
|
||||
|
||||
ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
|
||||
const ImmutableDBOptions* db_options,
|
||||
const EnvOptions& env_options,
|
||||
@@ -1233,14 +998,10 @@ ColumnFamilySet::~ColumnFamilySet() {
|
||||
while (column_family_data_.size() > 0) {
|
||||
// cfd destructor will delete itself from column_family_data_
|
||||
auto cfd = column_family_data_.begin()->second;
|
||||
bool last_ref __attribute__((__unused__));
|
||||
last_ref = cfd->Unref();
|
||||
assert(last_ref);
|
||||
cfd->Unref();
|
||||
delete cfd;
|
||||
}
|
||||
bool dummy_last_ref __attribute__((__unused__));
|
||||
dummy_last_ref = dummy_cfd_->Unref();
|
||||
assert(dummy_last_ref);
|
||||
dummy_cfd_->Unref();
|
||||
delete dummy_cfd_;
|
||||
}
|
||||
|
||||
|
||||
+20
-74
@@ -30,7 +30,6 @@ namespace rocksdb {
|
||||
|
||||
class Version;
|
||||
class VersionSet;
|
||||
class VersionStorageInfo;
|
||||
class MemTable;
|
||||
class MemTableListVersion;
|
||||
class CompactionPicker;
|
||||
@@ -42,7 +41,6 @@ class DBImpl;
|
||||
class LogBuffer;
|
||||
class InstrumentedMutex;
|
||||
class InstrumentedMutexLock;
|
||||
struct SuperVersionContext;
|
||||
|
||||
extern const double kIncSlowdownRatio;
|
||||
|
||||
@@ -78,7 +76,7 @@ class ColumnFamilyHandleImpl : public ColumnFamilyHandle {
|
||||
class ColumnFamilyHandleInternal : public ColumnFamilyHandleImpl {
|
||||
public:
|
||||
ColumnFamilyHandleInternal()
|
||||
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), internal_cfd_(nullptr) {}
|
||||
: ColumnFamilyHandleImpl(nullptr, nullptr, nullptr) {}
|
||||
|
||||
void SetCFD(ColumnFamilyData* _cfd) { internal_cfd_ = _cfd; }
|
||||
virtual ColumnFamilyData* cfd() const override { return internal_cfd_; }
|
||||
@@ -97,7 +95,6 @@ struct SuperVersion {
|
||||
MutableCFOptions mutable_cf_options;
|
||||
// Version number of the current SuperVersion
|
||||
uint64_t version_number;
|
||||
WriteStallCondition write_stall_condition;
|
||||
|
||||
InstrumentedMutex* db_mutex;
|
||||
|
||||
@@ -139,9 +136,6 @@ extern Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options);
|
||||
extern Status CheckConcurrentWritesSupported(
|
||||
const ColumnFamilyOptions& cf_options);
|
||||
|
||||
extern Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
const ColumnFamilyOptions& cf_options);
|
||||
|
||||
extern ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
const ColumnFamilyOptions& src);
|
||||
// Wrap user defined table proproties collector factories `from cf_options`
|
||||
@@ -198,7 +192,7 @@ class ColumnFamilyData {
|
||||
// *) delete all memory associated with that column family
|
||||
// *) delete all the files associated with that column family
|
||||
void SetDropped();
|
||||
bool IsDropped() const { return dropped_.load(std::memory_order_relaxed); }
|
||||
bool IsDropped() const { return dropped_; }
|
||||
|
||||
// thread-safe
|
||||
int NumberLevels() const { return ioptions_.num_levels; }
|
||||
@@ -206,10 +200,6 @@ class ColumnFamilyData {
|
||||
void SetLogNumber(uint64_t log_number) { log_number_ = log_number; }
|
||||
uint64_t GetLogNumber() const { return log_number_; }
|
||||
|
||||
void SetFlushReason(FlushReason flush_reason) {
|
||||
flush_reason_ = flush_reason;
|
||||
}
|
||||
FlushReason GetFlushReason() const { return flush_reason_; }
|
||||
// thread-safe
|
||||
const EnvOptions* soptions() const;
|
||||
const ImmutableCFOptions* ioptions() const { return &ioptions_; }
|
||||
@@ -247,12 +237,7 @@ class ColumnFamilyData {
|
||||
void SetCurrent(Version* _current);
|
||||
uint64_t GetNumLiveVersions() const; // REQUIRE: DB mutex held
|
||||
uint64_t GetTotalSstFilesSize() const; // REQUIRE: DB mutex held
|
||||
uint64_t GetLiveSstFilesSize() const; // REQUIRE: DB mutex held
|
||||
void SetMemtable(MemTable* new_mem) {
|
||||
uint64_t memtable_id = last_memtable_id_.fetch_add(1) + 1;
|
||||
new_mem->SetID(memtable_id);
|
||||
mem_ = new_mem;
|
||||
}
|
||||
void SetMemtable(MemTable* new_mem) { mem_ = new_mem; }
|
||||
|
||||
// calculate the oldest log needed for the durability of this column family
|
||||
uint64_t OldestLogToKeep();
|
||||
@@ -278,27 +263,17 @@ class ColumnFamilyData {
|
||||
const Slice& largest_user_key,
|
||||
int level) const;
|
||||
|
||||
// Check if the passed ranges overlap with any unflushed memtables
|
||||
// (immutable or mutable).
|
||||
//
|
||||
// @param super_version A referenced SuperVersion that will be held for the
|
||||
// duration of this function.
|
||||
//
|
||||
// Thread-safe
|
||||
Status RangesOverlapWithMemtables(const autovector<Range>& ranges,
|
||||
SuperVersion* super_version, bool* overlap);
|
||||
|
||||
// A flag to tell a manual compaction is to compact all levels together
|
||||
// instead of a specific level.
|
||||
// instad of for specific level.
|
||||
static const int kCompactAllLevels;
|
||||
// A flag to tell a manual compaction's output is base level.
|
||||
static const int kCompactToBaseLevel;
|
||||
// REQUIRES: DB mutex held
|
||||
Compaction* CompactRange(const MutableCFOptions& mutable_cf_options,
|
||||
int input_level, int output_level,
|
||||
uint32_t output_path_id, uint32_t max_subcompactions,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict);
|
||||
uint32_t output_path_id, const InternalKey* begin,
|
||||
const InternalKey* end, InternalKey** compaction_end,
|
||||
bool* manual_conflict);
|
||||
|
||||
CompactionPicker* compaction_picker() { return compaction_picker_.get(); }
|
||||
// thread-safe
|
||||
@@ -336,53 +311,32 @@ class ColumnFamilyData {
|
||||
// As argument takes a pointer to allocated SuperVersion to enable
|
||||
// the clients to allocate SuperVersion outside of mutex.
|
||||
// IMPORTANT: Only call this from DBImpl::InstallSuperVersion()
|
||||
void InstallSuperVersion(SuperVersionContext* sv_context,
|
||||
InstrumentedMutex* db_mutex,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
void InstallSuperVersion(SuperVersionContext* sv_context,
|
||||
InstrumentedMutex* db_mutex);
|
||||
SuperVersion* InstallSuperVersion(SuperVersion* new_superversion,
|
||||
InstrumentedMutex* db_mutex,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
SuperVersion* InstallSuperVersion(SuperVersion* new_superversion,
|
||||
InstrumentedMutex* db_mutex);
|
||||
|
||||
void ResetThreadLocalSuperVersions();
|
||||
|
||||
// Protected by DB mutex
|
||||
void set_queued_for_flush(bool value) { queued_for_flush_ = value; }
|
||||
void set_queued_for_compaction(bool value) { queued_for_compaction_ = value; }
|
||||
bool queued_for_flush() { return queued_for_flush_; }
|
||||
bool queued_for_compaction() { return queued_for_compaction_; }
|
||||
|
||||
enum class WriteStallCause {
|
||||
kNone,
|
||||
kMemtableLimit,
|
||||
kL0FileCountLimit,
|
||||
kPendingCompactionBytes,
|
||||
};
|
||||
static std::pair<WriteStallCondition, WriteStallCause>
|
||||
GetWriteStallConditionAndCause(int num_unflushed_memtables, int num_l0_files,
|
||||
uint64_t num_compaction_needed_bytes,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
void set_pending_flush(bool value) { pending_flush_ = value; }
|
||||
void set_pending_compaction(bool value) { pending_compaction_ = value; }
|
||||
bool pending_flush() { return pending_flush_; }
|
||||
bool pending_compaction() { return pending_compaction_; }
|
||||
|
||||
// Recalculate some small conditions, which are changed only during
|
||||
// compaction, adding new memtable and/or
|
||||
// recalculation of compaction score. These values are used in
|
||||
// DBImpl::MakeRoomForWrite function to decide, if it need to make
|
||||
// a write stall
|
||||
WriteStallCondition RecalculateWriteStallConditions(
|
||||
void RecalculateWriteStallConditions(
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
|
||||
void set_initialized() { initialized_.store(true); }
|
||||
|
||||
bool initialized() const { return initialized_.load(); }
|
||||
|
||||
const ColumnFamilyOptions& initial_cf_options() {
|
||||
return initial_cf_options_;
|
||||
}
|
||||
|
||||
Env::WriteLifeTimeHint CalculateSSTWriteHint(int level);
|
||||
|
||||
Status AddDirectories();
|
||||
|
||||
Directory* GetDataDir(size_t path_id) const;
|
||||
|
||||
private:
|
||||
friend class ColumnFamilySet;
|
||||
ColumnFamilyData(uint32_t id, const std::string& name,
|
||||
@@ -400,7 +354,7 @@ class ColumnFamilyData {
|
||||
|
||||
std::atomic<int> refs_; // outstanding references to ColumnFamilyData
|
||||
std::atomic<bool> initialized_;
|
||||
std::atomic<bool> dropped_; // true if client dropped it
|
||||
bool dropped_; // true if client dropped it
|
||||
|
||||
const InternalKeyComparator internal_comparator_;
|
||||
std::vector<std::unique_ptr<IntTblPropCollectorFactory>>
|
||||
@@ -442,8 +396,6 @@ class ColumnFamilyData {
|
||||
// recovered from
|
||||
uint64_t log_number_;
|
||||
|
||||
std::atomic<FlushReason> flush_reason_;
|
||||
|
||||
// An object that keeps all the compaction stats
|
||||
// and picks the next compaction
|
||||
std::unique_ptr<CompactionPicker> compaction_picker_;
|
||||
@@ -453,22 +405,16 @@ class ColumnFamilyData {
|
||||
std::unique_ptr<WriteControllerToken> write_controller_token_;
|
||||
|
||||
// If true --> this ColumnFamily is currently present in DBImpl::flush_queue_
|
||||
bool queued_for_flush_;
|
||||
bool pending_flush_;
|
||||
|
||||
// If true --> this ColumnFamily is currently present in
|
||||
// DBImpl::compaction_queue_
|
||||
bool queued_for_compaction_;
|
||||
bool pending_compaction_;
|
||||
|
||||
uint64_t prev_compaction_needed_bytes_;
|
||||
|
||||
// if the database was opened with 2pc enabled
|
||||
bool allow_2pc_;
|
||||
|
||||
// Memtable id to track flush.
|
||||
std::atomic<uint64_t> last_memtable_id_;
|
||||
|
||||
// Directories corresponding to cf_paths.
|
||||
std::vector<std::unique_ptr<Directory>> data_dirs_;
|
||||
};
|
||||
|
||||
// ColumnFamilySet has interesting thread-safety requirements
|
||||
|
||||
+168
-158
@@ -69,15 +69,9 @@ class ColumnFamilyTest : public testing::Test {
|
||||
}
|
||||
|
||||
~ColumnFamilyTest() {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (auto h : handles_) {
|
||||
ColumnFamilyDescriptor cfdescriptor;
|
||||
h->GetDescriptor(&cfdescriptor);
|
||||
column_families.push_back(cfdescriptor);
|
||||
}
|
||||
Close();
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
Destroy(column_families);
|
||||
Destroy();
|
||||
delete env_;
|
||||
}
|
||||
|
||||
@@ -242,11 +236,9 @@ class ColumnFamilyTest : public testing::Test {
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
void Destroy(const std::vector<ColumnFamilyDescriptor>& column_families =
|
||||
std::vector<ColumnFamilyDescriptor>()) {
|
||||
void Destroy() {
|
||||
Close();
|
||||
ASSERT_OK(DestroyDB(dbname_, Options(db_options_, column_family_options_),
|
||||
column_families));
|
||||
ASSERT_OK(DestroyDB(dbname_, Options(db_options_, column_family_options_)));
|
||||
}
|
||||
|
||||
void CreateColumnFamilies(
|
||||
@@ -299,9 +291,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
}
|
||||
|
||||
void PutRandomData(int cf, int num, int key_value_size, bool save = false) {
|
||||
if (cf >= static_cast<int>(keys_.size())) {
|
||||
keys_.resize(cf + 1);
|
||||
}
|
||||
for (int i = 0; i < num; ++i) {
|
||||
// 10 bytes for key, rest is value
|
||||
if (!save) {
|
||||
@@ -309,7 +298,7 @@ class ColumnFamilyTest : public testing::Test {
|
||||
RandomString(&rnd_, key_value_size - 10)));
|
||||
} else {
|
||||
std::string key = test::RandomKey(&rnd_, 11);
|
||||
keys_[cf].insert(key);
|
||||
keys_.insert(key);
|
||||
ASSERT_OK(Put(cf, key, RandomString(&rnd_, key_value_size - 10)));
|
||||
}
|
||||
}
|
||||
@@ -394,9 +383,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertFilesPerLevel(const std::string& value, int cf) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ(value, FilesPerLevel(cf));
|
||||
#else
|
||||
(void) value;
|
||||
(void) cf;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -411,8 +397,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertCountLiveFiles(int expected_value) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ(expected_value, CountLiveFiles());
|
||||
#else
|
||||
(void) expected_value;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -461,8 +445,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
void AssertCountLiveLogFiles(int value) {
|
||||
#ifndef ROCKSDB_LITE // GetSortedWalFiles is not supported
|
||||
ASSERT_EQ(value, CountLiveLogFiles());
|
||||
#else
|
||||
(void) value;
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
@@ -501,15 +483,9 @@ class ColumnFamilyTest : public testing::Test {
|
||||
ASSERT_OK(destfile->Close());
|
||||
}
|
||||
|
||||
int GetSstFileCount(std::string path) {
|
||||
std::vector<std::string> files;
|
||||
DBTestBase::GetSstFiles(env_, path, &files);
|
||||
return static_cast<int>(files.size());
|
||||
}
|
||||
|
||||
std::vector<ColumnFamilyHandle*> handles_;
|
||||
std::vector<std::string> names_;
|
||||
std::vector<std::set<std::string>> keys_;
|
||||
std::set<std::string> keys_;
|
||||
ColumnFamilyOptions column_family_options_;
|
||||
DBOptions db_options_;
|
||||
std::string dbname_;
|
||||
@@ -545,7 +521,6 @@ TEST_F(ColumnFamilyTest, DontReuseColumnFamilyID) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
|
||||
Open();
|
||||
|
||||
@@ -567,7 +542,6 @@ TEST_F(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
class FlushEmptyCFTestWithParam : public ColumnFamilyTest,
|
||||
public testing::WithParamInterface<bool> {
|
||||
@@ -957,62 +931,62 @@ TEST_F(ColumnFamilyTest, FlushTest) {
|
||||
TEST_F(ColumnFamilyTest, LogDeletionTest) {
|
||||
db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max();
|
||||
column_family_options_.arena_block_size = 4 * 1024;
|
||||
column_family_options_.write_buffer_size = 128000; // 128KB
|
||||
column_family_options_.write_buffer_size = 100000; // 100KB
|
||||
Open();
|
||||
CreateColumnFamilies({"one", "two", "three", "four"});
|
||||
// Each bracket is one log file. if number is in (), it means
|
||||
// we don't need it anymore (it's been flushed)
|
||||
// []
|
||||
AssertCountLiveLogFiles(0);
|
||||
PutRandomData(0, 1, 128);
|
||||
PutRandomData(0, 1, 100);
|
||||
// [0]
|
||||
PutRandomData(1, 1, 128);
|
||||
PutRandomData(1, 1, 100);
|
||||
// [0, 1]
|
||||
PutRandomData(1, 1000, 128);
|
||||
PutRandomData(1, 1000, 100);
|
||||
WaitForFlush(1);
|
||||
// [0, (1)] [1]
|
||||
AssertCountLiveLogFiles(2);
|
||||
PutRandomData(0, 1, 128);
|
||||
PutRandomData(0, 1, 100);
|
||||
// [0, (1)] [0, 1]
|
||||
AssertCountLiveLogFiles(2);
|
||||
PutRandomData(2, 1, 128);
|
||||
PutRandomData(2, 1, 100);
|
||||
// [0, (1)] [0, 1, 2]
|
||||
PutRandomData(2, 1000, 128);
|
||||
PutRandomData(2, 1000, 100);
|
||||
WaitForFlush(2);
|
||||
// [0, (1)] [0, 1, (2)] [2]
|
||||
AssertCountLiveLogFiles(3);
|
||||
PutRandomData(2, 1000, 128);
|
||||
PutRandomData(2, 1000, 100);
|
||||
WaitForFlush(2);
|
||||
// [0, (1)] [0, 1, (2)] [(2)] [2]
|
||||
AssertCountLiveLogFiles(4);
|
||||
PutRandomData(3, 1, 128);
|
||||
PutRandomData(3, 1, 100);
|
||||
// [0, (1)] [0, 1, (2)] [(2)] [2, 3]
|
||||
PutRandomData(1, 1, 128);
|
||||
PutRandomData(1, 1, 100);
|
||||
// [0, (1)] [0, 1, (2)] [(2)] [1, 2, 3]
|
||||
AssertCountLiveLogFiles(4);
|
||||
PutRandomData(1, 1000, 128);
|
||||
PutRandomData(1, 1000, 100);
|
||||
WaitForFlush(1);
|
||||
// [0, (1)] [0, (1), (2)] [(2)] [(1), 2, 3] [1]
|
||||
AssertCountLiveLogFiles(5);
|
||||
PutRandomData(0, 1000, 128);
|
||||
PutRandomData(0, 1000, 100);
|
||||
WaitForFlush(0);
|
||||
// [(0), (1)] [(0), (1), (2)] [(2)] [(1), 2, 3] [1, (0)] [0]
|
||||
// delete obsolete logs -->
|
||||
// [(1), 2, 3] [1, (0)] [0]
|
||||
AssertCountLiveLogFiles(3);
|
||||
PutRandomData(0, 1000, 128);
|
||||
PutRandomData(0, 1000, 100);
|
||||
WaitForFlush(0);
|
||||
// [(1), 2, 3] [1, (0)], [(0)] [0]
|
||||
AssertCountLiveLogFiles(4);
|
||||
PutRandomData(1, 1000, 128);
|
||||
PutRandomData(1, 1000, 100);
|
||||
WaitForFlush(1);
|
||||
// [(1), 2, 3] [(1), (0)] [(0)] [0, (1)] [1]
|
||||
AssertCountLiveLogFiles(5);
|
||||
PutRandomData(2, 1000, 128);
|
||||
PutRandomData(2, 1000, 100);
|
||||
WaitForFlush(2);
|
||||
// [(1), (2), 3] [(1), (0)] [(0)] [0, (1)] [1, (2)], [2]
|
||||
AssertCountLiveLogFiles(6);
|
||||
PutRandomData(3, 1000, 128);
|
||||
PutRandomData(3, 1000, 100);
|
||||
WaitForFlush(3);
|
||||
// [(1), (2), (3)] [(1), (0)] [(0)] [0, (1)] [1, (2)], [2, (3)] [3]
|
||||
// delete obsolete logs -->
|
||||
@@ -1192,14 +1166,13 @@ TEST_F(ColumnFamilyTest, MemtableNotSupportSnapshot) {
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
class TestComparator : public Comparator {
|
||||
int Compare(const rocksdb::Slice& /*a*/,
|
||||
const rocksdb::Slice& /*b*/) const override {
|
||||
int Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const override {
|
||||
return 0;
|
||||
}
|
||||
const char* Name() const override { return "Test"; }
|
||||
void FindShortestSeparator(std::string* /*start*/,
|
||||
const rocksdb::Slice& /*limit*/) const override {}
|
||||
void FindShortSuccessor(std::string* /*key*/) const override {}
|
||||
void FindShortestSeparator(std::string* start,
|
||||
const rocksdb::Slice& limit) const override {}
|
||||
void FindShortSuccessor(std::string* key) const override {}
|
||||
};
|
||||
|
||||
static TestComparator third_comparator;
|
||||
@@ -1371,7 +1344,7 @@ TEST_F(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
{"ColumnFamilyTest::MultiManual:2", "ColumnFamilyTest::MultiManual:5"},
|
||||
{"ColumnFamilyTest::MultiManual:2", "ColumnFamilyTest::MultiManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::MultiManual:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1417,8 +1390,8 @@ TEST_F(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
CompactAll(2);
|
||||
AssertFilesPerLevel("0,1", 2);
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1464,7 +1437,7 @@ TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
{"ColumnFamilyTest::AutoManual:2", "ColumnFamilyTest::AutoManual:5"},
|
||||
{"ColumnFamilyTest::AutoManual:2", "ColumnFamilyTest::AutoManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
cf_1_1 = false;
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:4");
|
||||
@@ -1511,8 +1484,8 @@ TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
CompactAll(2);
|
||||
AssertFilesPerLevel("0,1", 2);
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1565,7 +1538,7 @@ TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
{"ColumnFamilyTest::ManualAuto:5", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:2", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1607,8 +1580,8 @@ TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
CompactAll(2);
|
||||
AssertFilesPerLevel("0,1", 2);
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1658,7 +1631,7 @@ TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
{"ColumnFamilyTest::ManualManual:1",
|
||||
"ColumnFamilyTest::ManualManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualManual:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1706,8 +1679,8 @@ TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
ASSERT_LE(NumTableFilesAtLevel(0, 1), 2);
|
||||
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1756,7 +1729,7 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1796,8 +1769,8 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
ASSERT_LE(NumTableFilesAtLevel(0, 1), 2);
|
||||
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1848,7 +1821,7 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
"ColumnFamilyTest::ManualAuto:3"},
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1886,8 +1859,128 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
AssertFilesPerLevel("0,1", 1);
|
||||
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// This test checks for automatic getting a conflict if there is a
|
||||
// manual which has not yet been scheduled.
|
||||
// The manual compaction waits in NotScheduled
|
||||
// We generate more files and then trigger an automatic compaction
|
||||
// This will wait because there is an unscheduled manual compaction.
|
||||
// Once the conflict is hit, the manual compaction starts and ends
|
||||
// Then another automatic will start and end.
|
||||
TEST_F(ColumnFamilyTest, SameCFManualAutomaticConflict) {
|
||||
Open();
|
||||
CreateColumnFamilies({"one"});
|
||||
ColumnFamilyOptions default_cf, one;
|
||||
db_options_.max_open_files = 20; // only 10 files in file cache
|
||||
db_options_.max_background_compactions = 3;
|
||||
|
||||
default_cf.compaction_style = kCompactionStyleLevel;
|
||||
default_cf.num_levels = 3;
|
||||
default_cf.write_buffer_size = 64 << 10; // 64KB
|
||||
default_cf.target_file_size_base = 30 << 10;
|
||||
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.no_block_cache = true;
|
||||
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
one.compaction_style = kCompactionStyleUniversal;
|
||||
|
||||
one.num_levels = 1;
|
||||
// trigger compaction if there are >= 4 files
|
||||
one.level0_file_num_compaction_trigger = 4;
|
||||
one.write_buffer_size = 120000;
|
||||
|
||||
Reopen({default_cf, one});
|
||||
// make sure all background compaction jobs can be scheduled
|
||||
auto stop_token =
|
||||
dbfull()->TEST_write_controler().GetCompactionPressureToken();
|
||||
|
||||
// SETUP column family "one" -- universal style
|
||||
for (int i = 0; i < one.level0_file_num_compaction_trigger - 2; ++i) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::BackgroundCompaction()::Conflict",
|
||||
"ColumnFamilyTest::ManualAutoCon:7"},
|
||||
{"ColumnFamilyTest::ManualAutoCon:9",
|
||||
"ColumnFamilyTest::ManualAutoCon:8"},
|
||||
{"ColumnFamilyTest::ManualAutoCon:2",
|
||||
"ColumnFamilyTest::ManualAutoCon:6"},
|
||||
{"ColumnFamilyTest::ManualAutoCon:4",
|
||||
"ColumnFamilyTest::ManualAutoCon:5"},
|
||||
{"ColumnFamilyTest::ManualAutoCon:1",
|
||||
"ColumnFamilyTest::ManualAutoCon:2"},
|
||||
{"ColumnFamilyTest::ManualAutoCon:1",
|
||||
"ColumnFamilyTest::ManualAutoCon:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:4");
|
||||
cf_1_1 = false;
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:3");
|
||||
} else if (cf_1_2) {
|
||||
cf_1_2 = false;
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:2");
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::RunManualCompaction:NotScheduled", [&](void* arg) {
|
||||
InstrumentedMutex* mutex = static_cast<InstrumentedMutex*>(arg);
|
||||
mutex->Unlock();
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:9");
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:7");
|
||||
mutex->Lock();
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
rocksdb::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
db_->CompactRange(compact_options, handles_[1], nullptr, nullptr));
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:6");
|
||||
});
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:8");
|
||||
WaitForFlush(1);
|
||||
|
||||
// Add more L0 files and force automatic compaction
|
||||
for (int i = 0; i < one.level0_file_num_compaction_trigger; ++i) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(ToString(one.level0_file_num_compaction_trigger + i),
|
||||
1);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:5");
|
||||
// Add more L0 files and force automatic compaction
|
||||
for (int i = 0; i < one.level0_file_num_compaction_trigger; ++i) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
}
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAutoCon:1");
|
||||
|
||||
threads.join();
|
||||
WaitForCompaction();
|
||||
// VERIFY compaction "one"
|
||||
ASSERT_LE(NumTableFilesAtLevel(0, 1), 3);
|
||||
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -1935,7 +2028,7 @@ TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
{"CompactionPicker::CompactRange:Conflict",
|
||||
"ColumnFamilyTest::AutoManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* arg) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:4");
|
||||
cf_1_1 = false;
|
||||
@@ -1975,8 +2068,8 @@ TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
// VERIFY compaction "one"
|
||||
AssertFilesPerLevel("1", 1);
|
||||
// Compare against saved keys
|
||||
std::set<std::string>::iterator key_iter = keys_[1].begin();
|
||||
while (key_iter != keys_[1].end()) {
|
||||
std::set<std::string>::iterator key_iter = keys_.begin();
|
||||
while (key_iter != keys_.end()) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
@@ -2382,7 +2475,7 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
|
||||
auto main_thread_id = std::this_thread::get_id();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack("PersistRocksDBOptions:start",
|
||||
[&](void* /*arg*/) {
|
||||
[&](void* arg) {
|
||||
auto current_thread_id = std::this_thread::get_id();
|
||||
// If it's the main thread hitting this sync-point, then it
|
||||
// will be blocked until some other thread update the test_stage.
|
||||
@@ -2395,7 +2488,7 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::EnterUnbatched:Wait", [&](void* /*arg*/) {
|
||||
"WriteThread::EnterUnbatched:Wait", [&](void* arg) {
|
||||
// This means a thread doing DropColumnFamily() is waiting for
|
||||
// other thread to finish persisting options.
|
||||
// In such case, we update the test_stage to unblock the main thread.
|
||||
@@ -2815,18 +2908,6 @@ TEST_F(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
}
|
||||
|
||||
TEST_F(ColumnFamilyTest, CreateAndDestoryOptions) {
|
||||
std::unique_ptr<ColumnFamilyOptions> cfo(new ColumnFamilyOptions());
|
||||
ColumnFamilyHandle* cfh;
|
||||
Open();
|
||||
ASSERT_OK(db_->CreateColumnFamily(*(cfo.get()), "yoyo", &cfh));
|
||||
cfo.reset();
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfh, "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions(), cfh));
|
||||
ASSERT_OK(db_->DropColumnFamily(cfh));
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(ColumnFamilyTest, FlushCloseWALFiles) {
|
||||
SpecialEnv env(Env::Default());
|
||||
@@ -3153,77 +3234,6 @@ TEST_F(ColumnFamilyTest, DISABLED_LogTruncationTest) {
|
||||
// cleanup
|
||||
env_->DeleteDir(backup_logs);
|
||||
}
|
||||
|
||||
TEST_F(ColumnFamilyTest, DefaultCfPathsTest) {
|
||||
Open();
|
||||
// Leave cf_paths for one column families to be empty.
|
||||
// Files should be generated according to db_paths for that
|
||||
// column family.
|
||||
ColumnFamilyOptions cf_opt1, cf_opt2;
|
||||
cf_opt1.cf_paths.emplace_back(dbname_ + "_one_1",
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
CreateColumnFamilies({"one", "two"}, {cf_opt1, cf_opt2});
|
||||
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
|
||||
|
||||
// Fill Column family 1.
|
||||
PutRandomData(1, 100, 100);
|
||||
Flush(1);
|
||||
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt1.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
// Fill column family 2
|
||||
PutRandomData(2, 100, 100);
|
||||
Flush(2);
|
||||
|
||||
// SST from Column family 2 should be generated in
|
||||
// db_paths which is dbname_ in this case.
|
||||
ASSERT_EQ(1, GetSstFileCount(dbname_));
|
||||
}
|
||||
|
||||
TEST_F(ColumnFamilyTest, MultipleCFPathsTest) {
|
||||
Open();
|
||||
// Configure Column family specific paths.
|
||||
ColumnFamilyOptions cf_opt1, cf_opt2;
|
||||
cf_opt1.cf_paths.emplace_back(dbname_ + "_one_1",
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
cf_opt2.cf_paths.emplace_back(dbname_ + "_two_1",
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
CreateColumnFamilies({"one", "two"}, {cf_opt1, cf_opt2});
|
||||
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
|
||||
|
||||
PutRandomData(1, 100, 100, true /* save */);
|
||||
Flush(1);
|
||||
|
||||
// Check that files are generated in appropriate paths.
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt1.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
PutRandomData(2, 100, 100, true /* save */);
|
||||
Flush(2);
|
||||
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt2.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
// Re-open and verify the keys.
|
||||
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
for (int cf = 1; cf != 3; ++cf) {
|
||||
ReadOptions read_options;
|
||||
read_options.readahead_size = 0;
|
||||
auto it = dbi->NewIterator(read_options, handles_[cf]);
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
Slice key(it->key());
|
||||
ASSERT_NE(keys_[cf].end(), keys_[cf].find(key.ToString()));
|
||||
}
|
||||
delete it;
|
||||
|
||||
for (const auto& key : keys_[cf]) {
|
||||
ASSERT_NE("NOT_FOUND", Get(cf, key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -37,7 +37,8 @@ class FlushedFileCollector : public EventListener {
|
||||
FlushedFileCollector() {}
|
||||
~FlushedFileCollector() {}
|
||||
|
||||
virtual void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override {
|
||||
virtual void OnFlushCompleted(
|
||||
DB* db, const FlushJobInfo& info) override {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
flushed_files_.push_back(info.file_path);
|
||||
}
|
||||
@@ -256,9 +257,9 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
TEST_F(CompactFilesTest, CompactionFilterWithGetSv) {
|
||||
class FilterWithGet : public CompactionFilter {
|
||||
public:
|
||||
virtual bool Filter(int /*level*/, const Slice& /*key*/,
|
||||
const Slice& /*value*/, std::string* /*new_value*/,
|
||||
bool* /*value_changed*/) const override {
|
||||
virtual bool Filter(int level, const Slice& key, const Slice& value,
|
||||
std::string* new_value,
|
||||
bool* value_changed) const override {
|
||||
if (db_ == nullptr) {
|
||||
return true;
|
||||
}
|
||||
@@ -318,7 +319,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as DBImpl::CompactFiles is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
@@ -17,8 +17,7 @@ extern bool SaveValue(void* arg, const ParsedInternalKey& parsed_key,
|
||||
|
||||
CompactedDBImpl::CompactedDBImpl(
|
||||
const DBOptions& options, const std::string& dbname)
|
||||
: DBImpl(options, dbname), cfd_(nullptr), version_(nullptr),
|
||||
user_comparator_(nullptr) {
|
||||
: DBImpl(options, dbname) {
|
||||
}
|
||||
|
||||
CompactedDBImpl::~CompactedDBImpl() {
|
||||
@@ -49,8 +48,8 @@ Status CompactedDBImpl::Get(const ReadOptions& options, ColumnFamilyHandle*,
|
||||
GetContext::kNotFound, key, value, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
LookupKey lkey(key, kMaxSequenceNumber);
|
||||
files_.files[FindFile(key)].fd.table_reader->Get(options, lkey.internal_key(),
|
||||
&get_context, nullptr);
|
||||
files_.files[FindFile(key)].fd.table_reader->Get(
|
||||
options, lkey.internal_key(), &get_context);
|
||||
if (get_context.State() == GetContext::kFound) {
|
||||
return Status::OK();
|
||||
}
|
||||
@@ -82,7 +81,7 @@ std::vector<Status> CompactedDBImpl::MultiGet(const ReadOptions& options,
|
||||
GetContext::kNotFound, keys[idx], &pinnable_val,
|
||||
nullptr, nullptr, nullptr, nullptr);
|
||||
LookupKey lkey(keys[idx], kMaxSequenceNumber);
|
||||
r->Get(options, lkey.internal_key(), &get_context, nullptr);
|
||||
r->Get(options, lkey.internal_key(), &get_context);
|
||||
value.assign(pinnable_val.data(), pinnable_val.size());
|
||||
if (get_context.State() == GetContext::kFound) {
|
||||
statuses[idx] = Status::OK();
|
||||
@@ -94,7 +93,6 @@ std::vector<Status> CompactedDBImpl::MultiGet(const ReadOptions& options,
|
||||
}
|
||||
|
||||
Status CompactedDBImpl::Init(const Options& options) {
|
||||
SuperVersionContext sv_context(/* create_superversion */ true);
|
||||
mutex_.Lock();
|
||||
ColumnFamilyDescriptor cf(kDefaultColumnFamilyName,
|
||||
ColumnFamilyOptions(options));
|
||||
@@ -102,10 +100,9 @@ Status CompactedDBImpl::Init(const Options& options) {
|
||||
if (s.ok()) {
|
||||
cfd_ = reinterpret_cast<ColumnFamilyHandleImpl*>(
|
||||
DefaultColumnFamily())->cfd();
|
||||
cfd_->InstallSuperVersion(&sv_context, &mutex_);
|
||||
delete cfd_->InstallSuperVersion(new SuperVersion(), &mutex_);
|
||||
}
|
||||
mutex_.Unlock();
|
||||
sv_context.Clean();
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
+22
-23
@@ -32,56 +32,55 @@ class CompactedDBImpl : public DBImpl {
|
||||
override;
|
||||
|
||||
using DBImpl::Put;
|
||||
virtual Status Put(const WriteOptions& /*options*/,
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const Slice& /*key*/, const Slice& /*value*/) override {
|
||||
virtual Status Put(const WriteOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
const Slice& value) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
using DBImpl::Merge;
|
||||
virtual Status Merge(const WriteOptions& /*options*/,
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const Slice& /*key*/, const Slice& /*value*/) override {
|
||||
virtual Status Merge(const WriteOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
const Slice& value) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
using DBImpl::Delete;
|
||||
virtual Status Delete(const WriteOptions& /*options*/,
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const Slice& /*key*/) override {
|
||||
virtual Status Delete(const WriteOptions& options,
|
||||
ColumnFamilyHandle* column_family,
|
||||
const Slice& key) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
virtual Status Write(const WriteOptions& /*options*/,
|
||||
WriteBatch* /*updates*/) override {
|
||||
virtual Status Write(const WriteOptions& options,
|
||||
WriteBatch* updates) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
using DBImpl::CompactRange;
|
||||
virtual Status CompactRange(const CompactRangeOptions& /*options*/,
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const Slice* /*begin*/,
|
||||
const Slice* /*end*/) override {
|
||||
virtual Status CompactRange(const CompactRangeOptions& options,
|
||||
ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
|
||||
virtual Status DisableFileDeletions() override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
virtual Status EnableFileDeletions(bool /*force*/) override {
|
||||
virtual Status EnableFileDeletions(bool force) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* /*manifest_file_size*/,
|
||||
bool /*flush_memtable*/ = true) override {
|
||||
uint64_t* manifest_file_size,
|
||||
bool flush_memtable = true) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
using DBImpl::Flush;
|
||||
virtual Status Flush(const FlushOptions& /*options*/,
|
||||
ColumnFamilyHandle* /*column_family*/) override {
|
||||
virtual Status Flush(const FlushOptions& options,
|
||||
ColumnFamilyHandle* column_family) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
using DB::IngestExternalFile;
|
||||
virtual Status IngestExternalFile(
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
const std::vector<std::string>& /*external_files*/,
|
||||
const IngestExternalFileOptions& /*ingestion_options*/) override {
|
||||
ColumnFamilyHandle* column_family,
|
||||
const std::vector<std::string>& external_files,
|
||||
const IngestExternalFileOptions& ingestion_options) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
|
||||
|
||||
+45
-46
@@ -86,23 +86,35 @@ void Compaction::GetBoundaryKeys(
|
||||
bool Compaction::IsBottommostLevel(
|
||||
int output_level, VersionStorageInfo* vstorage,
|
||||
const std::vector<CompactionInputFiles>& inputs) {
|
||||
int output_l0_idx;
|
||||
if (output_level == 0) {
|
||||
output_l0_idx = 0;
|
||||
for (const auto* file : vstorage->LevelFiles(0)) {
|
||||
if (inputs[0].files.back() == file) {
|
||||
break;
|
||||
}
|
||||
++output_l0_idx;
|
||||
}
|
||||
assert(static_cast<size_t>(output_l0_idx) < vstorage->LevelFiles(0).size());
|
||||
} else {
|
||||
output_l0_idx = -1;
|
||||
if (inputs[0].level == 0 &&
|
||||
inputs[0].files.back() != vstorage->LevelFiles(0).back()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Slice smallest_key, largest_key;
|
||||
GetBoundaryKeys(vstorage, inputs, &smallest_key, &largest_key);
|
||||
return !vstorage->RangeMightExistAfterSortedRun(smallest_key, largest_key,
|
||||
output_level, output_l0_idx);
|
||||
|
||||
// Checks whether there are files living beyond the output_level.
|
||||
// If lower levels have files, it checks for overlap between files
|
||||
// if the compaction process and those files.
|
||||
// Bottomlevel optimizations can be made if there are no files in
|
||||
// lower levels or if there is no overlap with the files in
|
||||
// the lower levels.
|
||||
for (int i = output_level + 1; i < vstorage->num_levels(); i++) {
|
||||
// It is not the bottommost level if there are files in higher
|
||||
// levels when the output level is 0 or if there are files in
|
||||
// higher levels which overlap with files to be compacted.
|
||||
// output_level == 0 means that we want it to be considered
|
||||
// s the bottommost level only if the last file on the level
|
||||
// is a part of the files to be compacted - this is verified by
|
||||
// the first if condition in this function
|
||||
if (vstorage->NumLevelFiles(i) > 0 &&
|
||||
(output_level == 0 ||
|
||||
vstorage->OverlapInLevel(i, &smallest_key, &largest_key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// test function to validate the functionality of IsBottommostLevel()
|
||||
@@ -134,7 +146,6 @@ Compaction::Compaction(VersionStorageInfo* vstorage,
|
||||
int _output_level, uint64_t _target_file_size,
|
||||
uint64_t _max_compaction_bytes, uint32_t _output_path_id,
|
||||
CompressionType _compression,
|
||||
uint32_t _max_subcompactions,
|
||||
std::vector<FileMetaData*> _grandparents,
|
||||
bool _manual_compaction, double _score,
|
||||
bool _deletion_compaction,
|
||||
@@ -144,7 +155,6 @@ Compaction::Compaction(VersionStorageInfo* vstorage,
|
||||
output_level_(_output_level),
|
||||
max_output_file_size_(_target_file_size),
|
||||
max_compaction_bytes_(_max_compaction_bytes),
|
||||
max_subcompactions_(_max_subcompactions),
|
||||
immutable_cf_options_(_immutable_cf_options),
|
||||
mutable_cf_options_(_mutable_cf_options),
|
||||
input_version_(nullptr),
|
||||
@@ -159,15 +169,11 @@ Compaction::Compaction(VersionStorageInfo* vstorage,
|
||||
bottommost_level_(IsBottommostLevel(output_level_, vstorage, inputs_)),
|
||||
is_full_compaction_(IsFullCompaction(vstorage, inputs_)),
|
||||
is_manual_compaction_(_manual_compaction),
|
||||
is_trivial_move_(false),
|
||||
compaction_reason_(_compaction_reason) {
|
||||
MarkFilesBeingCompacted(true);
|
||||
if (is_manual_compaction_) {
|
||||
compaction_reason_ = CompactionReason::kManualCompaction;
|
||||
}
|
||||
if (max_subcompactions_ == 0) {
|
||||
max_subcompactions_ = immutable_cf_options_.max_subcompactions;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 1; i < inputs_.size(); ++i) {
|
||||
@@ -234,7 +240,7 @@ bool Compaction::IsTrivialMove() const {
|
||||
|
||||
// Used in universal compaction, where trivial move can be done if the
|
||||
// input files are non overlapping
|
||||
if ((mutable_cf_options_.compaction_options_universal.allow_trivial_move) &&
|
||||
if ((immutable_cf_options_.compaction_options_universal.allow_trivial_move) &&
|
||||
(output_level_ != 0)) {
|
||||
return is_trivial_move_;
|
||||
}
|
||||
@@ -277,10 +283,10 @@ bool Compaction::KeyNotExistsBeyondOutputLevel(
|
||||
assert(input_version_ != nullptr);
|
||||
assert(level_ptrs != nullptr);
|
||||
assert(level_ptrs->size() == static_cast<size_t>(number_levels_));
|
||||
if (bottommost_level_) {
|
||||
return true;
|
||||
} else if (output_level_ != 0 &&
|
||||
cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
|
||||
if (cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
|
||||
if (output_level_ == 0) {
|
||||
return false;
|
||||
}
|
||||
// Maybe use binary search to find right entry instead of linear search?
|
||||
const Comparator* user_cmp = cfd_->user_comparator();
|
||||
for (int lvl = output_level_ + 1; lvl < number_levels_; lvl++) {
|
||||
@@ -300,8 +306,9 @@ bool Compaction::KeyNotExistsBeyondOutputLevel(
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return bottommost_level_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark (or clear) each file that is being compacted
|
||||
@@ -410,23 +417,20 @@ void Compaction::Summary(char* output, int len) {
|
||||
uint64_t Compaction::OutputFilePreallocationSize() const {
|
||||
uint64_t preallocation_size = 0;
|
||||
|
||||
for (const auto& level_files : inputs_) {
|
||||
for (const auto& file : level_files.files) {
|
||||
preallocation_size += file->fd.GetFileSize();
|
||||
if (max_output_file_size_ != port::kMaxUint64 &&
|
||||
(cfd_->ioptions()->compaction_style == kCompactionStyleLevel ||
|
||||
output_level() > 0)) {
|
||||
preallocation_size = max_output_file_size_;
|
||||
} else {
|
||||
for (const auto& level_files : inputs_) {
|
||||
for (const auto& file : level_files.files) {
|
||||
preallocation_size += file->fd.GetFileSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max_output_file_size_ != port::kMaxUint64 &&
|
||||
(immutable_cf_options_.compaction_style == kCompactionStyleLevel ||
|
||||
output_level() > 0)) {
|
||||
preallocation_size = std::min(max_output_file_size_, preallocation_size);
|
||||
}
|
||||
|
||||
// Over-estimate slightly so we don't end up just barely crossing
|
||||
// the threshold
|
||||
// No point to prellocate more than 1GB.
|
||||
return std::min(uint64_t{1073741824},
|
||||
preallocation_size + (preallocation_size / 10));
|
||||
return preallocation_size + (preallocation_size / 10);
|
||||
}
|
||||
|
||||
std::unique_ptr<CompactionFilter> Compaction::CreateCompactionFilter() const {
|
||||
@@ -447,12 +451,11 @@ bool Compaction::IsOutputLevelEmpty() const {
|
||||
}
|
||||
|
||||
bool Compaction::ShouldFormSubcompactions() const {
|
||||
if (max_subcompactions_ <= 1 || cfd_ == nullptr) {
|
||||
if (immutable_cf_options_.max_subcompactions <= 1 || cfd_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
|
||||
return (start_level_ == 0 || is_manual_compaction_) && output_level_ > 0 &&
|
||||
!IsOutputLevelEmpty();
|
||||
return start_level_ == 0 && output_level_ > 0 && !IsOutputLevelEmpty();
|
||||
} else if (cfd_->ioptions()->compaction_style == kCompactionStyleUniversal) {
|
||||
return number_levels_ > 1 && output_level_ > 0;
|
||||
} else {
|
||||
@@ -473,8 +476,4 @@ uint64_t Compaction::MaxInputFileCreationTime() const {
|
||||
return max_creation_time;
|
||||
}
|
||||
|
||||
int Compaction::GetInputBaseLevel() const {
|
||||
return input_vstorage_->base_level();
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -40,7 +40,6 @@ class Compaction {
|
||||
std::vector<CompactionInputFiles> inputs, int output_level,
|
||||
uint64_t target_file_size, uint64_t max_compaction_bytes,
|
||||
uint32_t output_path_id, CompressionType compression,
|
||||
uint32_t max_subcompactions,
|
||||
std::vector<FileMetaData*> grandparents,
|
||||
bool manual_compaction = false, double score = -1,
|
||||
bool deletion_compaction = false,
|
||||
@@ -234,8 +233,6 @@ class Compaction {
|
||||
|
||||
Slice GetLargestUserKey() const { return largest_user_key_; }
|
||||
|
||||
int GetInputBaseLevel() const;
|
||||
|
||||
CompactionReason compaction_reason() { return compaction_reason_; }
|
||||
|
||||
const std::vector<FileMetaData*>& grandparents() const {
|
||||
@@ -244,8 +241,6 @@ class Compaction {
|
||||
|
||||
uint64_t max_compaction_bytes() const { return max_compaction_bytes_; }
|
||||
|
||||
uint32_t max_subcompactions() const { return max_subcompactions_; }
|
||||
|
||||
uint64_t MaxInputFileCreationTime() const;
|
||||
|
||||
private:
|
||||
@@ -272,7 +267,6 @@ class Compaction {
|
||||
const int output_level_; // levels to which output files are stored
|
||||
uint64_t max_output_file_size_;
|
||||
uint64_t max_compaction_bytes_;
|
||||
uint32_t max_subcompactions_;
|
||||
const ImmutableCFOptions immutable_cf_options_;
|
||||
const MutableCFOptions mutable_cf_options_;
|
||||
Version* input_version_;
|
||||
|
||||
@@ -16,8 +16,6 @@ struct CompactionIterationStats {
|
||||
int64_t num_record_drop_obsolete = 0;
|
||||
int64_t num_record_drop_range_del = 0;
|
||||
int64_t num_range_del_drop_obsolete = 0;
|
||||
// Deletions obsoleted before bottom level due to file gap optimization.
|
||||
int64_t num_optimized_del_drop_obsolete = 0;
|
||||
uint64_t total_filter_time = 0;
|
||||
|
||||
// Input statistics
|
||||
|
||||
+120
-169
@@ -4,59 +4,75 @@
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/compaction_iterator.h"
|
||||
|
||||
#include "db/snapshot_checker.h"
|
||||
#include "port/likely.h"
|
||||
#include "rocksdb/listener.h"
|
||||
#include "table/internal_iterator.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
CompactionIterator::CompactionIterator(
|
||||
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
|
||||
SequenceNumber last_sequence, std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker, Env* env,
|
||||
bool expect_valid_internal_key, RangeDelAggregator* range_del_agg,
|
||||
const Compaction* compaction, const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum)
|
||||
: CompactionIterator(
|
||||
input, cmp, merge_helper, last_sequence, snapshots,
|
||||
earliest_write_conflict_snapshot, snapshot_checker, env,
|
||||
expect_valid_internal_key, range_del_agg,
|
||||
std::unique_ptr<CompactionProxy>(
|
||||
compaction ? new CompactionProxy(compaction) : nullptr),
|
||||
compaction_filter, shutting_down, preserve_deletes_seqnum) {}
|
||||
#ifndef ROCKSDB_LITE
|
||||
CompactionEventListener::CompactionListenerValueType fromInternalValueType(
|
||||
ValueType vt) {
|
||||
switch (vt) {
|
||||
case kTypeDeletion:
|
||||
return CompactionEventListener::CompactionListenerValueType::kDelete;
|
||||
case kTypeValue:
|
||||
return CompactionEventListener::CompactionListenerValueType::kValue;
|
||||
case kTypeMerge:
|
||||
return CompactionEventListener::CompactionListenerValueType::
|
||||
kMergeOperand;
|
||||
case kTypeSingleDeletion:
|
||||
return CompactionEventListener::CompactionListenerValueType::
|
||||
kSingleDelete;
|
||||
case kTypeRangeDeletion:
|
||||
return CompactionEventListener::CompactionListenerValueType::kRangeDelete;
|
||||
default:
|
||||
assert(false);
|
||||
return CompactionEventListener::CompactionListenerValueType::kInvalid;
|
||||
}
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
CompactionIterator::CompactionIterator(
|
||||
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
|
||||
SequenceNumber /*last_sequence*/, std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker, Env* env,
|
||||
SequenceNumber last_sequence, std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot, Env* env,
|
||||
bool expect_valid_internal_key, RangeDelAggregator* range_del_agg,
|
||||
const Compaction* compaction, const CompactionFilter* compaction_filter,
|
||||
CompactionEventListener* compaction_listener,
|
||||
const std::atomic<bool>* shutting_down)
|
||||
: CompactionIterator(
|
||||
input, cmp, merge_helper, last_sequence, snapshots,
|
||||
earliest_write_conflict_snapshot, env, expect_valid_internal_key,
|
||||
range_del_agg,
|
||||
std::unique_ptr<CompactionProxy>(
|
||||
compaction ? new CompactionProxy(compaction) : nullptr),
|
||||
compaction_filter, compaction_listener, shutting_down) {}
|
||||
|
||||
CompactionIterator::CompactionIterator(
|
||||
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
|
||||
SequenceNumber last_sequence, std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot, Env* env,
|
||||
bool expect_valid_internal_key, RangeDelAggregator* range_del_agg,
|
||||
std::unique_ptr<CompactionProxy> compaction,
|
||||
const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum)
|
||||
CompactionEventListener* compaction_listener,
|
||||
const std::atomic<bool>* shutting_down)
|
||||
: input_(input),
|
||||
cmp_(cmp),
|
||||
merge_helper_(merge_helper),
|
||||
snapshots_(snapshots),
|
||||
earliest_write_conflict_snapshot_(earliest_write_conflict_snapshot),
|
||||
snapshot_checker_(snapshot_checker),
|
||||
env_(env),
|
||||
expect_valid_internal_key_(expect_valid_internal_key),
|
||||
range_del_agg_(range_del_agg),
|
||||
compaction_(std::move(compaction)),
|
||||
compaction_filter_(compaction_filter),
|
||||
#ifndef ROCKSDB_LITE
|
||||
compaction_listener_(compaction_listener),
|
||||
#endif // ROCKSDB_LITE
|
||||
shutting_down_(shutting_down),
|
||||
preserve_deletes_seqnum_(preserve_deletes_seqnum),
|
||||
ignore_snapshots_(false),
|
||||
current_user_key_sequence_(0),
|
||||
current_user_key_snapshot_(0),
|
||||
merge_out_iter_(merge_helper_),
|
||||
current_key_committed_(false) {
|
||||
merge_out_iter_(merge_helper_) {
|
||||
assert(compaction_filter_ == nullptr || compaction_ != nullptr);
|
||||
bottommost_level_ =
|
||||
compaction_ == nullptr ? false : compaction_->bottommost_level();
|
||||
@@ -95,7 +111,6 @@ void CompactionIterator::ResetRecordCounts() {
|
||||
iter_stats_.num_record_drop_obsolete = 0;
|
||||
iter_stats_.num_record_drop_range_del = 0;
|
||||
iter_stats_.num_range_del_drop_obsolete = 0;
|
||||
iter_stats_.num_optimized_del_drop_obsolete = 0;
|
||||
}
|
||||
|
||||
void CompactionIterator::SeekToFirst() {
|
||||
@@ -113,8 +128,8 @@ void CompactionIterator::Next() {
|
||||
if (merge_out_iter_.Valid()) {
|
||||
key_ = merge_out_iter_.key();
|
||||
value_ = merge_out_iter_.value();
|
||||
bool valid_key __attribute__((__unused__));
|
||||
valid_key = ParseInternalKey(key_, &ikey_);
|
||||
bool valid_key __attribute__((__unused__)) =
|
||||
ParseInternalKey(key_, &ikey_);
|
||||
// MergeUntil stops when it encounters a corrupt key and does not
|
||||
// include them in the result, so we expect the keys here to be valid.
|
||||
assert(valid_key);
|
||||
@@ -148,64 +163,6 @@ void CompactionIterator::Next() {
|
||||
PrepareOutput();
|
||||
}
|
||||
|
||||
void CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
|
||||
Slice* skip_until) {
|
||||
if (compaction_filter_ != nullptr &&
|
||||
(ikey_.type == kTypeValue || ikey_.type == kTypeBlobIndex) &&
|
||||
(visible_at_tip_ || ignore_snapshots_ ||
|
||||
ikey_.sequence > latest_snapshot_ ||
|
||||
(snapshot_checker_ != nullptr &&
|
||||
UNLIKELY(!snapshot_checker_->IsInSnapshot(ikey_.sequence,
|
||||
latest_snapshot_))))) {
|
||||
// If the user has specified a compaction filter and the sequence
|
||||
// number is greater than any external snapshot, then invoke the
|
||||
// filter. If the return value of the compaction filter is true,
|
||||
// replace the entry with a deletion marker.
|
||||
CompactionFilter::Decision filter;
|
||||
compaction_filter_value_.clear();
|
||||
compaction_filter_skip_until_.Clear();
|
||||
CompactionFilter::ValueType value_type =
|
||||
ikey_.type == kTypeValue ? CompactionFilter::ValueType::kValue
|
||||
: CompactionFilter::ValueType::kBlobIndex;
|
||||
// Hack: pass internal key to BlobIndexCompactionFilter since it needs
|
||||
// to get sequence number.
|
||||
Slice& filter_key = ikey_.type == kTypeValue ? ikey_.user_key : key_;
|
||||
{
|
||||
StopWatchNano timer(env_, true);
|
||||
filter = compaction_filter_->FilterV2(
|
||||
compaction_->level(), filter_key, value_type, value_,
|
||||
&compaction_filter_value_, compaction_filter_skip_until_.rep());
|
||||
iter_stats_.total_filter_time +=
|
||||
env_ != nullptr ? timer.ElapsedNanos() : 0;
|
||||
}
|
||||
|
||||
if (filter == CompactionFilter::Decision::kRemoveAndSkipUntil &&
|
||||
cmp_->Compare(*compaction_filter_skip_until_.rep(), ikey_.user_key) <=
|
||||
0) {
|
||||
// Can't skip to a key smaller than the current one.
|
||||
// Keep the key as per FilterV2 documentation.
|
||||
filter = CompactionFilter::Decision::kKeep;
|
||||
}
|
||||
|
||||
if (filter == CompactionFilter::Decision::kRemove) {
|
||||
// convert the current key to a delete; key_ is pointing into
|
||||
// current_key_ at this point, so updating current_key_ updates key()
|
||||
ikey_.type = kTypeDeletion;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, kTypeDeletion);
|
||||
// no value associated with delete
|
||||
value_.clear();
|
||||
iter_stats_.num_record_drop_user++;
|
||||
} else if (filter == CompactionFilter::Decision::kChangeValue) {
|
||||
value_ = compaction_filter_value_;
|
||||
} else if (filter == CompactionFilter::Decision::kRemoveAndSkipUntil) {
|
||||
*need_skip = true;
|
||||
compaction_filter_skip_until_.ConvertFromUserKey(kMaxSequenceNumber,
|
||||
kValueTypeForSeek);
|
||||
*skip_until = compaction_filter_skip_until_.Encode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompactionIterator::NextFromInput() {
|
||||
at_next_ = false;
|
||||
valid_ = false;
|
||||
@@ -260,16 +217,70 @@ void CompactionIterator::NextFromInput() {
|
||||
has_outputted_key_ = false;
|
||||
current_user_key_sequence_ = kMaxSequenceNumber;
|
||||
current_user_key_snapshot_ = 0;
|
||||
current_key_committed_ =
|
||||
(snapshot_checker_ == nullptr ||
|
||||
snapshot_checker_->IsInSnapshot(ikey_.sequence, kMaxSequenceNumber));
|
||||
|
||||
// Apply the compaction filter to the first committed version of the user
|
||||
// key.
|
||||
if (current_key_committed_) {
|
||||
InvokeFilterIfNeeded(&need_skip, &skip_until);
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (compaction_listener_) {
|
||||
compaction_listener_->OnCompaction(compaction_->level(), ikey_.user_key,
|
||||
fromInternalValueType(ikey_.type),
|
||||
value_, ikey_.sequence, true);
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// apply the compaction filter to the first occurrence of the user key
|
||||
if (compaction_filter_ != nullptr && ikey_.type == kTypeValue &&
|
||||
(visible_at_tip_ || ikey_.sequence > latest_snapshot_ ||
|
||||
ignore_snapshots_)) {
|
||||
// If the user has specified a compaction filter and the sequence
|
||||
// number is greater than any external snapshot, then invoke the
|
||||
// filter. If the return value of the compaction filter is true,
|
||||
// replace the entry with a deletion marker.
|
||||
CompactionFilter::Decision filter;
|
||||
compaction_filter_value_.clear();
|
||||
compaction_filter_skip_until_.Clear();
|
||||
{
|
||||
StopWatchNano timer(env_, true);
|
||||
filter = compaction_filter_->FilterV2(
|
||||
compaction_->level(), ikey_.user_key,
|
||||
CompactionFilter::ValueType::kValue, value_,
|
||||
&compaction_filter_value_, compaction_filter_skip_until_.rep());
|
||||
iter_stats_.total_filter_time +=
|
||||
env_ != nullptr ? timer.ElapsedNanos() : 0;
|
||||
}
|
||||
|
||||
if (filter == CompactionFilter::Decision::kRemoveAndSkipUntil &&
|
||||
cmp_->Compare(*compaction_filter_skip_until_.rep(),
|
||||
ikey_.user_key) <= 0) {
|
||||
// Can't skip to a key smaller than the current one.
|
||||
// Keep the key as per FilterV2 documentation.
|
||||
filter = CompactionFilter::Decision::kKeep;
|
||||
}
|
||||
|
||||
if (filter == CompactionFilter::Decision::kRemove) {
|
||||
// convert the current key to a delete; key_ is pointing into
|
||||
// current_key_ at this point, so updating current_key_ updates key()
|
||||
ikey_.type = kTypeDeletion;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, kTypeDeletion);
|
||||
// no value associated with delete
|
||||
value_.clear();
|
||||
iter_stats_.num_record_drop_user++;
|
||||
} else if (filter == CompactionFilter::Decision::kChangeValue) {
|
||||
value_ = compaction_filter_value_;
|
||||
} else if (filter == CompactionFilter::Decision::kRemoveAndSkipUntil) {
|
||||
need_skip = true;
|
||||
compaction_filter_skip_until_.ConvertFromUserKey(kMaxSequenceNumber,
|
||||
kValueTypeForSeek);
|
||||
skip_until = compaction_filter_skip_until_.Encode();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (compaction_listener_) {
|
||||
compaction_listener_->OnCompaction(compaction_->level(), ikey_.user_key,
|
||||
fromInternalValueType(ikey_.type),
|
||||
value_, ikey_.sequence, false);
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Update the current key to reflect the new sequence number/type without
|
||||
// copying the user key.
|
||||
// TODO(rven): Compaction filter does not process keys in this path
|
||||
@@ -278,33 +289,13 @@ void CompactionIterator::NextFromInput() {
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
key_ = current_key_.GetInternalKey();
|
||||
ikey_.user_key = current_key_.GetUserKey();
|
||||
|
||||
// Note that newer version of a key is ordered before older versions. If a
|
||||
// newer version of a key is committed, so as the older version. No need
|
||||
// to query snapshot_checker_ in that case.
|
||||
if (UNLIKELY(!current_key_committed_)) {
|
||||
assert(snapshot_checker_ != nullptr);
|
||||
current_key_committed_ =
|
||||
snapshot_checker_->IsInSnapshot(ikey_.sequence, kMaxSequenceNumber);
|
||||
// Apply the compaction filter to the first committed version of the
|
||||
// user key.
|
||||
if (current_key_committed_) {
|
||||
InvokeFilterIfNeeded(&need_skip, &skip_until);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(!current_key_committed_)) {
|
||||
assert(snapshot_checker_ != nullptr);
|
||||
valid_ = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If there are no snapshots, then this kv affect visibility at tip.
|
||||
// Otherwise, search though all existing snapshots to find the earliest
|
||||
// snapshot that is affected by this kv.
|
||||
SequenceNumber last_sequence __attribute__((__unused__));
|
||||
last_sequence = current_user_key_sequence_;
|
||||
SequenceNumber last_sequence __attribute__((__unused__)) =
|
||||
current_user_key_sequence_;
|
||||
current_user_key_sequence_ = ikey_.sequence;
|
||||
SequenceNumber last_snapshot = current_user_key_snapshot_;
|
||||
SequenceNumber prev_snapshot = 0; // 0 means no previous snapshot
|
||||
@@ -369,10 +360,7 @@ void CompactionIterator::NextFromInput() {
|
||||
cmp_->Equal(ikey_.user_key, next_ikey.user_key)) {
|
||||
// Check whether the next key belongs to the same snapshot as the
|
||||
// SingleDelete.
|
||||
if (prev_snapshot == 0 || next_ikey.sequence > prev_snapshot ||
|
||||
(snapshot_checker_ != nullptr &&
|
||||
UNLIKELY(!snapshot_checker_->IsInSnapshot(next_ikey.sequence,
|
||||
prev_snapshot)))) {
|
||||
if (prev_snapshot == 0 || next_ikey.sequence > prev_snapshot) {
|
||||
if (next_ikey.type == kTypeSingleDeletion) {
|
||||
// We encountered two SingleDeletes in a row. This could be due to
|
||||
// unexpected user input.
|
||||
@@ -383,12 +371,8 @@ void CompactionIterator::NextFromInput() {
|
||||
// input_->Next().
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
++iter_stats_.num_single_del_mismatch;
|
||||
} else if (has_outputted_key_ ||
|
||||
(ikey_.sequence <= earliest_write_conflict_snapshot_ &&
|
||||
(snapshot_checker_ == nullptr ||
|
||||
LIKELY(snapshot_checker_->IsInSnapshot(
|
||||
ikey_.sequence,
|
||||
earliest_write_conflict_snapshot_))))) {
|
||||
} else if ((ikey_.sequence <= earliest_write_conflict_snapshot_) ||
|
||||
has_outputted_key_) {
|
||||
// Found a matching value, we can drop the single delete and the
|
||||
// value. It is safe to drop both records since we've already
|
||||
// outputted a key in this snapshot, or there is no earlier
|
||||
@@ -436,18 +420,12 @@ void CompactionIterator::NextFromInput() {
|
||||
// comparison, so the value of has_current_user_key does not matter.
|
||||
has_current_user_key_ = false;
|
||||
if (compaction_ != nullptr && ikey_.sequence <= earliest_snapshot_ &&
|
||||
(snapshot_checker_ == nullptr ||
|
||||
LIKELY(snapshot_checker_->IsInSnapshot(ikey_.sequence,
|
||||
earliest_snapshot_))) &&
|
||||
compaction_->KeyNotExistsBeyondOutputLevel(ikey_.user_key,
|
||||
&level_ptrs_)) {
|
||||
// Key doesn't exist outside of this range.
|
||||
// Can compact out this SingleDelete.
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
++iter_stats_.num_single_del_fallthru;
|
||||
if (!bottommost_level_) {
|
||||
++iter_stats_.num_optimized_del_drop_obsolete;
|
||||
}
|
||||
} else {
|
||||
// Output SingleDelete
|
||||
valid_ = true;
|
||||
@@ -472,10 +450,6 @@ void CompactionIterator::NextFromInput() {
|
||||
input_->Next();
|
||||
} else if (compaction_ != nullptr && ikey_.type == kTypeDeletion &&
|
||||
ikey_.sequence <= earliest_snapshot_ &&
|
||||
(snapshot_checker_ == nullptr ||
|
||||
LIKELY(snapshot_checker_->IsInSnapshot(ikey_.sequence,
|
||||
earliest_snapshot_))) &&
|
||||
ikeyNotNeededForIncrementalSnapshot() &&
|
||||
compaction_->KeyNotExistsBeyondOutputLevel(ikey_.user_key,
|
||||
&level_ptrs_)) {
|
||||
// TODO(noetzli): This is the only place where we use compaction_
|
||||
@@ -492,15 +466,7 @@ void CompactionIterator::NextFromInput() {
|
||||
//
|
||||
// Note: Dropping this Delete will not affect TransactionDB
|
||||
// write-conflict checking since it is earlier than any snapshot.
|
||||
//
|
||||
// It seems that we can also drop deletion later than earliest snapshot
|
||||
// given that:
|
||||
// (1) The deletion is earlier than earliest_write_conflict_snapshot, and
|
||||
// (2) No value exist earlier than the deletion.
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
if (!bottommost_level_) {
|
||||
++iter_stats_.num_optimized_del_drop_obsolete;
|
||||
}
|
||||
input_->Next();
|
||||
} else if (ikey_.type == kTypeMerge) {
|
||||
if (!merge_helper_->HasOperator()) {
|
||||
@@ -526,8 +492,8 @@ void CompactionIterator::NextFromInput() {
|
||||
// These will be correctly set below.
|
||||
key_ = merge_out_iter_.key();
|
||||
value_ = merge_out_iter_.value();
|
||||
bool valid_key __attribute__((__unused__));
|
||||
valid_key = ParseInternalKey(key_, &ikey_);
|
||||
bool valid_key __attribute__((__unused__)) =
|
||||
ParseInternalKey(key_, &ikey_);
|
||||
// MergeUntil stops when it encounters a corrupt key and does not
|
||||
// include them in the result, so we expect the keys here to valid.
|
||||
assert(valid_key);
|
||||
@@ -577,18 +543,11 @@ void CompactionIterator::PrepareOutput() {
|
||||
// and the earliest snapshot is larger than this seqno
|
||||
// and the userkey differs from the last userkey in compaction
|
||||
// then we can squash the seqno to zero.
|
||||
//
|
||||
|
||||
// This is safe for TransactionDB write-conflict checking since transactions
|
||||
// only care about sequence number larger than any active snapshots.
|
||||
//
|
||||
// Can we do the same for levels above bottom level as long as
|
||||
// KeyNotExistsBeyondOutputLevel() return true?
|
||||
if ((compaction_ != nullptr &&
|
||||
!compaction_->allow_ingest_behind()) &&
|
||||
ikeyNotNeededForIncrementalSnapshot() &&
|
||||
if ((compaction_ != nullptr && !compaction_->allow_ingest_behind()) &&
|
||||
bottommost_level_ && valid_ && ikey_.sequence <= earliest_snapshot_ &&
|
||||
(snapshot_checker_ == nullptr || LIKELY(snapshot_checker_->IsInSnapshot(
|
||||
ikey_.sequence, earliest_snapshot_))) &&
|
||||
ikey_.type != kTypeMerge &&
|
||||
!cmp_->Equal(compaction_->GetLargestUserKey(), ikey_.user_key)) {
|
||||
assert(ikey_.type != kTypeDeletion && ikey_.type != kTypeSingleDeletion);
|
||||
@@ -600,11 +559,10 @@ void CompactionIterator::PrepareOutput() {
|
||||
inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot(
|
||||
SequenceNumber in, SequenceNumber* prev_snapshot) {
|
||||
assert(snapshots_->size());
|
||||
SequenceNumber prev = kMaxSequenceNumber;
|
||||
SequenceNumber prev __attribute__((__unused__)) = kMaxSequenceNumber;
|
||||
for (const auto cur : *snapshots_) {
|
||||
assert(prev == kMaxSequenceNumber || prev <= cur);
|
||||
if (cur >= in && (snapshot_checker_ == nullptr ||
|
||||
snapshot_checker_->IsInSnapshot(in, cur))) {
|
||||
if (cur >= in) {
|
||||
*prev_snapshot = prev == kMaxSequenceNumber ? 0 : prev;
|
||||
return cur;
|
||||
}
|
||||
@@ -615,11 +573,4 @@ inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot(
|
||||
return kMaxSequenceNumber;
|
||||
}
|
||||
|
||||
// used in 2 places - prevents deletion markers to be dropped if they may be
|
||||
// needed and disables seqnum zero-out in PrepareOutput for recent keys.
|
||||
inline bool CompactionIterator::ikeyNotNeededForIncrementalSnapshot() {
|
||||
return (!compaction_->preserve_deletes()) ||
|
||||
(ikey_.sequence < preserve_deletes_seqnum_);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
+12
-27
@@ -14,12 +14,13 @@
|
||||
#include "db/merge_helper.h"
|
||||
#include "db/pinned_iterators_manager.h"
|
||||
#include "db/range_del_aggregator.h"
|
||||
#include "db/snapshot_checker.h"
|
||||
#include "options/cf_options.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class CompactionEventListener;
|
||||
|
||||
class CompactionIterator {
|
||||
public:
|
||||
// A wrapper around Compaction. Has a much smaller interface, only what
|
||||
@@ -30,7 +31,7 @@ class CompactionIterator {
|
||||
: compaction_(compaction) {}
|
||||
|
||||
virtual ~CompactionProxy() = default;
|
||||
virtual int level(size_t /*compaction_input_level*/ = 0) const {
|
||||
virtual int level(size_t compaction_input_level = 0) const {
|
||||
return compaction_->level();
|
||||
}
|
||||
virtual bool KeyNotExistsBeyondOutputLevel(
|
||||
@@ -47,9 +48,6 @@ class CompactionIterator {
|
||||
virtual bool allow_ingest_behind() const {
|
||||
return compaction_->immutable_cf_options()->allow_ingest_behind;
|
||||
}
|
||||
virtual bool preserve_deletes() const {
|
||||
return compaction_->immutable_cf_options()->preserve_deletes;
|
||||
}
|
||||
|
||||
protected:
|
||||
CompactionProxy() = default;
|
||||
@@ -61,27 +59,25 @@ class CompactionIterator {
|
||||
CompactionIterator(InternalIterator* input, const Comparator* cmp,
|
||||
MergeHelper* merge_helper, SequenceNumber last_sequence,
|
||||
std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker, Env* env,
|
||||
SequenceNumber earliest_write_conflict_snapshot, Env* env,
|
||||
bool expect_valid_internal_key,
|
||||
RangeDelAggregator* range_del_agg,
|
||||
const Compaction* compaction = nullptr,
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
const SequenceNumber preserve_deletes_seqnum = 0);
|
||||
CompactionEventListener* compaction_listener = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr);
|
||||
|
||||
// Constructor with custom CompactionProxy, used for tests.
|
||||
CompactionIterator(InternalIterator* input, const Comparator* cmp,
|
||||
MergeHelper* merge_helper, SequenceNumber last_sequence,
|
||||
std::vector<SequenceNumber>* snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker, Env* env,
|
||||
SequenceNumber earliest_write_conflict_snapshot, Env* env,
|
||||
bool expect_valid_internal_key,
|
||||
RangeDelAggregator* range_del_agg,
|
||||
std::unique_ptr<CompactionProxy> compaction,
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
const SequenceNumber preserve_deletes_seqnum = 0);
|
||||
CompactionEventListener* compaction_listener = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr);
|
||||
|
||||
~CompactionIterator();
|
||||
|
||||
@@ -115,9 +111,6 @@ class CompactionIterator {
|
||||
// compression.
|
||||
void PrepareOutput();
|
||||
|
||||
// Invoke compaction filter if needed.
|
||||
void InvokeFilterIfNeeded(bool* need_skip, Slice* skip_until);
|
||||
|
||||
// Given a sequence number, return the sequence number of the
|
||||
// earliest snapshot that this sequence number is visible in.
|
||||
// The snapshots themselves are arranged in ascending order of
|
||||
@@ -127,24 +120,20 @@ class CompactionIterator {
|
||||
inline SequenceNumber findEarliestVisibleSnapshot(
|
||||
SequenceNumber in, SequenceNumber* prev_snapshot);
|
||||
|
||||
// Checks whether the currently seen ikey_ is needed for
|
||||
// incremental (differential) snapshot and hence can't be dropped
|
||||
// or seqnum be zero-ed out even if all other conditions for it are met.
|
||||
inline bool ikeyNotNeededForIncrementalSnapshot();
|
||||
|
||||
InternalIterator* input_;
|
||||
const Comparator* cmp_;
|
||||
MergeHelper* merge_helper_;
|
||||
const std::vector<SequenceNumber>* snapshots_;
|
||||
const SequenceNumber earliest_write_conflict_snapshot_;
|
||||
const SnapshotChecker* const snapshot_checker_;
|
||||
Env* env_;
|
||||
bool expect_valid_internal_key_;
|
||||
RangeDelAggregator* range_del_agg_;
|
||||
std::unique_ptr<CompactionProxy> compaction_;
|
||||
const CompactionFilter* compaction_filter_;
|
||||
#ifndef ROCKSDB_LITE
|
||||
CompactionEventListener* compaction_listener_;
|
||||
#endif // ROCKSDB_LITE
|
||||
const std::atomic<bool>* shutting_down_;
|
||||
const SequenceNumber preserve_deletes_seqnum_;
|
||||
bool bottommost_level_;
|
||||
bool valid_ = false;
|
||||
bool visible_at_tip_;
|
||||
@@ -200,10 +189,6 @@ class CompactionIterator {
|
||||
std::vector<size_t> level_ptrs_;
|
||||
CompactionIterationStats iter_stats_;
|
||||
|
||||
// Used to avoid purging uncommitted values. The application can specify
|
||||
// uncommitted values by providing a SnapshotChecker object.
|
||||
bool current_key_committed_;
|
||||
|
||||
bool IsShuttingDown() {
|
||||
// This is a best-effort facility, so memory_order_relaxed is sufficient.
|
||||
return shutting_down_ && shutting_down_->load(std::memory_order_relaxed);
|
||||
|
||||
+44
-535
@@ -9,25 +9,23 @@
|
||||
#include <vector>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/testharness.h"
|
||||
#include "util/testutil.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// Expects no merging attempts.
|
||||
class NoMergingMergeOp : public MergeOperator {
|
||||
public:
|
||||
bool FullMergeV2(const MergeOperationInput& /*merge_in*/,
|
||||
MergeOperationOutput* /*merge_out*/) const override {
|
||||
bool FullMergeV2(const MergeOperationInput& merge_in,
|
||||
MergeOperationOutput* merge_out) const override {
|
||||
ADD_FAILURE();
|
||||
return false;
|
||||
}
|
||||
bool PartialMergeMulti(const Slice& /*key*/,
|
||||
const std::deque<Slice>& /*operand_list*/,
|
||||
std::string* /*new_value*/,
|
||||
Logger* /*logger*/) const override {
|
||||
bool PartialMergeMulti(const Slice& key,
|
||||
const std::deque<Slice>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* logger) const override {
|
||||
ADD_FAILURE();
|
||||
return false;
|
||||
}
|
||||
@@ -41,9 +39,9 @@ class NoMergingMergeOp : public MergeOperator {
|
||||
// Always returns Decition::kRemove.
|
||||
class StallingFilter : public CompactionFilter {
|
||||
public:
|
||||
Decision FilterV2(int /*level*/, const Slice& key, ValueType /*type*/,
|
||||
const Slice& /*existing_value*/, std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
virtual Decision FilterV2(int level, const Slice& key, ValueType t,
|
||||
const Slice& existing_value, std::string* new_value,
|
||||
std::string* skip_until) const override {
|
||||
int k = std::atoi(key.ToString().c_str());
|
||||
last_seen.store(k);
|
||||
while (k >= stall_at.load()) {
|
||||
@@ -74,18 +72,6 @@ class StallingFilter : public CompactionFilter {
|
||||
mutable std::atomic<int> last_seen{0};
|
||||
};
|
||||
|
||||
// Compaction filter that filter out all keys.
|
||||
class FilterAllKeysCompactionFilter : public CompactionFilter {
|
||||
public:
|
||||
Decision FilterV2(int /*level*/, const Slice& /*key*/, ValueType /*type*/,
|
||||
const Slice& /*existing_value*/, std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
return Decision::kRemove;
|
||||
}
|
||||
|
||||
const char* Name() const override { return "AllKeysCompactionFilter"; }
|
||||
};
|
||||
|
||||
class LoggingForwardVectorIterator : public InternalIterator {
|
||||
public:
|
||||
struct Action {
|
||||
@@ -126,7 +112,7 @@ class LoggingForwardVectorIterator : public InternalIterator {
|
||||
keys_.begin();
|
||||
}
|
||||
|
||||
virtual void SeekForPrev(const Slice& /*target*/) override { assert(false); }
|
||||
virtual void SeekForPrev(const Slice& target) override { assert(false); }
|
||||
|
||||
virtual void Next() override {
|
||||
assert(Valid());
|
||||
@@ -158,149 +144,71 @@ class FakeCompaction : public CompactionIterator::CompactionProxy {
|
||||
public:
|
||||
FakeCompaction() = default;
|
||||
|
||||
virtual int level(size_t /*compaction_input_level*/) const override {
|
||||
return 0;
|
||||
}
|
||||
virtual int level(size_t compaction_input_level) const { return 0; }
|
||||
virtual bool KeyNotExistsBeyondOutputLevel(
|
||||
const Slice& /*user_key*/,
|
||||
std::vector<size_t>* /*level_ptrs*/) const override {
|
||||
return is_bottommost_level || key_not_exists_beyond_output_level;
|
||||
const Slice& user_key, std::vector<size_t>* level_ptrs) const {
|
||||
return key_not_exists_beyond_output_level;
|
||||
}
|
||||
virtual bool bottommost_level() const override { return is_bottommost_level; }
|
||||
virtual int number_levels() const override { return 1; }
|
||||
virtual Slice GetLargestUserKey() const override {
|
||||
virtual bool bottommost_level() const { return false; }
|
||||
virtual int number_levels() const { return 1; }
|
||||
virtual Slice GetLargestUserKey() const {
|
||||
return "\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||
}
|
||||
virtual bool allow_ingest_behind() const override { return false; }
|
||||
|
||||
virtual bool preserve_deletes() const override { return false; }
|
||||
virtual bool allow_ingest_behind() const { return false; }
|
||||
|
||||
bool key_not_exists_beyond_output_level = false;
|
||||
|
||||
bool is_bottommost_level = false;
|
||||
};
|
||||
|
||||
// A simplifed snapshot checker which assumes each snapshot has a global
|
||||
// last visible sequence.
|
||||
class TestSnapshotChecker : public SnapshotChecker {
|
||||
public:
|
||||
explicit TestSnapshotChecker(
|
||||
SequenceNumber last_committed_sequence,
|
||||
const std::unordered_map<SequenceNumber, SequenceNumber>& snapshots = {})
|
||||
: last_committed_sequence_(last_committed_sequence),
|
||||
snapshots_(snapshots) {}
|
||||
|
||||
bool IsInSnapshot(SequenceNumber seq,
|
||||
SequenceNumber snapshot_seq) const override {
|
||||
if (snapshot_seq == kMaxSequenceNumber) {
|
||||
return seq <= last_committed_sequence_;
|
||||
}
|
||||
assert(snapshots_.count(snapshot_seq) > 0);
|
||||
return seq <= snapshots_.at(snapshot_seq);
|
||||
}
|
||||
|
||||
private:
|
||||
SequenceNumber last_committed_sequence_;
|
||||
// A map of valid snapshot to last visible sequence to the snapshot.
|
||||
std::unordered_map<SequenceNumber, SequenceNumber> snapshots_;
|
||||
};
|
||||
|
||||
// Test param:
|
||||
// bool: whether to pass snapshot_checker to compaction iterator.
|
||||
class CompactionIteratorTest : public testing::TestWithParam<bool> {
|
||||
class CompactionIteratorTest : public testing::Test {
|
||||
public:
|
||||
CompactionIteratorTest()
|
||||
: cmp_(BytewiseComparator()), icmp_(cmp_), snapshots_({}) {}
|
||||
|
||||
void InitIterators(
|
||||
const std::vector<std::string>& ks, const std::vector<std::string>& vs,
|
||||
const std::vector<std::string>& range_del_ks,
|
||||
const std::vector<std::string>& range_del_vs,
|
||||
SequenceNumber last_sequence,
|
||||
SequenceNumber last_committed_sequence = kMaxSequenceNumber,
|
||||
MergeOperator* merge_op = nullptr, CompactionFilter* filter = nullptr,
|
||||
bool bottommost_level = false,
|
||||
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber) {
|
||||
void InitIterators(const std::vector<std::string>& ks,
|
||||
const std::vector<std::string>& vs,
|
||||
const std::vector<std::string>& range_del_ks,
|
||||
const std::vector<std::string>& range_del_vs,
|
||||
SequenceNumber last_sequence,
|
||||
MergeOperator* merge_op = nullptr,
|
||||
CompactionFilter* filter = nullptr) {
|
||||
std::unique_ptr<InternalIterator> range_del_iter(
|
||||
new test::VectorIterator(range_del_ks, range_del_vs));
|
||||
range_del_agg_.reset(new RangeDelAggregator(icmp_, snapshots_));
|
||||
ASSERT_OK(range_del_agg_->AddTombstones(std::move(range_del_iter)));
|
||||
|
||||
std::unique_ptr<CompactionIterator::CompactionProxy> compaction;
|
||||
if (filter || bottommost_level) {
|
||||
if (filter) {
|
||||
compaction_proxy_ = new FakeCompaction();
|
||||
compaction_proxy_->is_bottommost_level = bottommost_level;
|
||||
compaction.reset(compaction_proxy_);
|
||||
}
|
||||
bool use_snapshot_checker = UseSnapshotChecker() || GetParam();
|
||||
if (use_snapshot_checker || last_committed_sequence < kMaxSequenceNumber) {
|
||||
snapshot_checker_.reset(
|
||||
new TestSnapshotChecker(last_committed_sequence, snapshot_map_));
|
||||
}
|
||||
merge_helper_.reset(
|
||||
new MergeHelper(Env::Default(), cmp_, merge_op, filter, nullptr, false,
|
||||
0 /*latest_snapshot*/, snapshot_checker_.get(),
|
||||
0 /*level*/, nullptr /*statistics*/, &shutting_down_));
|
||||
|
||||
merge_helper_.reset(new MergeHelper(Env::Default(), cmp_, merge_op, filter,
|
||||
nullptr, false, 0, 0, nullptr,
|
||||
&shutting_down_));
|
||||
iter_.reset(new LoggingForwardVectorIterator(ks, vs));
|
||||
iter_->SeekToFirst();
|
||||
c_iter_.reset(new CompactionIterator(
|
||||
iter_.get(), cmp_, merge_helper_.get(), last_sequence, &snapshots_,
|
||||
earliest_write_conflict_snapshot, snapshot_checker_.get(),
|
||||
Env::Default(), false, range_del_agg_.get(), std::move(compaction),
|
||||
filter, &shutting_down_));
|
||||
kMaxSequenceNumber, Env::Default(), false, range_del_agg_.get(),
|
||||
std::move(compaction), filter, nullptr, &shutting_down_));
|
||||
}
|
||||
|
||||
void AddSnapshot(SequenceNumber snapshot,
|
||||
SequenceNumber last_visible_seq = kMaxSequenceNumber) {
|
||||
snapshots_.push_back(snapshot);
|
||||
snapshot_map_[snapshot] = last_visible_seq;
|
||||
}
|
||||
|
||||
virtual bool UseSnapshotChecker() const { return false; }
|
||||
|
||||
void RunTest(
|
||||
const std::vector<std::string>& input_keys,
|
||||
const std::vector<std::string>& input_values,
|
||||
const std::vector<std::string>& expected_keys,
|
||||
const std::vector<std::string>& expected_values,
|
||||
SequenceNumber last_committed_seq = kMaxSequenceNumber,
|
||||
MergeOperator* merge_operator = nullptr,
|
||||
CompactionFilter* compaction_filter = nullptr,
|
||||
bool bottommost_level = false,
|
||||
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber) {
|
||||
InitIterators(input_keys, input_values, {}, {}, kMaxSequenceNumber,
|
||||
last_committed_seq, merge_operator, compaction_filter,
|
||||
bottommost_level, earliest_write_conflict_snapshot);
|
||||
c_iter_->SeekToFirst();
|
||||
for (size_t i = 0; i < expected_keys.size(); i++) {
|
||||
std::string info = "i = " + ToString(i);
|
||||
ASSERT_TRUE(c_iter_->Valid()) << info;
|
||||
ASSERT_OK(c_iter_->status()) << info;
|
||||
ASSERT_EQ(expected_keys[i], c_iter_->key().ToString()) << info;
|
||||
ASSERT_EQ(expected_values[i], c_iter_->value().ToString()) << info;
|
||||
c_iter_->Next();
|
||||
}
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
void AddSnapshot(SequenceNumber snapshot) { snapshots_.push_back(snapshot); }
|
||||
|
||||
const Comparator* cmp_;
|
||||
const InternalKeyComparator icmp_;
|
||||
std::vector<SequenceNumber> snapshots_;
|
||||
// A map of valid snapshot to last visible sequence to the snapshot.
|
||||
std::unordered_map<SequenceNumber, SequenceNumber> snapshot_map_;
|
||||
std::unique_ptr<MergeHelper> merge_helper_;
|
||||
std::unique_ptr<LoggingForwardVectorIterator> iter_;
|
||||
std::unique_ptr<CompactionIterator> c_iter_;
|
||||
std::unique_ptr<RangeDelAggregator> range_del_agg_;
|
||||
std::unique_ptr<SnapshotChecker> snapshot_checker_;
|
||||
std::atomic<bool> shutting_down_{false};
|
||||
FakeCompaction* compaction_proxy_;
|
||||
};
|
||||
|
||||
// It is possible that the output of the compaction iterator is empty even if
|
||||
// the input is not.
|
||||
TEST_P(CompactionIteratorTest, EmptyResult) {
|
||||
TEST_F(CompactionIteratorTest, EmptyResult) {
|
||||
InitIterators({test::KeyStr("a", 5, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 3, kTypeValue)},
|
||||
{"", "val"}, {}, {}, 5);
|
||||
@@ -310,7 +218,7 @@ TEST_P(CompactionIteratorTest, EmptyResult) {
|
||||
|
||||
// If there is a corruption after a single deletion, the corrupted key should
|
||||
// be preserved.
|
||||
TEST_P(CompactionIteratorTest, CorruptionAfterSingleDeletion) {
|
||||
TEST_F(CompactionIteratorTest, CorruptionAfterSingleDeletion) {
|
||||
InitIterators({test::KeyStr("a", 5, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 3, kTypeValue, true),
|
||||
test::KeyStr("b", 10, kTypeValue)},
|
||||
@@ -329,7 +237,7 @@ TEST_P(CompactionIteratorTest, CorruptionAfterSingleDeletion) {
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, SimpleRangeDeletion) {
|
||||
TEST_F(CompactionIteratorTest, SimpleRangeDeletion) {
|
||||
InitIterators({test::KeyStr("morning", 5, kTypeValue),
|
||||
test::KeyStr("morning", 2, kTypeValue),
|
||||
test::KeyStr("night", 3, kTypeValue)},
|
||||
@@ -345,7 +253,7 @@ TEST_P(CompactionIteratorTest, SimpleRangeDeletion) {
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, RangeDeletionWithSnapshots) {
|
||||
TEST_F(CompactionIteratorTest, RangeDeletionWithSnapshots) {
|
||||
AddSnapshot(10);
|
||||
std::vector<std::string> ks1;
|
||||
ks1.push_back(test::KeyStr("ma", 28, kTypeRangeDeletion));
|
||||
@@ -366,11 +274,11 @@ TEST_P(CompactionIteratorTest, RangeDeletionWithSnapshots) {
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
TEST_F(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
class Filter : public CompactionFilter {
|
||||
virtual Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
|
||||
virtual Decision FilterV2(int level, const Slice& key, ValueType t,
|
||||
const Slice& existing_value,
|
||||
std::string* /*new_value*/,
|
||||
std::string* new_value,
|
||||
std::string* skip_until) const override {
|
||||
std::string k = key.ToString();
|
||||
std::string v = existing_value.ToString();
|
||||
@@ -441,7 +349,7 @@ TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
test::KeyStr("j", 99, kTypeValue)},
|
||||
{"av50", "am45", "bv60", "bv40", "cv35", "dm70", "em71", "fm65", "fm30",
|
||||
"fv25", "gv90", "hv91", "im95", "jv99"},
|
||||
{}, {}, kMaxSequenceNumber, kMaxSequenceNumber, &merge_op, &filter);
|
||||
{}, {}, kMaxSequenceNumber, &merge_op, &filter);
|
||||
|
||||
// Compaction should output just "a", "e" and "h" keys.
|
||||
c_iter_->SeekToFirst();
|
||||
@@ -476,14 +384,13 @@ TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
ASSERT_EQ(expected_actions, iter_->log);
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, ShuttingDownInFilter) {
|
||||
TEST_F(CompactionIteratorTest, ShuttingDownInFilter) {
|
||||
NoMergingMergeOp merge_op;
|
||||
StallingFilter filter;
|
||||
InitIterators(
|
||||
{test::KeyStr("1", 1, kTypeValue), test::KeyStr("2", 2, kTypeValue),
|
||||
test::KeyStr("3", 3, kTypeValue), test::KeyStr("4", 4, kTypeValue)},
|
||||
{"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
|
||||
&merge_op, &filter);
|
||||
{"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, &merge_op, &filter);
|
||||
// Don't leave tombstones (kTypeDeletion) for filtered keys.
|
||||
compaction_proxy_->key_not_exists_beyond_output_level = true;
|
||||
|
||||
@@ -514,14 +421,13 @@ TEST_P(CompactionIteratorTest, ShuttingDownInFilter) {
|
||||
|
||||
// Same as ShuttingDownInFilter, but shutdown happens during filter call for
|
||||
// a merge operand, not for a value.
|
||||
TEST_P(CompactionIteratorTest, ShuttingDownInMerge) {
|
||||
TEST_F(CompactionIteratorTest, ShuttingDownInMerge) {
|
||||
NoMergingMergeOp merge_op;
|
||||
StallingFilter filter;
|
||||
InitIterators(
|
||||
{test::KeyStr("1", 1, kTypeValue), test::KeyStr("2", 2, kTypeMerge),
|
||||
test::KeyStr("3", 3, kTypeMerge), test::KeyStr("4", 4, kTypeValue)},
|
||||
{"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
|
||||
&merge_op, &filter);
|
||||
{"v1", "v2", "v3", "v4"}, {}, {}, kMaxSequenceNumber, &merge_op, &filter);
|
||||
compaction_proxy_->key_not_exists_beyond_output_level = true;
|
||||
|
||||
std::atomic<bool> seek_done{false};
|
||||
@@ -549,403 +455,6 @@ TEST_P(CompactionIteratorTest, ShuttingDownInMerge) {
|
||||
EXPECT_EQ(2, filter.last_seen.load());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, SingleMergeOperand) {
|
||||
class Filter : public CompactionFilter {
|
||||
virtual Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
|
||||
const Slice& existing_value,
|
||||
std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
std::string k = key.ToString();
|
||||
std::string v = existing_value.ToString();
|
||||
|
||||
// See InitIterators() call below for the sequence of keys and their
|
||||
// filtering decisions. Here we closely assert that compaction filter is
|
||||
// called with the expected keys and only them, and with the right values.
|
||||
if (k == "a") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
EXPECT_EQ("av1", v);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "b") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "c") {
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
ADD_FAILURE();
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest.SingleMergeOperand::Filter";
|
||||
}
|
||||
};
|
||||
|
||||
class SingleMergeOp : public MergeOperator {
|
||||
public:
|
||||
bool FullMergeV2(const MergeOperationInput& merge_in,
|
||||
MergeOperationOutput* merge_out) const override {
|
||||
// See InitIterators() call below for why "c" is the only key for which
|
||||
// FullMergeV2 should be called.
|
||||
EXPECT_EQ("c", merge_in.key.ToString());
|
||||
|
||||
std::string temp_value;
|
||||
if (merge_in.existing_value != nullptr) {
|
||||
temp_value = merge_in.existing_value->ToString();
|
||||
}
|
||||
|
||||
for (auto& operand : merge_in.operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
merge_out->new_value = temp_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PartialMergeMulti(const Slice& key,
|
||||
const std::deque<Slice>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* /*logger*/) const override {
|
||||
std::string string_key = key.ToString();
|
||||
EXPECT_TRUE(string_key == "a" || string_key == "b");
|
||||
|
||||
if (string_key == "a") {
|
||||
EXPECT_EQ(1, operand_list.size());
|
||||
} else if (string_key == "b") {
|
||||
EXPECT_EQ(2, operand_list.size());
|
||||
}
|
||||
|
||||
std::string temp_value;
|
||||
for (auto& operand : operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
swap(temp_value, *new_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest SingleMergeOp";
|
||||
}
|
||||
|
||||
bool AllowSingleOperand() const override { return true; }
|
||||
};
|
||||
|
||||
SingleMergeOp merge_op;
|
||||
Filter filter;
|
||||
InitIterators(
|
||||
// a should invoke PartialMergeMulti with a single merge operand.
|
||||
{test::KeyStr("a", 50, kTypeMerge),
|
||||
// b should invoke PartialMergeMulti with two operands.
|
||||
test::KeyStr("b", 70, kTypeMerge), test::KeyStr("b", 60, kTypeMerge),
|
||||
// c should invoke FullMerge due to kTypeValue at the beginning.
|
||||
test::KeyStr("c", 90, kTypeMerge), test::KeyStr("c", 80, kTypeValue)},
|
||||
{"av1", "bv2", "bv1", "cv2", "cv1"}, {}, {}, kMaxSequenceNumber,
|
||||
kMaxSequenceNumber, &merge_op, &filter);
|
||||
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("a", 50, kTypeMerge), c_iter_->key().ToString());
|
||||
ASSERT_EQ("av1", c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ("bv1bv2", c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_EQ("cv1cv2", c_iter_->value().ToString());
|
||||
}
|
||||
|
||||
// In bottommost level, values earlier than earliest snapshot can be output
|
||||
// with sequence = 0.
|
||||
TEST_P(CompactionIteratorTest, ZeroOutSequenceAtBottomLevel) {
|
||||
AddSnapshot(1);
|
||||
RunTest({test::KeyStr("a", 1, kTypeValue), test::KeyStr("b", 2, kTypeValue)},
|
||||
{"v1", "v2"},
|
||||
{test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 2, kTypeValue)},
|
||||
{"v1", "v2"}, kMaxSequenceNumber /*last_commited_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
// In bottommost level, deletions earlier than earliest snapshot can be removed
|
||||
// permanently.
|
||||
TEST_P(CompactionIteratorTest, RemoveDeletionAtBottomLevel) {
|
||||
AddSnapshot(1);
|
||||
RunTest({test::KeyStr("a", 1, kTypeDeletion),
|
||||
test::KeyStr("b", 2, kTypeDeletion)},
|
||||
{"", ""}, {test::KeyStr("b", 2, kTypeDeletion)}, {""},
|
||||
kMaxSequenceNumber /*last_commited_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
// In bottommost level, single deletions earlier than earliest snapshot can be
|
||||
// removed permanently.
|
||||
TEST_P(CompactionIteratorTest, RemoveSingleDeletionAtBottomLevel) {
|
||||
AddSnapshot(1);
|
||||
RunTest({test::KeyStr("a", 1, kTypeSingleDeletion),
|
||||
test::KeyStr("b", 2, kTypeSingleDeletion)},
|
||||
{"", ""}, {test::KeyStr("b", 2, kTypeSingleDeletion)}, {""},
|
||||
kMaxSequenceNumber /*last_commited_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(CompactionIteratorTestInstance, CompactionIteratorTest,
|
||||
testing::Values(true, false));
|
||||
|
||||
// Tests how CompactionIterator work together with SnapshotChecker.
|
||||
class CompactionIteratorWithSnapshotCheckerTest
|
||||
: public CompactionIteratorTest {
|
||||
public:
|
||||
bool UseSnapshotChecker() const override { return true; }
|
||||
};
|
||||
|
||||
// Uncommitted keys (keys with seq > last_committed_seq) should be output as-is
|
||||
// while committed version of these keys should get compacted as usual.
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
PreserveUncommittedKeys_Value) {
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 3, kTypeValue), test::KeyStr("foo", 2, kTypeValue),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 3, kTypeValue), test::KeyStr("foo", 2, kTypeValue)},
|
||||
{"v3", "v2"}, 2 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
PreserveUncommittedKeys_Deletion) {
|
||||
RunTest({test::KeyStr("foo", 2, kTypeDeletion),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"", "v1"},
|
||||
{test::KeyStr("foo", 2, kTypeDeletion),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"", "v1"}, 1 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
PreserveUncommittedKeys_Merge) {
|
||||
auto merge_op = MergeOperators::CreateStringAppendOperator();
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeMerge),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeValue)},
|
||||
{"v3", "v1,v2"}, 2 /*last_committed_seq*/, merge_op.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
PreserveUncommittedKeys_SingleDelete) {
|
||||
RunTest({test::KeyStr("foo", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"", "v1"},
|
||||
{test::KeyStr("foo", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"", "v1"}, 1 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
PreserveUncommittedKeys_BlobIndex) {
|
||||
RunTest({test::KeyStr("foo", 3, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 2, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 1, kTypeBlobIndex)},
|
||||
{"v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 3, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 2, kTypeBlobIndex)},
|
||||
{"v3", "v2"}, 2 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
// Test compaction iterator dedup keys visible to the same snapshot.
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Value) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 3, kTypeValue),
|
||||
test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 3, kTypeValue),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "v3", "v1"}, 3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Deletion) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 4, kTypeValue),
|
||||
test::KeyStr("foo", 3, kTypeDeletion),
|
||||
test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "", "v2", "v1"},
|
||||
{test::KeyStr("foo", 4, kTypeValue),
|
||||
test::KeyStr("foo", 3, kTypeDeletion),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "", "v1"}, 3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Merge) {
|
||||
AddSnapshot(2, 1);
|
||||
AddSnapshot(4, 3);
|
||||
auto merge_op = MergeOperators::CreateStringAppendOperator();
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 5, kTypeMerge), test::KeyStr("foo", 4, kTypeMerge),
|
||||
test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 2, kTypeMerge),
|
||||
test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v5", "v4", "v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 5, kTypeMerge), test::KeyStr("foo", 4, kTypeMerge),
|
||||
test::KeyStr("foo", 3, kTypeMerge), test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v5", "v4", "v2,v3", "v1"}, 4 /*last_committed_seq*/, merge_op.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
DedupSameSnapshot_SingleDeletion) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest(
|
||||
{test::KeyStr("foo", 4, kTypeValue),
|
||||
test::KeyStr("foo", 3, kTypeSingleDeletion),
|
||||
test::KeyStr("foo", 2, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "", "v2", "v1"},
|
||||
{test::KeyStr("foo", 4, kTypeValue), test::KeyStr("foo", 1, kTypeValue)},
|
||||
{"v4", "v1"}, 3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_BlobIndex) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest({test::KeyStr("foo", 4, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 3, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 2, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 1, kTypeBlobIndex)},
|
||||
{"v4", "v3", "v2", "v1"},
|
||||
{test::KeyStr("foo", 4, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 3, kTypeBlobIndex),
|
||||
test::KeyStr("foo", 1, kTypeBlobIndex)},
|
||||
{"v4", "v3", "v1"}, 3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
// At bottom level, sequence numbers can be zero out, and deletions can be
|
||||
// removed, but only when they are visible to earliest snapshot.
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
NotZeroOutSequenceIfNotVisibleToEarliestSnapshot) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest({test::KeyStr("a", 1, kTypeValue), test::KeyStr("b", 2, kTypeValue),
|
||||
test::KeyStr("c", 3, kTypeValue)},
|
||||
{"v1", "v2", "v3"},
|
||||
{test::KeyStr("a", 0, kTypeValue), test::KeyStr("b", 2, kTypeValue),
|
||||
test::KeyStr("c", 3, kTypeValue)},
|
||||
{"v1", "v2", "v3"}, kMaxSequenceNumber /*last_commited_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
NotRemoveDeletionIfNotVisibleToEarliestSnapshot) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest(
|
||||
{test::KeyStr("a", 1, kTypeDeletion), test::KeyStr("b", 2, kTypeDeletion),
|
||||
test::KeyStr("c", 3, kTypeDeletion)},
|
||||
{"", "", ""},
|
||||
{test::KeyStr("b", 2, kTypeDeletion),
|
||||
test::KeyStr("c", 3, kTypeDeletion)},
|
||||
{"", ""}, kMaxSequenceNumber /*last_commited_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
NotRemoveSingleDeletionIfNotVisibleToEarliestSnapshot) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest({test::KeyStr("a", 1, kTypeSingleDeletion),
|
||||
test::KeyStr("b", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("c", 3, kTypeSingleDeletion)},
|
||||
{"", "", ""},
|
||||
{test::KeyStr("b", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("c", 3, kTypeSingleDeletion)},
|
||||
{"", ""}, kMaxSequenceNumber /*last_commited_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
// Single delete should not cancel out values that not visible to the
|
||||
// same set of snapshots
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
SingleDeleteAcrossSnapshotBoundary) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", "v1"},
|
||||
{test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", "v1"}, 2 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
// Single delete should be kept in case it is not visible to the
|
||||
// earliest write conflict snapshot. If a single delete is kept for this reason,
|
||||
// corresponding value can be trimmed to save space.
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
KeepSingleDeletionForWriteConflictChecking) {
|
||||
AddSnapshot(2, 0);
|
||||
RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", "v1"},
|
||||
{test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", ""}, 2 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, false /*bottommost_level*/,
|
||||
2 /*earliest_write_conflict_snapshot*/);
|
||||
}
|
||||
|
||||
// Compaction filter should keep uncommitted key as-is, and
|
||||
// * Convert the latest velue to deletion, and/or
|
||||
// * if latest value is a merge, apply filter to all suequent merges.
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Value) {
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
RunTest(
|
||||
{test::KeyStr("a", 2, kTypeValue), test::KeyStr("a", 1, kTypeValue),
|
||||
test::KeyStr("b", 3, kTypeValue), test::KeyStr("c", 1, kTypeValue)},
|
||||
{"v2", "v1", "v3", "v4"},
|
||||
{test::KeyStr("a", 2, kTypeValue), test::KeyStr("a", 1, kTypeDeletion),
|
||||
test::KeyStr("b", 3, kTypeValue), test::KeyStr("c", 1, kTypeDeletion)},
|
||||
{"v2", "", "v3", ""}, 1 /*last_committed_seq*/,
|
||||
nullptr /*merge_operator*/, compaction_filter.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Deletion) {
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
RunTest(
|
||||
{test::KeyStr("a", 2, kTypeDeletion), test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", "v1"},
|
||||
{test::KeyStr("a", 2, kTypeDeletion),
|
||||
test::KeyStr("a", 1, kTypeDeletion)},
|
||||
{"", ""}, 1 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
compaction_filter.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
CompactionFilter_PartialMerge) {
|
||||
std::shared_ptr<MergeOperator> merge_op =
|
||||
MergeOperators::CreateStringAppendOperator();
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
RunTest({test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 2, kTypeMerge),
|
||||
test::KeyStr("a", 1, kTypeMerge)},
|
||||
{"v3", "v2", "v1"}, {test::KeyStr("a", 3, kTypeMerge)}, {"v3"},
|
||||
2 /*last_committed_seq*/, merge_op.get(), compaction_filter.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_FullMerge) {
|
||||
std::shared_ptr<MergeOperator> merge_op =
|
||||
MergeOperators::CreateStringAppendOperator();
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
RunTest(
|
||||
{test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 2, kTypeMerge),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"v3", "v2", "v1"},
|
||||
{test::KeyStr("a", 3, kTypeMerge), test::KeyStr("a", 1, kTypeDeletion)},
|
||||
{"v3", ""}, 2 /*last_committed_seq*/, merge_op.get(),
|
||||
compaction_filter.get());
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
+136
-235
@@ -38,6 +38,7 @@
|
||||
#include "monitoring/iostats_context_imp.h"
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "port/likely.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
@@ -62,46 +63,6 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
const char* GetCompactionReasonString(CompactionReason compaction_reason) {
|
||||
switch (compaction_reason) {
|
||||
case CompactionReason::kUnknown:
|
||||
return "Unknown";
|
||||
case CompactionReason::kLevelL0FilesNum:
|
||||
return "LevelL0FilesNum";
|
||||
case CompactionReason::kLevelMaxLevelSize:
|
||||
return "LevelMaxLevelSize";
|
||||
case CompactionReason::kUniversalSizeAmplification:
|
||||
return "UniversalSizeAmplification";
|
||||
case CompactionReason::kUniversalSizeRatio:
|
||||
return "UniversalSizeRatio";
|
||||
case CompactionReason::kUniversalSortedRunNum:
|
||||
return "UniversalSortedRunNum";
|
||||
case CompactionReason::kFIFOMaxSize:
|
||||
return "FIFOMaxSize";
|
||||
case CompactionReason::kFIFOReduceNumFiles:
|
||||
return "FIFOReduceNumFiles";
|
||||
case CompactionReason::kFIFOTtl:
|
||||
return "FIFOTtl";
|
||||
case CompactionReason::kManualCompaction:
|
||||
return "ManualCompaction";
|
||||
case CompactionReason::kFilesMarkedForCompaction:
|
||||
return "FilesMarkedForCompaction";
|
||||
case CompactionReason::kBottommostFiles:
|
||||
return "BottommostFiles";
|
||||
case CompactionReason::kTtl:
|
||||
return "Ttl";
|
||||
case CompactionReason::kFlush:
|
||||
return "Flush";
|
||||
case CompactionReason::kExternalSstIngestion:
|
||||
return "ExternalSstIngestion";
|
||||
case CompactionReason::kNumOfReasons:
|
||||
// fall through
|
||||
default:
|
||||
assert(false);
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
// Maintains state for each sub-compaction
|
||||
struct CompactionJob::SubcompactionState {
|
||||
const Compaction* compaction;
|
||||
@@ -303,29 +264,25 @@ void CompactionJob::AggregateStatistics() {
|
||||
|
||||
CompactionJob::CompactionJob(
|
||||
int job_id, Compaction* compaction, const ImmutableDBOptions& db_options,
|
||||
const EnvOptions env_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum, LogBuffer* log_buffer,
|
||||
const EnvOptions& env_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down, LogBuffer* log_buffer,
|
||||
Directory* db_directory, Directory* output_directory, Statistics* stats,
|
||||
InstrumentedMutex* db_mutex, Status* db_bg_error,
|
||||
std::vector<SequenceNumber> existing_snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker, std::shared_ptr<Cache> table_cache,
|
||||
EventLogger* event_logger, bool paranoid_file_checks, bool measure_io_stats,
|
||||
const std::string& dbname, CompactionJobStats* compaction_job_stats)
|
||||
std::shared_ptr<Cache> table_cache, EventLogger* event_logger,
|
||||
bool paranoid_file_checks, bool measure_io_stats, const std::string& dbname,
|
||||
CompactionJobStats* compaction_job_stats)
|
||||
: job_id_(job_id),
|
||||
compact_(new CompactionState(compaction)),
|
||||
compaction_job_stats_(compaction_job_stats),
|
||||
compaction_stats_(compaction->compaction_reason(), 1),
|
||||
compaction_stats_(1),
|
||||
dbname_(dbname),
|
||||
db_options_(db_options),
|
||||
env_options_(env_options),
|
||||
env_(db_options.env),
|
||||
env_optiosn_for_read_(
|
||||
env_->OptimizeForCompactionTableRead(env_options, db_options_)),
|
||||
versions_(versions),
|
||||
shutting_down_(shutting_down),
|
||||
preserve_deletes_seqnum_(preserve_deletes_seqnum),
|
||||
log_buffer_(log_buffer),
|
||||
db_directory_(db_directory),
|
||||
output_directory_(output_directory),
|
||||
@@ -334,13 +291,10 @@ CompactionJob::CompactionJob(
|
||||
db_bg_error_(db_bg_error),
|
||||
existing_snapshots_(std::move(existing_snapshots)),
|
||||
earliest_write_conflict_snapshot_(earliest_write_conflict_snapshot),
|
||||
snapshot_checker_(snapshot_checker),
|
||||
table_cache_(std::move(table_cache)),
|
||||
event_logger_(event_logger),
|
||||
bottommost_level_(false),
|
||||
paranoid_file_checks_(paranoid_file_checks),
|
||||
measure_io_stats_(measure_io_stats),
|
||||
write_hint_(Env::WLTH_NOT_SET) {
|
||||
measure_io_stats_(measure_io_stats) {
|
||||
assert(log_buffer_ != nullptr);
|
||||
const auto* cfd = compact_->compaction->column_family_data();
|
||||
ThreadStatusUtil::SetColumnFamily(cfd, cfd->ioptions()->env,
|
||||
@@ -354,13 +308,15 @@ CompactionJob::~CompactionJob() {
|
||||
ThreadStatusUtil::ResetThreadStatus();
|
||||
}
|
||||
|
||||
void CompactionJob::ReportStartedCompaction(Compaction* compaction) {
|
||||
void CompactionJob::ReportStartedCompaction(
|
||||
Compaction* compaction) {
|
||||
const auto* cfd = compact_->compaction->column_family_data();
|
||||
ThreadStatusUtil::SetColumnFamily(cfd, cfd->ioptions()->env,
|
||||
db_options_.enable_thread_tracking);
|
||||
|
||||
ThreadStatusUtil::SetThreadOperationProperty(ThreadStatus::COMPACTION_JOB_ID,
|
||||
job_id_);
|
||||
ThreadStatusUtil::SetThreadOperationProperty(
|
||||
ThreadStatus::COMPACTION_JOB_ID,
|
||||
job_id_);
|
||||
|
||||
ThreadStatusUtil::SetThreadOperationProperty(
|
||||
ThreadStatus::COMPACTION_INPUT_OUTPUT_LEVEL,
|
||||
@@ -390,7 +346,8 @@ void CompactionJob::ReportStartedCompaction(Compaction* compaction) {
|
||||
|
||||
// Set the thread operation after operation properties
|
||||
// to ensure GetThreadList() can always show them all together.
|
||||
ThreadStatusUtil::SetThreadOperation(ThreadStatus::OP_COMPACTION);
|
||||
ThreadStatusUtil::SetThreadOperation(
|
||||
ThreadStatus::OP_COMPACTION);
|
||||
|
||||
if (compaction_job_stats_) {
|
||||
compaction_job_stats_->is_manual_compaction =
|
||||
@@ -405,11 +362,9 @@ void CompactionJob::Prepare() {
|
||||
// Generate file_levels_ for compaction berfore making Iterator
|
||||
auto* c = compact_->compaction;
|
||||
assert(c->column_family_data() != nullptr);
|
||||
assert(c->column_family_data()->current()->storage_info()->NumLevelFiles(
|
||||
compact_->compaction->level()) > 0);
|
||||
assert(c->column_family_data()->current()->storage_info()
|
||||
->NumLevelFiles(compact_->compaction->level()) > 0);
|
||||
|
||||
write_hint_ =
|
||||
c->column_family_data()->CalculateSSTWriteHint(c->output_level());
|
||||
// Is this compaction producing files at the bottommost level?
|
||||
bottommost_level_ = c->bottommost_level();
|
||||
|
||||
@@ -492,18 +447,14 @@ void CompactionJob::GenSubcompactionBoundaries() {
|
||||
}
|
||||
|
||||
std::sort(bounds.begin(), bounds.end(),
|
||||
[cfd_comparator](const Slice& a, const Slice& b) -> bool {
|
||||
return cfd_comparator->Compare(ExtractUserKey(a),
|
||||
ExtractUserKey(b)) < 0;
|
||||
});
|
||||
[cfd_comparator] (const Slice& a, const Slice& b) -> bool {
|
||||
return cfd_comparator->Compare(ExtractUserKey(a), ExtractUserKey(b)) < 0;
|
||||
});
|
||||
// Remove duplicated entries from bounds
|
||||
bounds.erase(
|
||||
std::unique(bounds.begin(), bounds.end(),
|
||||
[cfd_comparator](const Slice& a, const Slice& b) -> bool {
|
||||
return cfd_comparator->Compare(ExtractUserKey(a),
|
||||
ExtractUserKey(b)) == 0;
|
||||
}),
|
||||
bounds.end());
|
||||
bounds.erase(std::unique(bounds.begin(), bounds.end(),
|
||||
[cfd_comparator] (const Slice& a, const Slice& b) -> bool {
|
||||
return cfd_comparator->Compare(ExtractUserKey(a), ExtractUserKey(b)) == 0;
|
||||
}), bounds.end());
|
||||
|
||||
// Combine consecutive pairs of boundaries into ranges with an approximate
|
||||
// size of data covered by keys in that range
|
||||
@@ -526,15 +477,12 @@ void CompactionJob::GenSubcompactionBoundaries() {
|
||||
|
||||
// Group the ranges into subcompactions
|
||||
const double min_file_fill_percent = 4.0 / 5;
|
||||
int base_level = v->storage_info()->base_level();
|
||||
uint64_t max_output_files = static_cast<uint64_t>(std::ceil(
|
||||
sum / min_file_fill_percent /
|
||||
MaxFileSizeForLevel(*(c->mutable_cf_options()), out_lvl,
|
||||
c->immutable_cf_options()->compaction_style, base_level,
|
||||
c->immutable_cf_options()->level_compaction_dynamic_level_bytes)));
|
||||
uint64_t max_output_files = static_cast<uint64_t>(
|
||||
std::ceil(sum / min_file_fill_percent /
|
||||
c->mutable_cf_options()->MaxFileSizeForLevel(out_lvl)));
|
||||
uint64_t subcompactions =
|
||||
std::min({static_cast<uint64_t>(ranges.size()),
|
||||
static_cast<uint64_t>(c->max_subcompactions()),
|
||||
static_cast<uint64_t>(db_options_.max_subcompactions),
|
||||
max_output_files});
|
||||
|
||||
if (subcompactions > 1) {
|
||||
@@ -610,9 +558,8 @@ Status CompactionJob::Run() {
|
||||
TablePropertiesCollection tp;
|
||||
for (const auto& state : compact_->sub_compact_states) {
|
||||
for (const auto& output : state.outputs) {
|
||||
auto fn =
|
||||
TableFileName(state.compaction->immutable_cf_options()->cf_paths,
|
||||
output.meta.fd.GetNumber(), output.meta.fd.GetPathId());
|
||||
auto fn = TableFileName(db_options_.db_paths, output.meta.fd.GetNumber(),
|
||||
output.meta.fd.GetPathId());
|
||||
tp[fn] = output.table_properties;
|
||||
}
|
||||
}
|
||||
@@ -647,9 +594,6 @@ Status CompactionJob::Install(const MutableCFOptions& mutable_cf_options) {
|
||||
|
||||
double read_write_amp = 0.0;
|
||||
double write_amp = 0.0;
|
||||
double bytes_read_per_sec = 0;
|
||||
double bytes_written_per_sec = 0;
|
||||
|
||||
if (stats.bytes_read_non_output_levels > 0) {
|
||||
read_write_amp = (stats.bytes_written + stats.bytes_read_output_level +
|
||||
stats.bytes_read_non_output_levels) /
|
||||
@@ -657,46 +601,37 @@ Status CompactionJob::Install(const MutableCFOptions& mutable_cf_options) {
|
||||
write_amp = stats.bytes_written /
|
||||
static_cast<double>(stats.bytes_read_non_output_levels);
|
||||
}
|
||||
if (stats.micros > 0) {
|
||||
bytes_read_per_sec =
|
||||
(stats.bytes_read_non_output_levels + stats.bytes_read_output_level) /
|
||||
static_cast<double>(stats.micros);
|
||||
bytes_written_per_sec =
|
||||
stats.bytes_written / static_cast<double>(stats.micros);
|
||||
}
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer_,
|
||||
"[%s] compacted to: %s, MB/sec: %.1f rd, %.1f wr, level %d, "
|
||||
"files in(%d, %d) out(%d) "
|
||||
"MB in(%.1f, %.1f) out(%.1f), read-write-amplify(%.1f) "
|
||||
"write-amplify(%.1f) %s, records in: %" PRIu64
|
||||
", records dropped: %" PRIu64 " output_compression: %s\n",
|
||||
cfd->GetName().c_str(), vstorage->LevelSummary(&tmp), bytes_read_per_sec,
|
||||
bytes_written_per_sec, compact_->compaction->output_level(),
|
||||
"write-amplify(%.1f) %s, records in: %d, records dropped: %d\n",
|
||||
cfd->GetName().c_str(), vstorage->LevelSummary(&tmp),
|
||||
(stats.bytes_read_non_output_levels + stats.bytes_read_output_level) /
|
||||
static_cast<double>(stats.micros),
|
||||
stats.bytes_written / static_cast<double>(stats.micros),
|
||||
compact_->compaction->output_level(),
|
||||
stats.num_input_files_in_non_output_levels,
|
||||
stats.num_input_files_in_output_level, stats.num_output_files,
|
||||
stats.bytes_read_non_output_levels / 1048576.0,
|
||||
stats.bytes_read_output_level / 1048576.0,
|
||||
stats.bytes_written / 1048576.0, read_write_amp, write_amp,
|
||||
status.ToString().c_str(), stats.num_input_records,
|
||||
stats.num_dropped_records,
|
||||
CompressionTypeToString(compact_->compaction->output_compression())
|
||||
.c_str());
|
||||
stats.num_dropped_records);
|
||||
|
||||
UpdateCompactionJobStats(stats);
|
||||
|
||||
auto stream = event_logger_->LogToBuffer(log_buffer_);
|
||||
stream << "job" << job_id_ << "event"
|
||||
<< "compaction_finished"
|
||||
stream << "job" << job_id_
|
||||
<< "event" << "compaction_finished"
|
||||
<< "compaction_time_micros" << compaction_stats_.micros
|
||||
<< "output_level" << compact_->compaction->output_level()
|
||||
<< "num_output_files" << compact_->NumOutputFiles()
|
||||
<< "total_output_size" << compact_->total_bytes << "num_input_records"
|
||||
<< compact_->num_input_records << "num_output_records"
|
||||
<< compact_->num_output_records << "num_subcompactions"
|
||||
<< compact_->sub_compact_states.size() << "output_compression"
|
||||
<< CompressionTypeToString(compact_->compaction->output_compression());
|
||||
<< "total_output_size" << compact_->total_bytes
|
||||
<< "num_input_records" << compact_->num_input_records
|
||||
<< "num_output_records" << compact_->num_output_records
|
||||
<< "num_subcompactions" << compact_->sub_compact_states.size();
|
||||
|
||||
if (compaction_job_stats_ != nullptr) {
|
||||
stream << "num_single_delete_mismatches"
|
||||
@@ -731,7 +666,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
std::unique_ptr<RangeDelAggregator> range_del_agg(
|
||||
new RangeDelAggregator(cfd->internal_comparator(), existing_snapshots_));
|
||||
std::unique_ptr<InternalIterator> input(versions_->MakeInputIterator(
|
||||
sub_compact->compaction, range_del_agg.get(), env_optiosn_for_read_));
|
||||
sub_compact->compaction, range_del_agg.get()));
|
||||
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_PROCESS_KV);
|
||||
@@ -756,31 +691,23 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
sub_compact->compaction->mutable_cf_options();
|
||||
|
||||
// To build compression dictionary, we sample the first output file, assuming
|
||||
// it'll reach the maximum length. We optionally pass these samples through
|
||||
// zstd's dictionary trainer, or just use them directly. Then, the dictionary
|
||||
// is used for compressing subsequent output files in the same subcompaction.
|
||||
const bool kUseZstdTrainer =
|
||||
cfd->ioptions()->compression_opts.zstd_max_train_bytes > 0;
|
||||
const size_t kSampleBytes =
|
||||
kUseZstdTrainer ? cfd->ioptions()->compression_opts.zstd_max_train_bytes
|
||||
: cfd->ioptions()->compression_opts.max_dict_bytes;
|
||||
// it'll reach the maximum length, and then use the dictionary for compressing
|
||||
// subsequent output files. The dictionary may be less than max_dict_bytes if
|
||||
// the first output file's length is less than the maximum.
|
||||
const int kSampleLenShift = 6; // 2^6 = 64-byte samples
|
||||
std::set<size_t> sample_begin_offsets;
|
||||
if (bottommost_level_ && kSampleBytes > 0) {
|
||||
const size_t kMaxSamples = kSampleBytes >> kSampleLenShift;
|
||||
const size_t kOutFileLen =
|
||||
static_cast<size_t>(MaxFileSizeForLevel(*mutable_cf_options,
|
||||
compact_->compaction->output_level(),
|
||||
cfd->ioptions()->compaction_style,
|
||||
compact_->compaction->GetInputBaseLevel(),
|
||||
cfd->ioptions()->level_compaction_dynamic_level_bytes));
|
||||
if (bottommost_level_ &&
|
||||
cfd->ioptions()->compression_opts.max_dict_bytes > 0) {
|
||||
const size_t kMaxSamples =
|
||||
cfd->ioptions()->compression_opts.max_dict_bytes >> kSampleLenShift;
|
||||
const size_t kOutFileLen = mutable_cf_options->MaxFileSizeForLevel(
|
||||
compact_->compaction->output_level());
|
||||
if (kOutFileLen != port::kMaxSizet) {
|
||||
const size_t kOutFileNumSamples = kOutFileLen >> kSampleLenShift;
|
||||
Random64 generator{versions_->NewFileNumber()};
|
||||
for (size_t i = 0; i < kMaxSamples; ++i) {
|
||||
sample_begin_offsets.insert(
|
||||
static_cast<size_t>(generator.Uniform(kOutFileNumSamples))
|
||||
<< kSampleLenShift);
|
||||
sample_begin_offsets.insert(generator.Uniform(kOutFileNumSamples)
|
||||
<< kSampleLenShift);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -797,8 +724,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
compaction_filter, db_options_.info_log.get(),
|
||||
false /* internal key corruption is expected */,
|
||||
existing_snapshots_.empty() ? 0 : existing_snapshots_.back(),
|
||||
snapshot_checker_, compact_->compaction->level(),
|
||||
db_options_.statistics.get(), shutting_down_);
|
||||
compact_->compaction->level(), db_options_.statistics.get(),
|
||||
shutting_down_);
|
||||
|
||||
TEST_SYNC_POINT("CompactionJob::Run():Inprogress");
|
||||
|
||||
@@ -812,29 +739,40 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
input->SeekToFirst();
|
||||
}
|
||||
|
||||
// we allow only 1 compaction event listener. Used by blob storage
|
||||
CompactionEventListener* comp_event_listener = nullptr;
|
||||
#ifndef ROCKSDB_LITE
|
||||
for (auto& celitr : cfd->ioptions()->listeners) {
|
||||
comp_event_listener = celitr->GetCompactionEventListener();
|
||||
if (comp_event_listener != nullptr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
Status status;
|
||||
sub_compact->c_iter.reset(new CompactionIterator(
|
||||
input.get(), cfd->user_comparator(), &merge, versions_->LastSequence(),
|
||||
&existing_snapshots_, earliest_write_conflict_snapshot_,
|
||||
snapshot_checker_, env_, false, range_del_agg.get(),
|
||||
sub_compact->compaction, compaction_filter, shutting_down_,
|
||||
preserve_deletes_seqnum_));
|
||||
&existing_snapshots_, earliest_write_conflict_snapshot_, env_, false,
|
||||
range_del_agg.get(), sub_compact->compaction, compaction_filter,
|
||||
comp_event_listener, shutting_down_));
|
||||
auto c_iter = sub_compact->c_iter.get();
|
||||
c_iter->SeekToFirst();
|
||||
if (c_iter->Valid() && sub_compact->compaction->output_level() != 0) {
|
||||
if (c_iter->Valid() &&
|
||||
sub_compact->compaction->output_level() != 0) {
|
||||
// ShouldStopBefore() maintains state based on keys processed so far. The
|
||||
// compaction loop always calls it on the "next" key, thus won't tell it the
|
||||
// first key. So we do that here.
|
||||
sub_compact->ShouldStopBefore(c_iter->key(),
|
||||
sub_compact->current_output_file_size);
|
||||
sub_compact->ShouldStopBefore(
|
||||
c_iter->key(), sub_compact->current_output_file_size);
|
||||
}
|
||||
const auto& c_iter_stats = c_iter->iter_stats();
|
||||
auto sample_begin_offset_iter = sample_begin_offsets.cbegin();
|
||||
// data_begin_offset and dict_sample_data are only valid while generating
|
||||
// data_begin_offset and compression_dict are only valid while generating
|
||||
// dictionary from the first output file.
|
||||
size_t data_begin_offset = 0;
|
||||
std::string dict_sample_data;
|
||||
dict_sample_data.reserve(kSampleBytes);
|
||||
std::string compression_dict;
|
||||
compression_dict.reserve(cfd->ioptions()->compression_opts.max_dict_bytes);
|
||||
|
||||
while (status.ok() && !cfd->IsDropped() && c_iter->Valid()) {
|
||||
// Invariant: c_iter.status() is guaranteed to be OK if c_iter->Valid()
|
||||
@@ -906,7 +844,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
data_elmt_copy_len =
|
||||
data_end_offset - (data_begin_offset + data_elmt_copy_offset);
|
||||
}
|
||||
dict_sample_data.append(&data_elmt.data()[data_elmt_copy_offset],
|
||||
compression_dict.append(&data_elmt.data()[data_elmt_copy_offset],
|
||||
data_elmt_copy_len);
|
||||
if (sample_end_offset > data_end_offset) {
|
||||
// Didn't finish sample. Try to finish it with the next data_elmt.
|
||||
@@ -940,8 +878,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
c_iter->Next();
|
||||
if (!output_file_ended && c_iter->Valid() &&
|
||||
sub_compact->compaction->output_level() != 0 &&
|
||||
sub_compact->ShouldStopBefore(c_iter->key(),
|
||||
sub_compact->current_output_file_size) &&
|
||||
sub_compact->ShouldStopBefore(
|
||||
c_iter->key(), sub_compact->current_output_file_size) &&
|
||||
sub_compact->builder != nullptr) {
|
||||
// (2) this key belongs to the next file. For historical reasons, the
|
||||
// iterator status after advancing will be given to
|
||||
@@ -961,15 +899,9 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
RecordDroppedKeys(range_del_out_stats,
|
||||
&sub_compact->compaction_job_stats);
|
||||
if (sub_compact->outputs.size() == 1) {
|
||||
// Use samples from first output file to create dictionary for
|
||||
// compression of subsequent files.
|
||||
if (kUseZstdTrainer) {
|
||||
sub_compact->compression_dict = ZSTD_TrainDictionary(
|
||||
dict_sample_data, kSampleLenShift,
|
||||
cfd->ioptions()->compression_opts.max_dict_bytes);
|
||||
} else {
|
||||
sub_compact->compression_dict = std::move(dict_sample_data);
|
||||
}
|
||||
// Use dictionary from first output file for compression of subsequent
|
||||
// files.
|
||||
sub_compact->compression_dict = std::move(compression_dict);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -993,8 +925,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
RecordDroppedKeys(c_iter_stats, &sub_compact->compaction_job_stats);
|
||||
RecordCompactionIOStats();
|
||||
|
||||
if (status.ok() &&
|
||||
(shutting_down_->load(std::memory_order_relaxed) || cfd->IsDropped())) {
|
||||
if (status.ok() && (shutting_down_->load(std::memory_order_relaxed) ||
|
||||
cfd->IsDropped())) {
|
||||
status = Status::ShutdownInProgress(
|
||||
"Database shutdown or Column family drop during compaction");
|
||||
}
|
||||
@@ -1074,10 +1006,6 @@ void CompactionJob::RecordDroppedKeys(
|
||||
RecordTick(stats_, COMPACTION_RANGE_DEL_DROP_OBSOLETE,
|
||||
c_iter_stats.num_range_del_drop_obsolete);
|
||||
}
|
||||
if (c_iter_stats.num_optimized_del_drop_obsolete > 0) {
|
||||
RecordTick(stats_, COMPACTION_OPTIMIZED_DEL_DROP_OBSOLETE,
|
||||
c_iter_stats.num_optimized_del_drop_obsolete);
|
||||
}
|
||||
}
|
||||
|
||||
Status CompactionJob::FinishCompactionOutputFile(
|
||||
@@ -1100,7 +1028,6 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
auto meta = &sub_compact->current_output()->meta;
|
||||
if (s.ok()) {
|
||||
Slice lower_bound_guard, upper_bound_guard;
|
||||
std::string smallest_user_key;
|
||||
const Slice *lower_bound, *upper_bound;
|
||||
if (sub_compact->outputs.size() == 1) {
|
||||
// For the first output table, include range tombstones before the min key
|
||||
@@ -1110,8 +1037,7 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
// For subsequent output tables, only include range tombstones from min
|
||||
// key onwards since the previous file was extended to contain range
|
||||
// tombstones falling before min key.
|
||||
smallest_user_key = meta->smallest.user_key().ToString(false /*hex*/);
|
||||
lower_bound_guard = Slice(smallest_user_key);
|
||||
lower_bound_guard = meta->smallest.user_key();
|
||||
lower_bound = &lower_bound_guard;
|
||||
} else {
|
||||
lower_bound = nullptr;
|
||||
@@ -1129,18 +1055,16 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
range_del_agg->AddToBuilder(sub_compact->builder.get(), lower_bound,
|
||||
upper_bound, meta, range_del_out_stats,
|
||||
bottommost_level_);
|
||||
meta->marked_for_compaction = sub_compact->builder->NeedCompact();
|
||||
}
|
||||
const uint64_t current_entries = sub_compact->builder->NumEntries();
|
||||
meta->marked_for_compaction = sub_compact->builder->NeedCompact();
|
||||
if (s.ok()) {
|
||||
s = sub_compact->builder->Finish();
|
||||
} else {
|
||||
sub_compact->builder->Abandon();
|
||||
}
|
||||
const uint64_t current_bytes = sub_compact->builder->FileSize();
|
||||
if (s.ok()) {
|
||||
meta->fd.file_size = current_bytes;
|
||||
}
|
||||
meta->fd.file_size = current_bytes;
|
||||
sub_compact->current_output()->finished = true;
|
||||
sub_compact->total_bytes += current_bytes;
|
||||
|
||||
@@ -1158,9 +1082,8 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
// If there is nothing to output, no necessary to generate a sst file.
|
||||
// This happens when the output level is bottom level, at the same time
|
||||
// the sub_compact output nothing.
|
||||
std::string fname =
|
||||
TableFileName(sub_compact->compaction->immutable_cf_options()->cf_paths,
|
||||
meta->fd.GetNumber(), meta->fd.GetPathId());
|
||||
std::string fname = TableFileName(
|
||||
db_options_.db_paths, meta->fd.GetNumber(), meta->fd.GetPathId());
|
||||
env_->DeleteFile(fname);
|
||||
|
||||
// Also need to remove the file from outputs, or it will be added to the
|
||||
@@ -1179,22 +1102,18 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
// We set for_compaction to false and don't OptimizeForCompactionTableRead
|
||||
// here because this is a special case after we finish the table building
|
||||
// No matter whether use_direct_io_for_flush_and_compaction is true,
|
||||
// we will regard this verification as user reads since the goal is
|
||||
// we will regrad this verification as user reads since the goal is
|
||||
// to cache it here for further user reads
|
||||
InternalIterator* iter = cfd->table_cache()->NewIterator(
|
||||
ReadOptions(), env_options_, cfd->internal_comparator(), meta->fd,
|
||||
nullptr /* range_del_agg */,
|
||||
sub_compact->compaction->mutable_cf_options()->prefix_extractor.get(),
|
||||
nullptr,
|
||||
nullptr /* range_del_agg */, nullptr,
|
||||
cfd->internal_stats()->GetFileReadHist(
|
||||
compact_->compaction->output_level()),
|
||||
false, nullptr /* arena */, false /* skip_filters */,
|
||||
compact_->compaction->output_level());
|
||||
false);
|
||||
s = iter->status();
|
||||
|
||||
if (s.ok() && paranoid_file_checks_) {
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
}
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {}
|
||||
s = iter->status();
|
||||
}
|
||||
|
||||
@@ -1213,33 +1132,24 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
meta->marked_for_compaction ? " (need compaction)" : "");
|
||||
}
|
||||
}
|
||||
std::string fname;
|
||||
FileDescriptor output_fd;
|
||||
if (meta != nullptr) {
|
||||
fname =
|
||||
TableFileName(sub_compact->compaction->immutable_cf_options()->cf_paths,
|
||||
meta->fd.GetNumber(), meta->fd.GetPathId());
|
||||
output_fd = meta->fd;
|
||||
} else {
|
||||
fname = "(nil)";
|
||||
}
|
||||
std::string fname = TableFileName(db_options_.db_paths, meta->fd.GetNumber(),
|
||||
meta->fd.GetPathId());
|
||||
EventHelpers::LogAndNotifyTableFileCreationFinished(
|
||||
event_logger_, cfd->ioptions()->listeners, dbname_, cfd->GetName(), fname,
|
||||
job_id_, output_fd, tp, TableFileCreationReason::kCompaction, s);
|
||||
job_id_, meta->fd, tp, TableFileCreationReason::kCompaction, s);
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
// Report new file to SstFileManagerImpl
|
||||
auto sfm =
|
||||
static_cast<SstFileManagerImpl*>(db_options_.sst_file_manager.get());
|
||||
if (sfm && meta != nullptr && meta->fd.GetPathId() == 0) {
|
||||
auto fn =
|
||||
TableFileName(sub_compact->compaction->immutable_cf_options()->cf_paths,
|
||||
meta->fd.GetNumber(), meta->fd.GetPathId());
|
||||
if (sfm && meta->fd.GetPathId() == 0) {
|
||||
auto fn = TableFileName(cfd->ioptions()->db_paths, meta->fd.GetNumber(),
|
||||
meta->fd.GetPathId());
|
||||
sfm->OnAddFile(fn);
|
||||
if (sfm->IsMaxAllowedSpaceReached()) {
|
||||
// TODO(ajkr): should we return OK() if max space was reached by the final
|
||||
// compaction output file (similarly to how flush works when full)?
|
||||
s = Status::NoSpace("Max allowed space was reached");
|
||||
s = Status::IOError("Max allowed space was reached");
|
||||
TEST_SYNC_POINT(
|
||||
"CompactionJob::FinishCompactionOutputFile:"
|
||||
"MaxAllowedSpaceReached");
|
||||
@@ -1289,7 +1199,7 @@ Status CompactionJob::InstallCompactionResults(
|
||||
compaction->InputLevelSummary(&inputs_summary), compact_->total_bytes);
|
||||
}
|
||||
|
||||
// Add compaction inputs
|
||||
// Add compaction outputs
|
||||
compaction->AddInputDeletions(compact_->compaction->edit());
|
||||
|
||||
for (const auto& sub_compact : compact_->sub_compact_states) {
|
||||
@@ -1319,9 +1229,8 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
assert(sub_compact->builder == nullptr);
|
||||
// no need to lock because VersionSet::next_file_number_ is atomic
|
||||
uint64_t file_number = versions_->NewFileNumber();
|
||||
std::string fname =
|
||||
TableFileName(sub_compact->compaction->immutable_cf_options()->cf_paths,
|
||||
file_number, sub_compact->compaction->output_path_id());
|
||||
std::string fname = TableFileName(db_options_.db_paths, file_number,
|
||||
sub_compact->compaction->output_path_id());
|
||||
// Fire events.
|
||||
ColumnFamilyData* cfd = sub_compact->compaction->column_family_data();
|
||||
#ifndef ROCKSDB_LITE
|
||||
@@ -1331,12 +1240,11 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
#endif // !ROCKSDB_LITE
|
||||
// Make the output file
|
||||
unique_ptr<WritableFile> writable_file;
|
||||
#ifndef NDEBUG
|
||||
bool syncpoint_arg = env_options_.use_direct_writes;
|
||||
EnvOptions opt_env_opts =
|
||||
env_->OptimizeForCompactionTableWrite(env_options_, db_options_);
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionJob::OpenCompactionOutputFile",
|
||||
&syncpoint_arg);
|
||||
#endif
|
||||
Status s = NewWritableFile(env_, fname, &writable_file, env_options_);
|
||||
&opt_env_opts.use_direct_writes);
|
||||
Status s = NewWritableFile(env_, fname, &writable_file, opt_env_opts);
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_ERROR(
|
||||
db_options_.info_log,
|
||||
@@ -1359,7 +1267,6 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
|
||||
sub_compact->outputs.push_back(out);
|
||||
writable_file->SetIOPriority(Env::IO_LOW);
|
||||
writable_file->SetWriteLifeTimeHint(write_hint_);
|
||||
writable_file->SetPreallocationBlockSize(static_cast<size_t>(
|
||||
sub_compact->compaction->OutputFilePreallocationSize()));
|
||||
sub_compact->outfile.reset(new WritableFileWriter(
|
||||
@@ -1375,23 +1282,14 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
sub_compact->compaction->MaxInputFileCreationTime();
|
||||
if (output_file_creation_time == 0) {
|
||||
int64_t _current_time = 0;
|
||||
auto status = db_options_.env->GetCurrentTime(&_current_time);
|
||||
// Safe to proceed even if GetCurrentTime fails. So, log and proceed.
|
||||
if (!status.ok()) {
|
||||
ROCKS_LOG_WARN(
|
||||
db_options_.info_log,
|
||||
"Failed to get current time to populate creation_time property. "
|
||||
"Status: %s",
|
||||
status.ToString().c_str());
|
||||
}
|
||||
db_options_.env->GetCurrentTime(&_current_time); // ignore error
|
||||
output_file_creation_time = static_cast<uint64_t>(_current_time);
|
||||
}
|
||||
|
||||
sub_compact->builder.reset(NewTableBuilder(
|
||||
*cfd->ioptions(), *(sub_compact->compaction->mutable_cf_options()),
|
||||
cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(),
|
||||
cfd->GetID(), cfd->GetName(), sub_compact->outfile.get(),
|
||||
sub_compact->compaction->output_compression(),
|
||||
*cfd->ioptions(), cfd->internal_comparator(),
|
||||
cfd->int_tbl_prop_collector_factories(), cfd->GetID(), cfd->GetName(),
|
||||
sub_compact->outfile.get(), sub_compact->compaction->output_compression(),
|
||||
cfd->ioptions()->compression_opts,
|
||||
sub_compact->compaction->output_level(), &sub_compact->compression_dict,
|
||||
skip_filters, output_file_creation_time));
|
||||
@@ -1424,7 +1322,8 @@ void CompactionJob::CleanupCompaction() {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace {
|
||||
void CopyPrefix(const Slice& src, size_t prefix_length, std::string* dst) {
|
||||
void CopyPrefix(
|
||||
const Slice& src, size_t prefix_length, std::string* dst) {
|
||||
assert(prefix_length > 0);
|
||||
size_t length = src.size() > prefix_length ? prefix_length : src.size();
|
||||
dst->assign(src.data(), length);
|
||||
@@ -1443,11 +1342,13 @@ void CompactionJob::UpdateCompactionStats() {
|
||||
if (compaction->level(input_level) != compaction->output_level()) {
|
||||
UpdateCompactionInputStatsHelper(
|
||||
&compaction_stats_.num_input_files_in_non_output_levels,
|
||||
&compaction_stats_.bytes_read_non_output_levels, input_level);
|
||||
&compaction_stats_.bytes_read_non_output_levels,
|
||||
input_level);
|
||||
} else {
|
||||
UpdateCompactionInputStatsHelper(
|
||||
&compaction_stats_.num_input_files_in_output_level,
|
||||
&compaction_stats_.bytes_read_output_level, input_level);
|
||||
&compaction_stats_.bytes_read_output_level,
|
||||
input_level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1470,9 +1371,8 @@ void CompactionJob::UpdateCompactionStats() {
|
||||
}
|
||||
}
|
||||
|
||||
void CompactionJob::UpdateCompactionInputStatsHelper(int* num_files,
|
||||
uint64_t* bytes_read,
|
||||
int input_level) {
|
||||
void CompactionJob::UpdateCompactionInputStatsHelper(
|
||||
int* num_files, uint64_t* bytes_read, int input_level) {
|
||||
const Compaction* compaction = compact_->compaction;
|
||||
auto num_input_files = compaction->num_input_files(input_level);
|
||||
*num_files += static_cast<int>(num_input_files);
|
||||
@@ -1493,8 +1393,10 @@ void CompactionJob::UpdateCompactionJobStats(
|
||||
|
||||
// input information
|
||||
compaction_job_stats_->total_input_bytes =
|
||||
stats.bytes_read_non_output_levels + stats.bytes_read_output_level;
|
||||
compaction_job_stats_->num_input_records = compact_->num_input_records;
|
||||
stats.bytes_read_non_output_levels +
|
||||
stats.bytes_read_output_level;
|
||||
compaction_job_stats_->num_input_records =
|
||||
compact_->num_input_records;
|
||||
compaction_job_stats_->num_input_files =
|
||||
stats.num_input_files_in_non_output_levels +
|
||||
stats.num_input_files_in_output_level;
|
||||
@@ -1503,20 +1405,21 @@ void CompactionJob::UpdateCompactionJobStats(
|
||||
|
||||
// output information
|
||||
compaction_job_stats_->total_output_bytes = stats.bytes_written;
|
||||
compaction_job_stats_->num_output_records = compact_->num_output_records;
|
||||
compaction_job_stats_->num_output_records =
|
||||
compact_->num_output_records;
|
||||
compaction_job_stats_->num_output_files = stats.num_output_files;
|
||||
|
||||
if (compact_->NumOutputFiles() > 0U) {
|
||||
CopyPrefix(compact_->SmallestUserKey(),
|
||||
CompactionJobStats::kMaxPrefixLength,
|
||||
&compaction_job_stats_->smallest_output_key_prefix);
|
||||
CopyPrefix(compact_->LargestUserKey(),
|
||||
CompactionJobStats::kMaxPrefixLength,
|
||||
&compaction_job_stats_->largest_output_key_prefix);
|
||||
CopyPrefix(
|
||||
compact_->SmallestUserKey(),
|
||||
CompactionJobStats::kMaxPrefixLength,
|
||||
&compaction_job_stats_->smallest_output_key_prefix);
|
||||
CopyPrefix(
|
||||
compact_->LargestUserKey(),
|
||||
CompactionJobStats::kMaxPrefixLength,
|
||||
&compaction_job_stats_->largest_output_key_prefix);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)stats;
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
@@ -1539,9 +1442,7 @@ void CompactionJob::LogCompaction() {
|
||||
// build event logger report
|
||||
auto stream = event_logger_->Log();
|
||||
stream << "job" << job_id_ << "event"
|
||||
<< "compaction_started"
|
||||
<< "compaction_reason"
|
||||
<< GetCompactionReasonString(compaction->compaction_reason());
|
||||
<< "compaction_started";
|
||||
for (size_t i = 0; i < compaction->num_input_levels(); ++i) {
|
||||
stream << ("files_L" + ToString(compaction->level(i)));
|
||||
stream.StartArray();
|
||||
|
||||
+4
-15
@@ -30,7 +30,6 @@
|
||||
#include "db/write_controller.h"
|
||||
#include "db/write_thread.h"
|
||||
#include "options/db_options.h"
|
||||
#include "options/cf_options.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
#include "rocksdb/compaction_job_stats.h"
|
||||
@@ -46,28 +45,24 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class Arena;
|
||||
class MemTable;
|
||||
class SnapshotChecker;
|
||||
class TableCache;
|
||||
class Version;
|
||||
class VersionEdit;
|
||||
class VersionSet;
|
||||
class Arena;
|
||||
|
||||
class CompactionJob {
|
||||
public:
|
||||
CompactionJob(int job_id, Compaction* compaction,
|
||||
const ImmutableDBOptions& db_options,
|
||||
const EnvOptions env_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum,
|
||||
LogBuffer* log_buffer,
|
||||
const EnvOptions& env_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down, LogBuffer* log_buffer,
|
||||
Directory* db_directory, Directory* output_directory,
|
||||
Statistics* stats, InstrumentedMutex* db_mutex,
|
||||
Status* db_bg_error,
|
||||
std::vector<SequenceNumber> existing_snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
const SnapshotChecker* snapshot_checker,
|
||||
std::shared_ptr<Cache> table_cache, EventLogger* event_logger,
|
||||
bool paranoid_file_checks, bool measure_io_stats,
|
||||
const std::string& dbname,
|
||||
@@ -132,14 +127,11 @@ class CompactionJob {
|
||||
// DBImpl state
|
||||
const std::string& dbname_;
|
||||
const ImmutableDBOptions& db_options_;
|
||||
const EnvOptions env_options_;
|
||||
const EnvOptions& env_options_;
|
||||
|
||||
Env* env_;
|
||||
// env_option optimized for compaction table reads
|
||||
EnvOptions env_optiosn_for_read_;
|
||||
VersionSet* versions_;
|
||||
const std::atomic<bool>* shutting_down_;
|
||||
const SequenceNumber preserve_deletes_seqnum_;
|
||||
LogBuffer* log_buffer_;
|
||||
Directory* db_directory_;
|
||||
Directory* output_directory_;
|
||||
@@ -157,8 +149,6 @@ class CompactionJob {
|
||||
// should make sure not to remove evidence that a write occurred.
|
||||
SequenceNumber earliest_write_conflict_snapshot_;
|
||||
|
||||
const SnapshotChecker* const snapshot_checker_;
|
||||
|
||||
std::shared_ptr<Cache> table_cache_;
|
||||
|
||||
EventLogger* event_logger_;
|
||||
@@ -170,7 +160,6 @@ class CompactionJob {
|
||||
std::vector<Slice> boundaries_;
|
||||
// Stores the approx size of keys covered in the range of each subcompaction
|
||||
std::vector<uint64_t> sizes_;
|
||||
Env::WriteLifeTimeHint write_hint_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -426,7 +426,7 @@ class CompactionJobStatsChecker : public EventListener {
|
||||
// Once a compaction completed, this function will verify the returned
|
||||
// CompactionJobInfo with the oldest CompactionJobInfo added earlier
|
||||
// in "expected_stats_" which has not yet being used for verification.
|
||||
virtual void OnCompactionCompleted(DB* /*db*/, const CompactionJobInfo& ci) {
|
||||
virtual void OnCompactionCompleted(DB *db, const CompactionJobInfo& ci) {
|
||||
if (verify_next_comp_io_stats_) {
|
||||
ASSERT_GT(ci.stats.file_write_nanos, 0);
|
||||
ASSERT_GT(ci.stats.file_range_sync_nanos, 0);
|
||||
@@ -806,7 +806,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
stats_checker->set_verify_next_comp_io_stats(true);
|
||||
std::atomic<bool> first_prepare_write(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::Append:BeforePrepareWrite", [&](void* /*arg*/) {
|
||||
"WritableFileWriter::Append:BeforePrepareWrite", [&](void* arg) {
|
||||
if (first_prepare_write.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
first_prepare_write.store(false);
|
||||
@@ -815,7 +815,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
|
||||
std::atomic<bool> first_flush(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::Flush:BeforeAppend", [&](void* /*arg*/) {
|
||||
"WritableFileWriter::Flush:BeforeAppend", [&](void* arg) {
|
||||
if (first_flush.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
first_flush.store(false);
|
||||
@@ -824,7 +824,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
|
||||
std::atomic<bool> first_sync(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::SyncInternal:0", [&](void* /*arg*/) {
|
||||
"WritableFileWriter::SyncInternal:0", [&](void* arg) {
|
||||
if (first_sync.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
first_sync.store(false);
|
||||
@@ -833,7 +833,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
|
||||
std::atomic<bool> first_range_sync(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::RangeSync:0", [&](void* /*arg*/) {
|
||||
"WritableFileWriter::RangeSync:0", [&](void* arg) {
|
||||
if (first_range_sync.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
first_range_sync.store(false);
|
||||
@@ -1034,7 +1034,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED, not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1043,5 +1043,5 @@ int main(int /*argc*/, char** /*argv*/) {
|
||||
|
||||
#else
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) { return 0; }
|
||||
int main(int argc, char** argv) { return 0; }
|
||||
#endif // !defined(IOS_CROSS_COMPILE)
|
||||
|
||||
@@ -76,7 +76,6 @@ class CompactionJobTest : public testing::Test {
|
||||
table_cache_.get(), &write_buffer_manager_,
|
||||
&write_controller_)),
|
||||
shutting_down_(false),
|
||||
preserve_deletes_seqnum_(0),
|
||||
mock_table_factory_(new mock::MockTableFactory()) {
|
||||
EXPECT_OK(env_->CreateDirIfMissing(dbname_));
|
||||
db_options_.db_paths.emplace_back(dbname_,
|
||||
@@ -143,8 +142,7 @@ class CompactionJobTest : public testing::Test {
|
||||
}
|
||||
|
||||
void SetLastSequence(const SequenceNumber sequence_number) {
|
||||
versions_->SetLastAllocatedSequence(sequence_number + 1);
|
||||
versions_->SetLastPublishedSequence(sequence_number + 1);
|
||||
versions_->SetLastToBeWrittenSequence(sequence_number + 1);
|
||||
versions_->SetLastSequence(sequence_number + 1);
|
||||
}
|
||||
|
||||
@@ -246,21 +244,18 @@ class CompactionJobTest : public testing::Test {
|
||||
Compaction compaction(cfd->current()->storage_info(), *cfd->ioptions(),
|
||||
*cfd->GetLatestMutableCFOptions(),
|
||||
compaction_input_files, 1, 1024 * 1024,
|
||||
10 * 1024 * 1024, 0, kNoCompression, 0, {}, true);
|
||||
10 * 1024 * 1024, 0, kNoCompression, {}, true);
|
||||
compaction.SetInputVersion(cfd->current());
|
||||
|
||||
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, db_options_.info_log.get());
|
||||
mutex_.Lock();
|
||||
EventLogger event_logger(db_options_.info_log.get());
|
||||
// TODO(yiwu) add a mock snapshot checker and add test for it.
|
||||
SnapshotChecker* snapshot_checker = nullptr;
|
||||
CompactionJob compaction_job(0, &compaction, db_options_, env_options_,
|
||||
versions_.get(), &shutting_down_,
|
||||
preserve_deletes_seqnum_, &log_buffer,
|
||||
nullptr, nullptr, nullptr, &mutex_, &bg_error_,
|
||||
snapshots, earliest_write_conflict_snapshot,
|
||||
snapshot_checker, table_cache_, &event_logger,
|
||||
false, false, dbname_, &compaction_job_stats_);
|
||||
CompactionJob compaction_job(
|
||||
0, &compaction, db_options_, env_options_, versions_.get(),
|
||||
&shutting_down_, &log_buffer, nullptr, nullptr, nullptr, &mutex_,
|
||||
&bg_error_, snapshots, earliest_write_conflict_snapshot, table_cache_,
|
||||
&event_logger, false, false, dbname_, &compaction_job_stats_);
|
||||
|
||||
VerifyInitializationOfCompactionJobStats(compaction_job_stats_);
|
||||
|
||||
compaction_job.Prepare();
|
||||
@@ -296,7 +291,6 @@ class CompactionJobTest : public testing::Test {
|
||||
std::unique_ptr<VersionSet> versions_;
|
||||
InstrumentedMutex mutex_;
|
||||
std::atomic<bool> shutting_down_;
|
||||
SequenceNumber preserve_deletes_seqnum_;
|
||||
std::shared_ptr<mock::MockTableFactory> mock_table_factory_;
|
||||
CompactionJobStats compaction_job_stats_;
|
||||
ColumnFamilyData* cfd_;
|
||||
@@ -946,7 +940,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr,
|
||||
"SKIPPED as CompactionJobStats is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
|
||||
+103
-222
@@ -41,7 +41,7 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
size_t min_files_to_compact,
|
||||
uint64_t max_compact_bytes_per_del_file,
|
||||
CompactionInputFiles* comp_inputs) {
|
||||
size_t compact_bytes = static_cast<size_t>(level_files[0]->fd.file_size);
|
||||
size_t compact_bytes = level_files[0]->fd.file_size;
|
||||
size_t compact_bytes_per_del_file = port::kMaxSizet;
|
||||
// compaction range will be [0, span_len).
|
||||
size_t span_len;
|
||||
@@ -59,7 +59,7 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
}
|
||||
|
||||
if (span_len >= min_files_to_compact &&
|
||||
compact_bytes_per_del_file < max_compact_bytes_per_del_file) {
|
||||
new_compact_bytes_per_del_file < max_compact_bytes_per_del_file) {
|
||||
assert(comp_inputs != nullptr);
|
||||
comp_inputs->level = 0;
|
||||
for (size_t i = 0; i < span_len; ++i) {
|
||||
@@ -89,7 +89,7 @@ CompressionType GetCompressionType(const ImmutableCFOptions& ioptions,
|
||||
// If bottommost_compression is set and we are compacting to the
|
||||
// bottommost level then we should use it.
|
||||
if (ioptions.bottommost_compression != kDisableCompressionOption &&
|
||||
level >= (vstorage->num_non_empty_levels() - 1)) {
|
||||
level > base_level && level >= (vstorage->num_non_empty_levels() - 1)) {
|
||||
return ioptions.bottommost_compression;
|
||||
}
|
||||
// If the user has specified a different compression level for each level,
|
||||
@@ -199,7 +199,7 @@ void CompactionPicker::GetRange(const std::vector<CompactionInputFiles>& inputs,
|
||||
assert(initialized);
|
||||
}
|
||||
|
||||
bool CompactionPicker::ExpandInputsToCleanCut(const std::string& /*cf_name*/,
|
||||
bool CompactionPicker::ExpandInputsToCleanCut(const std::string& cf_name,
|
||||
VersionStorageInfo* vstorage,
|
||||
CompactionInputFiles* inputs) {
|
||||
// This isn't good compaction
|
||||
@@ -234,6 +234,11 @@ bool CompactionPicker::ExpandInputsToCleanCut(const std::string& /*cf_name*/,
|
||||
// If, after the expansion, there are files that are already under
|
||||
// compaction, then we must drop/cancel this compaction.
|
||||
if (AreFilesInCompaction(inputs->files)) {
|
||||
ROCKS_LOG_WARN(
|
||||
ioptions_.info_log,
|
||||
"[%s] ExpandWhileOverlapping() failure because some of the necessary"
|
||||
" compaction input files are currently being compacted.",
|
||||
cf_name.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -292,18 +297,25 @@ Compaction* CompactionPicker::CompactFiles(
|
||||
VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options,
|
||||
uint32_t output_path_id) {
|
||||
assert(input_files.size());
|
||||
// This compaction output should not overlap with a running compaction as
|
||||
// `SanitizeCompactionInputFiles` should've checked earlier and db mutex
|
||||
// shouldn't have been released since.
|
||||
assert(!FilesRangeOverlapWithCompaction(input_files, output_level));
|
||||
|
||||
// TODO(rven ): we might be able to run concurrent level 0 compaction
|
||||
// if the key ranges of the two compactions do not overlap, but for now
|
||||
// we do not allow it.
|
||||
if ((input_files[0].level == 0) && !level0_compactions_in_progress_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
// This compaction output could overlap with a running compaction
|
||||
if (FilesRangeOverlapWithCompaction(input_files, output_level)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto c =
|
||||
new Compaction(vstorage, ioptions_, mutable_cf_options, input_files,
|
||||
output_level, compact_options.output_file_size_limit,
|
||||
mutable_cf_options.max_compaction_bytes, output_path_id,
|
||||
compact_options.compression,
|
||||
compact_options.max_subcompactions,
|
||||
/* grandparents */ {}, true);
|
||||
compact_options.compression, /* grandparents */ {}, true);
|
||||
|
||||
// If it's level 0 compaction, make sure we don't execute any other level 0
|
||||
// compactions in parallel
|
||||
RegisterCompaction(c);
|
||||
return c;
|
||||
}
|
||||
@@ -311,7 +323,7 @@ Compaction* CompactionPicker::CompactFiles(
|
||||
Status CompactionPicker::GetCompactionInputsFromFileNumbers(
|
||||
std::vector<CompactionInputFiles>* input_files,
|
||||
std::unordered_set<uint64_t>* input_set, const VersionStorageInfo* vstorage,
|
||||
const CompactionOptions& /*compact_options*/) const {
|
||||
const CompactionOptions& compact_options) const {
|
||||
if (input_set->size() == 0U) {
|
||||
return Status::InvalidArgument(
|
||||
"Compaction must include at least one file.");
|
||||
@@ -389,10 +401,7 @@ bool CompactionPicker::SetupOtherInputs(
|
||||
assert(output_level_inputs->empty());
|
||||
const int input_level = inputs->level;
|
||||
const int output_level = output_level_inputs->level;
|
||||
if (input_level == output_level) {
|
||||
// no possibility of conflict
|
||||
return true;
|
||||
}
|
||||
assert(input_level != output_level);
|
||||
|
||||
// For now, we only support merging two levels, start level and output level.
|
||||
// We need to assert other levels are empty.
|
||||
@@ -477,7 +486,7 @@ bool CompactionPicker::SetupOtherInputs(
|
||||
ROCKS_LOG_INFO(ioptions_.info_log,
|
||||
"[%s] Expanding@%d %" ROCKSDB_PRIszt "+%" ROCKSDB_PRIszt
|
||||
"(%" PRIu64 "+%" PRIu64 " bytes) to %" ROCKSDB_PRIszt
|
||||
"+%" ROCKSDB_PRIszt " (%" PRIu64 "+%" PRIu64 " bytes)\n",
|
||||
"+%" ROCKSDB_PRIszt " (%" PRIu64 "+%" PRIu64 "bytes)\n",
|
||||
cf_name.c_str(), input_level, inputs->size(),
|
||||
output_level_inputs->size(), inputs_size,
|
||||
output_level_inputs_size, expanded_inputs.size(),
|
||||
@@ -506,8 +515,7 @@ void CompactionPicker::GetGrandparents(
|
||||
Compaction* CompactionPicker::CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, int input_level, int output_level,
|
||||
uint32_t output_path_id, uint32_t max_subcompactions,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
uint32_t output_path_id, const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict) {
|
||||
// CompactionPickerFIFO has its own implementation of compact range
|
||||
assert(ioptions_.compaction_style != kCompactionStyleFIFO);
|
||||
@@ -569,12 +577,11 @@ Compaction* CompactionPicker::CompactRange(
|
||||
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(inputs),
|
||||
output_level, MaxFileSizeForLevel(mutable_cf_options, output_level,
|
||||
ioptions_.compaction_style),
|
||||
output_level, mutable_cf_options.MaxFileSizeForLevel(output_level),
|
||||
/* max_compaction_bytes */ LLONG_MAX, output_path_id,
|
||||
GetCompressionType(ioptions_, vstorage, mutable_cf_options,
|
||||
output_level, 1),
|
||||
max_subcompactions, /* grandparents */ {}, /* is manual */ true);
|
||||
/* grandparents */ {}, /* is manual */ true);
|
||||
RegisterCompaction(c);
|
||||
return c;
|
||||
}
|
||||
@@ -620,7 +627,7 @@ Compaction* CompactionPicker::CompactRange(
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(output_path_id < static_cast<uint32_t>(ioptions_.cf_paths.size()));
|
||||
assert(output_path_id < static_cast<uint32_t>(ioptions_.db_paths.size()));
|
||||
|
||||
if (ExpandInputsToCleanCut(cf_name, vstorage, &inputs) == false) {
|
||||
// manual compaction is now multi-threaded, so it can
|
||||
@@ -677,15 +684,11 @@ Compaction* CompactionPicker::CompactRange(
|
||||
GetGrandparents(vstorage, inputs, output_level_inputs, &grandparents);
|
||||
Compaction* compaction = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(compaction_inputs),
|
||||
output_level,
|
||||
MaxFileSizeForLevel(mutable_cf_options, output_level,
|
||||
ioptions_.compaction_style, vstorage->base_level(),
|
||||
ioptions_.level_compaction_dynamic_level_bytes),
|
||||
output_level, mutable_cf_options.MaxFileSizeForLevel(output_level),
|
||||
mutable_cf_options.max_compaction_bytes, output_path_id,
|
||||
GetCompressionType(ioptions_, vstorage, mutable_cf_options, output_level,
|
||||
vstorage->base_level()),
|
||||
/* max_subcompactions */ 0, std::move(grandparents),
|
||||
/* is manual compaction */ true);
|
||||
std::move(grandparents), /* is manual compaction */ true);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionPicker::CompactRange:Return", compaction);
|
||||
RegisterCompaction(compaction);
|
||||
@@ -732,6 +735,10 @@ Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
|
||||
auto& levels = cf_meta.levels;
|
||||
auto comparator = icmp_->user_comparator();
|
||||
|
||||
// TODO(yhchiang): If there is any input files of L1 or up and there
|
||||
// is at least one L0 files. All L0 files older than the L0 file needs
|
||||
// to be included. Otherwise, it is a false conditoin
|
||||
|
||||
// TODO(yhchiang): add is_adjustable to CompactionOptions
|
||||
|
||||
// the smallest and largest key of the current compaction input
|
||||
@@ -792,8 +799,6 @@ Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
|
||||
}
|
||||
last_included++;
|
||||
}
|
||||
} else if (output_level > 0) {
|
||||
last_included = static_cast<int>(current_files.size() - 1);
|
||||
}
|
||||
|
||||
// include all files between the first and the last compaction input files.
|
||||
@@ -949,12 +954,6 @@ void CompactionPicker::UnregisterCompaction(Compaction* c) {
|
||||
|
||||
bool LevelCompactionPicker::NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const {
|
||||
if (!vstorage->ExpiredTtlFiles().empty()) {
|
||||
return true;
|
||||
}
|
||||
if (!vstorage->BottommostFilesMarkedForCompaction().empty()) {
|
||||
return true;
|
||||
}
|
||||
if (!vstorage->FilesMarkedForCompaction().empty()) {
|
||||
return true;
|
||||
}
|
||||
@@ -1021,8 +1020,6 @@ class LevelCompactionBuilder {
|
||||
// If there is any file marked for compaction, put put it into inputs.
|
||||
void PickFilesMarkedForCompaction();
|
||||
|
||||
void PickExpiredTtlFiles();
|
||||
|
||||
const std::string& cf_name_;
|
||||
VersionStorageInfo* vstorage_;
|
||||
CompactionPicker* compaction_picker_;
|
||||
@@ -1093,42 +1090,6 @@ void LevelCompactionBuilder::PickFilesMarkedForCompaction() {
|
||||
start_level_inputs_.files.clear();
|
||||
}
|
||||
|
||||
void LevelCompactionBuilder::PickExpiredTtlFiles() {
|
||||
if (vstorage_->ExpiredTtlFiles().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto continuation = [&](std::pair<int, FileMetaData*> level_file) {
|
||||
// If it's being compacted it has nothing to do here.
|
||||
// If this assert() fails that means that some function marked some
|
||||
// files as being_compacted, but didn't call ComputeCompactionScore()
|
||||
assert(!level_file.second->being_compacted);
|
||||
start_level_ = level_file.first;
|
||||
output_level_ =
|
||||
(start_level_ == 0) ? vstorage_->base_level() : start_level_ + 1;
|
||||
|
||||
if ((start_level_ == vstorage_->num_non_empty_levels() - 1) ||
|
||||
(start_level_ == 0 &&
|
||||
!compaction_picker_->level0_compactions_in_progress()->empty())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start_level_inputs_.files = {level_file.second};
|
||||
start_level_inputs_.level = start_level_;
|
||||
return compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
|
||||
&start_level_inputs_);
|
||||
};
|
||||
|
||||
for (auto& level_file : vstorage_->ExpiredTtlFiles()) {
|
||||
if (continuation(level_file)) {
|
||||
// found the compaction!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
start_level_inputs_.files.clear();
|
||||
}
|
||||
|
||||
void LevelCompactionBuilder::SetupInitialFiles() {
|
||||
// Find the compactions by size on all levels.
|
||||
bool skipped_l0_to_base = false;
|
||||
@@ -1145,7 +1106,11 @@ void LevelCompactionBuilder::SetupInitialFiles() {
|
||||
}
|
||||
output_level_ =
|
||||
(start_level_ == 0) ? vstorage_->base_level() : start_level_ + 1;
|
||||
if (PickFileToCompact()) {
|
||||
if (PickFileToCompact() &&
|
||||
compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
|
||||
&start_level_inputs_) &&
|
||||
!compaction_picker_->FilesRangeOverlapWithCompaction(
|
||||
{start_level_inputs_}, output_level_)) {
|
||||
// found the compaction!
|
||||
if (start_level_ == 0) {
|
||||
// L0 score = `num L0 files` / `level0_file_num_compaction_trigger`
|
||||
@@ -1180,40 +1145,11 @@ void LevelCompactionBuilder::SetupInitialFiles() {
|
||||
// if we didn't find a compaction, check if there are any files marked for
|
||||
// compaction
|
||||
if (start_level_inputs_.empty()) {
|
||||
is_manual_ = true;
|
||||
parent_index_ = base_index_ = -1;
|
||||
|
||||
PickFilesMarkedForCompaction();
|
||||
if (!start_level_inputs_.empty()) {
|
||||
is_manual_ = true;
|
||||
compaction_reason_ = CompactionReason::kFilesMarkedForCompaction;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < vstorage_->BottommostFilesMarkedForCompaction().size();
|
||||
++i) {
|
||||
auto& level_and_file = vstorage_->BottommostFilesMarkedForCompaction()[i];
|
||||
assert(!level_and_file.second->being_compacted);
|
||||
start_level_inputs_.level = output_level_ = start_level_ =
|
||||
level_and_file.first;
|
||||
start_level_inputs_.files = {level_and_file.second};
|
||||
if (compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
|
||||
&start_level_inputs_)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == vstorage_->BottommostFilesMarkedForCompaction().size()) {
|
||||
start_level_inputs_.clear();
|
||||
} else {
|
||||
assert(!start_level_inputs_.empty());
|
||||
compaction_reason_ = CompactionReason::kBottommostFiles;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(start_level_inputs_.empty());
|
||||
PickExpiredTtlFiles();
|
||||
if (!start_level_inputs_.empty()) {
|
||||
compaction_reason_ = CompactionReason::kTtl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1315,16 +1251,13 @@ Compaction* LevelCompactionBuilder::PickCompaction() {
|
||||
Compaction* LevelCompactionBuilder::GetCompaction() {
|
||||
auto c = new Compaction(
|
||||
vstorage_, ioptions_, mutable_cf_options_, std::move(compaction_inputs_),
|
||||
output_level_,
|
||||
MaxFileSizeForLevel(mutable_cf_options_, output_level_,
|
||||
ioptions_.compaction_style, vstorage_->base_level(),
|
||||
ioptions_.level_compaction_dynamic_level_bytes),
|
||||
output_level_, mutable_cf_options_.MaxFileSizeForLevel(output_level_),
|
||||
mutable_cf_options_.max_compaction_bytes,
|
||||
GetPathId(ioptions_, mutable_cf_options_, output_level_),
|
||||
GetCompressionType(ioptions_, vstorage_, mutable_cf_options_,
|
||||
output_level_, vstorage_->base_level()),
|
||||
/* max_subcompactions */ 0, std::move(grandparents_), is_manual_,
|
||||
start_level_score_, false /* deletion_compaction */, compaction_reason_);
|
||||
std::move(grandparents_), is_manual_, start_level_score_,
|
||||
false /* deletion_compaction */, compaction_reason_);
|
||||
|
||||
// If it's level 0 compaction, make sure we don't execute any other level 0
|
||||
// compactions in parallel
|
||||
@@ -1347,47 +1280,32 @@ uint32_t LevelCompactionBuilder::GetPathId(
|
||||
const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options, int level) {
|
||||
uint32_t p = 0;
|
||||
assert(!ioptions.cf_paths.empty());
|
||||
assert(!ioptions.db_paths.empty());
|
||||
|
||||
// size remaining in the most recent path
|
||||
uint64_t current_path_size = ioptions.cf_paths[0].target_size;
|
||||
uint64_t current_path_size = ioptions.db_paths[0].target_size;
|
||||
|
||||
uint64_t level_size;
|
||||
int cur_level = 0;
|
||||
|
||||
// max_bytes_for_level_base denotes L1 size.
|
||||
// We estimate L0 size to be the same as L1.
|
||||
level_size = mutable_cf_options.max_bytes_for_level_base;
|
||||
|
||||
// Last path is the fallback
|
||||
while (p < ioptions.cf_paths.size() - 1) {
|
||||
while (p < ioptions.db_paths.size() - 1) {
|
||||
if (level_size <= current_path_size) {
|
||||
if (cur_level == level) {
|
||||
// Does desired level fit in this path?
|
||||
return p;
|
||||
} else {
|
||||
current_path_size -= level_size;
|
||||
if (cur_level > 0) {
|
||||
if (ioptions.level_compaction_dynamic_level_bytes) {
|
||||
// Currently, level_compaction_dynamic_level_bytes is ignored when
|
||||
// multiple db paths are specified. https://github.com/facebook/
|
||||
// rocksdb/blob/master/db/column_family.cc.
|
||||
// Still, adding this check to avoid accidentally using
|
||||
// max_bytes_for_level_multiplier_additional
|
||||
level_size = static_cast<uint64_t>(
|
||||
level_size * mutable_cf_options.max_bytes_for_level_multiplier);
|
||||
} else {
|
||||
level_size = static_cast<uint64_t>(
|
||||
level_size * mutable_cf_options.max_bytes_for_level_multiplier *
|
||||
mutable_cf_options.MaxBytesMultiplerAdditional(cur_level));
|
||||
}
|
||||
}
|
||||
level_size = static_cast<uint64_t>(
|
||||
level_size * mutable_cf_options.max_bytes_for_level_multiplier);
|
||||
cur_level++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
current_path_size = ioptions.cf_paths[p].target_size;
|
||||
current_path_size = ioptions.db_paths[p].target_size;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -1414,10 +1332,12 @@ bool LevelCompactionBuilder::PickFileToCompact() {
|
||||
const std::vector<FileMetaData*>& level_files =
|
||||
vstorage_->LevelFiles(start_level_);
|
||||
|
||||
unsigned int cmp_idx;
|
||||
for (cmp_idx = vstorage_->NextCompactionIndex(start_level_);
|
||||
cmp_idx < file_size.size(); cmp_idx++) {
|
||||
int index = file_size[cmp_idx];
|
||||
// record the first file that is not yet compacted
|
||||
int nextIndex = -1;
|
||||
|
||||
for (unsigned int i = vstorage_->NextCompactionIndex(start_level_);
|
||||
i < file_size.size(); i++) {
|
||||
int index = file_size[i];
|
||||
auto* f = level_files[index];
|
||||
|
||||
// do not pick a file to compact if it is being compacted
|
||||
@@ -1426,42 +1346,27 @@ bool LevelCompactionBuilder::PickFileToCompact() {
|
||||
continue;
|
||||
}
|
||||
|
||||
start_level_inputs_.files.push_back(f);
|
||||
start_level_inputs_.level = start_level_;
|
||||
if (!compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
|
||||
&start_level_inputs_) ||
|
||||
compaction_picker_->FilesRangeOverlapWithCompaction(
|
||||
{start_level_inputs_}, output_level_)) {
|
||||
// A locked (pending compaction) input-level file was pulled in due to
|
||||
// user-key overlap.
|
||||
start_level_inputs_.clear();
|
||||
continue;
|
||||
// remember the startIndex for the next call to PickCompaction
|
||||
if (nextIndex == -1) {
|
||||
nextIndex = i;
|
||||
}
|
||||
|
||||
// Now that input level is fully expanded, we check whether any output files
|
||||
// are locked due to pending compaction.
|
||||
//
|
||||
// Note we rely on ExpandInputsToCleanCut() to tell us whether any output-
|
||||
// level files are locked, not just the extra ones pulled in for user-key
|
||||
// overlap.
|
||||
InternalKey smallest, largest;
|
||||
compaction_picker_->GetRange(start_level_inputs_, &smallest, &largest);
|
||||
CompactionInputFiles output_level_inputs;
|
||||
output_level_inputs.level = output_level_;
|
||||
vstorage_->GetOverlappingInputs(output_level_, &smallest, &largest,
|
||||
&output_level_inputs.files);
|
||||
if (!output_level_inputs.empty() &&
|
||||
!compaction_picker_->ExpandInputsToCleanCut(cf_name_, vstorage_,
|
||||
&output_level_inputs)) {
|
||||
start_level_inputs_.clear();
|
||||
// Do not pick this file if its parents at level+1 are being compacted.
|
||||
// Maybe we can avoid redoing this work in SetupOtherInputs
|
||||
parent_index_ = -1;
|
||||
if (compaction_picker_->IsRangeInCompaction(vstorage_, &f->smallest,
|
||||
&f->largest, output_level_,
|
||||
&parent_index_)) {
|
||||
continue;
|
||||
}
|
||||
start_level_inputs_.files.push_back(f);
|
||||
start_level_inputs_.level = start_level_;
|
||||
base_index_ = index;
|
||||
break;
|
||||
}
|
||||
|
||||
// store where to start the iteration in the next call to PickCompaction
|
||||
vstorage_->SetNextCompactionIndex(start_level_, cmp_idx);
|
||||
vstorage_->SetNextCompactionIndex(start_level_, nextIndex);
|
||||
|
||||
return start_level_inputs_.size() > 0;
|
||||
}
|
||||
@@ -1512,7 +1417,7 @@ uint64_t GetTotalFilesSize(
|
||||
Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer) {
|
||||
assert(mutable_cf_options.compaction_options_fifo.ttl > 0);
|
||||
assert(ioptions_.compaction_options_fifo.ttl > 0);
|
||||
|
||||
const int kLevel0 = 0;
|
||||
const std::vector<FileMetaData*>& level_files = vstorage->LevelFiles(kLevel0);
|
||||
@@ -1533,22 +1438,19 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
inputs.emplace_back();
|
||||
inputs[0].level = 0;
|
||||
|
||||
// avoid underflow
|
||||
if (current_time > mutable_cf_options.compaction_options_fifo.ttl) {
|
||||
for (auto ritr = level_files.rbegin(); ritr != level_files.rend(); ++ritr) {
|
||||
auto f = *ritr;
|
||||
if (f->fd.table_reader != nullptr &&
|
||||
f->fd.table_reader->GetTableProperties() != nullptr) {
|
||||
auto creation_time =
|
||||
f->fd.table_reader->GetTableProperties()->creation_time;
|
||||
if (creation_time == 0 ||
|
||||
creation_time >= (current_time -
|
||||
mutable_cf_options.compaction_options_fifo.ttl)) {
|
||||
break;
|
||||
}
|
||||
total_size -= f->compensated_file_size;
|
||||
inputs[0].files.push_back(f);
|
||||
for (auto ritr = level_files.rbegin(); ritr != level_files.rend(); ++ritr) {
|
||||
auto f = *ritr;
|
||||
if (f->fd.table_reader != nullptr &&
|
||||
f->fd.table_reader->GetTableProperties() != nullptr) {
|
||||
auto creation_time =
|
||||
f->fd.table_reader->GetTableProperties()->creation_time;
|
||||
if (creation_time == 0 ||
|
||||
creation_time >=
|
||||
(current_time - ioptions_.compaction_options_fifo.ttl)) {
|
||||
break;
|
||||
}
|
||||
total_size -= f->compensated_file_size;
|
||||
inputs[0].files.push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1557,8 +1459,7 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
// 2. there are a few files older than ttl, but deleting them will not bring
|
||||
// the total size to be less than max_table_files_size threshold.
|
||||
if (inputs[0].files.empty() ||
|
||||
total_size >
|
||||
mutable_cf_options.compaction_options_fifo.max_table_files_size) {
|
||||
total_size > ioptions_.compaction_options_fifo.max_table_files_size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1572,9 +1473,8 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(inputs), 0, 0, 0, 0,
|
||||
kNoCompression, /* max_subcompactions */ 0, {}, /* is manual */ false,
|
||||
vstorage->CompactionScore(0), /* is deletion compaction */ true,
|
||||
CompactionReason::kFIFOTtl);
|
||||
kNoCompression, {}, /* is manual */ false, vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ true, CompactionReason::kFIFOTtl);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -1585,46 +1485,34 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
|
||||
const std::vector<FileMetaData*>& level_files = vstorage->LevelFiles(kLevel0);
|
||||
uint64_t total_size = GetTotalFilesSize(level_files);
|
||||
|
||||
if (total_size <=
|
||||
mutable_cf_options.compaction_options_fifo.max_table_files_size ||
|
||||
if (total_size <= ioptions_.compaction_options_fifo.max_table_files_size ||
|
||||
level_files.size() == 0) {
|
||||
// total size not exceeded
|
||||
if (mutable_cf_options.compaction_options_fifo.allow_compaction &&
|
||||
if (ioptions_.compaction_options_fifo.allow_compaction &&
|
||||
level_files.size() > 0) {
|
||||
CompactionInputFiles comp_inputs;
|
||||
// try to prevent same files from being compacted multiple times, which
|
||||
// could produce large files that may never TTL-expire. Achieve this by
|
||||
// disallowing compactions with files larger than memtable (inflate its
|
||||
// size by 10% to account for uncompressed L0 files that may have size
|
||||
// slightly greater than memtable size limit).
|
||||
size_t max_compact_bytes_per_del_file =
|
||||
static_cast<size_t>(MultiplyCheckOverflow(
|
||||
static_cast<uint64_t>(mutable_cf_options.write_buffer_size),
|
||||
1.1));
|
||||
if (FindIntraL0Compaction(
|
||||
level_files,
|
||||
mutable_cf_options
|
||||
.level0_file_num_compaction_trigger /* min_files_to_compact */
|
||||
,
|
||||
max_compact_bytes_per_del_file, &comp_inputs)) {
|
||||
.level0_file_num_compaction_trigger /* min_files_to_compact */,
|
||||
mutable_cf_options.write_buffer_size, &comp_inputs)) {
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, {comp_inputs}, 0,
|
||||
16 * 1024 * 1024 /* output file size limit */,
|
||||
0 /* max compaction bytes, not applicable */,
|
||||
0 /* output path ID */, mutable_cf_options.compression,
|
||||
0 /* max_subcompactions */, {}, /* is manual */ false,
|
||||
vstorage->CompactionScore(0), /* is deletion compaction */ false,
|
||||
0 /* output path ID */, mutable_cf_options.compression, {},
|
||||
/* is manual */ false, vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ false,
|
||||
CompactionReason::kFIFOReduceNumFiles);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
"[%s] FIFO compaction: nothing to do. Total size %" PRIu64
|
||||
", max size %" PRIu64 "\n",
|
||||
cf_name.c_str(), total_size,
|
||||
mutable_cf_options.compaction_options_fifo.max_table_files_size);
|
||||
ROCKS_LOG_BUFFER(log_buffer,
|
||||
"[%s] FIFO compaction: nothing to do. Total size %" PRIu64
|
||||
", max size %" PRIu64 "\n",
|
||||
cf_name.c_str(), total_size,
|
||||
ioptions_.compaction_options_fifo.max_table_files_size);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1651,17 +1539,15 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
|
||||
"[%s] FIFO compaction: picking file %" PRIu64
|
||||
" with size %s for deletion",
|
||||
cf_name.c_str(), f->fd.GetNumber(), tmp_fsize);
|
||||
if (total_size <=
|
||||
mutable_cf_options.compaction_options_fifo.max_table_files_size) {
|
||||
if (total_size <= ioptions_.compaction_options_fifo.max_table_files_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(inputs), 0, 0, 0, 0,
|
||||
kNoCompression, /* max_subcompactions */ 0, {}, /* is manual */ false,
|
||||
vstorage->CompactionScore(0), /* is deletion compaction */ true,
|
||||
CompactionReason::kFIFOMaxSize);
|
||||
kNoCompression, {}, /* is manual */ false, vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ true, CompactionReason::kFIFOMaxSize);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -1671,7 +1557,7 @@ Compaction* FIFOCompactionPicker::PickCompaction(
|
||||
assert(vstorage->num_levels() == 1);
|
||||
|
||||
Compaction* c = nullptr;
|
||||
if (mutable_cf_options.compaction_options_fifo.ttl > 0) {
|
||||
if (ioptions_.compaction_options_fifo.ttl > 0) {
|
||||
c = PickTTLCompaction(cf_name, mutable_cf_options, vstorage, log_buffer);
|
||||
}
|
||||
if (c == nullptr) {
|
||||
@@ -1684,13 +1570,8 @@ Compaction* FIFOCompactionPicker::PickCompaction(
|
||||
Compaction* FIFOCompactionPicker::CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, int input_level, int output_level,
|
||||
uint32_t /*output_path_id*/, uint32_t /*max_subcompactions*/,
|
||||
const InternalKey* /*begin*/, const InternalKey* /*end*/,
|
||||
InternalKey** compaction_end, bool* /*manual_conflict*/) {
|
||||
#ifdef NDEBUG
|
||||
(void)input_level;
|
||||
(void)output_level;
|
||||
#endif
|
||||
uint32_t output_path_id, const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict) {
|
||||
assert(input_level == 0);
|
||||
assert(output_level == 0);
|
||||
*compaction_end = nullptr;
|
||||
|
||||
+14
-23
@@ -58,8 +58,7 @@ class CompactionPicker {
|
||||
virtual Compaction* CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, int input_level, int output_level,
|
||||
uint32_t output_path_id, uint32_t max_subcompactions,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
uint32_t output_path_id, const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict);
|
||||
|
||||
// The maximum allowed output level. Default value is NumberLevels() - 1.
|
||||
@@ -89,10 +88,6 @@ class CompactionPicker {
|
||||
|
||||
// Takes a list of CompactionInputFiles and returns a (manual) Compaction
|
||||
// object.
|
||||
//
|
||||
// Caller must provide a set of input files that has been passed through
|
||||
// `SanitizeCompactionInputFiles` earlier. The lock should not be released
|
||||
// between that call and this one.
|
||||
Compaction* CompactFiles(const CompactionOptions& compact_options,
|
||||
const std::vector<CompactionInputFiles>& input_files,
|
||||
int output_level, VersionStorageInfo* vstorage,
|
||||
@@ -239,8 +234,7 @@ class FIFOCompactionPicker : public CompactionPicker {
|
||||
virtual Compaction* CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, int input_level, int output_level,
|
||||
uint32_t output_path_id, uint32_t max_subcompactions,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
uint32_t output_path_id, const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict) override;
|
||||
|
||||
// The maximum allowed output level. Always returns 0.
|
||||
@@ -269,30 +263,27 @@ class NullCompactionPicker : public CompactionPicker {
|
||||
virtual ~NullCompactionPicker() {}
|
||||
|
||||
// Always return "nullptr"
|
||||
Compaction* PickCompaction(const std::string& /*cf_name*/,
|
||||
const MutableCFOptions& /*mutable_cf_options*/,
|
||||
VersionStorageInfo* /*vstorage*/,
|
||||
LogBuffer* /*log_buffer*/) override {
|
||||
Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Always return "nullptr"
|
||||
Compaction* CompactRange(const std::string& /*cf_name*/,
|
||||
const MutableCFOptions& /*mutable_cf_options*/,
|
||||
VersionStorageInfo* /*vstorage*/,
|
||||
int /*input_level*/, int /*output_level*/,
|
||||
uint32_t /*output_path_id*/,
|
||||
uint32_t /*max_subcompactions*/,
|
||||
const InternalKey* /*begin*/,
|
||||
const InternalKey* /*end*/,
|
||||
InternalKey** /*compaction_end*/,
|
||||
bool* /*manual_conflict*/) override {
|
||||
Compaction* CompactRange(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, int input_level,
|
||||
int output_level, uint32_t output_path_id,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end,
|
||||
bool* manual_conflict) override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Always returns false.
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* /*vstorage*/) const override {
|
||||
const VersionStorageInfo* vstorage) const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace rocksdb {
|
||||
class CountingLogger : public Logger {
|
||||
public:
|
||||
using Logger::Logv;
|
||||
virtual void Logv(const char* /*format*/, va_list /*ap*/) override {
|
||||
log_count++;
|
||||
}
|
||||
virtual void Logv(const char* format, va_list ap) override { log_count++; }
|
||||
size_t log_count;
|
||||
};
|
||||
|
||||
@@ -59,7 +57,7 @@ class CompactionPickerTest : public testing::Test {
|
||||
vstorage_(nullptr) {
|
||||
fifo_options_.max_table_files_size = 1;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
ioptions_.cf_paths.emplace_back("dummy",
|
||||
ioptions_.db_paths.emplace_back("dummy",
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
@@ -177,8 +175,6 @@ TEST_F(CompactionPickerTest, Level1Trigger) {
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, Level1Trigger2) {
|
||||
mutable_cf_options_.target_file_size_base = 10000000000;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
Add(1, 66U, "150", "200", 1000000001U);
|
||||
Add(1, 88U, "201", "300", 1000000000U);
|
||||
@@ -195,14 +191,13 @@ TEST_F(CompactionPickerTest, Level1Trigger2) {
|
||||
ASSERT_EQ(66U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(6U, compaction->input(1, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(7U, compaction->input(1, 1)->fd.GetNumber());
|
||||
ASSERT_EQ(uint64_t{1073741824}, compaction->OutputFilePreallocationSize());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, LevelMaxScore) {
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.target_file_size_base = 10000000;
|
||||
mutable_cf_options_.target_file_size_multiplier = 10;
|
||||
mutable_cf_options_.max_bytes_for_level_base = 10 * 1024 * 1024;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
Add(0, 1U, "150", "200", 1000000U);
|
||||
// Level 1 score 1.2
|
||||
Add(1, 66U, "150", "200", 6000000U);
|
||||
@@ -223,9 +218,6 @@ TEST_F(CompactionPickerTest, LevelMaxScore) {
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(mutable_cf_options_.target_file_size_base +
|
||||
mutable_cf_options_.target_file_size_base / 10,
|
||||
compaction->OutputFilePreallocationSize());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, NeedsCompactionLevel) {
|
||||
@@ -445,7 +437,7 @@ TEST_F(CompactionPickerTest, CompactionUniversalIngestBehindReservedLevel) {
|
||||
TEST_F(CompactionPickerTest, CannotTrivialMoveUniversal) {
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.compaction_options_universal.allow_trivial_move = true;
|
||||
ioptions_.compaction_options_universal.allow_trivial_move = true;
|
||||
NewVersionStorage(1, kCompactionStyleUniversal);
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
// must return false when there's no files.
|
||||
@@ -476,7 +468,7 @@ TEST_F(CompactionPickerTest, CannotTrivialMoveUniversal) {
|
||||
TEST_F(CompactionPickerTest, AllowsTrivialMoveUniversal) {
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.compaction_options_universal.allow_trivial_move = true;
|
||||
ioptions_.compaction_options_universal.allow_trivial_move = true;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(3, kCompactionStyleUniversal);
|
||||
@@ -504,7 +496,7 @@ TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
||||
const uint64_t kMaxSize = kFileSize * kFileCount / 2;
|
||||
|
||||
fifo_options_.max_table_files_size = kMaxSize;
|
||||
mutable_cf_options_.compaction_options_fifo = fifo_options_;
|
||||
ioptions_.compaction_options_fifo = fifo_options_;
|
||||
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
|
||||
UpdateVersionStorageInfo();
|
||||
// must return false when there's no files.
|
||||
@@ -520,7 +512,7 @@ TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
||||
kFileSize, 0, i * 100, i * 100 + 99);
|
||||
current_size += kFileSize;
|
||||
UpdateVersionStorageInfo();
|
||||
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()),
|
||||
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
|
||||
vstorage_->CompactionScore(0) >= 1);
|
||||
}
|
||||
}
|
||||
@@ -529,10 +521,9 @@ TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
||||
TEST_F(CompactionPickerTest, CompactionPriMinOverlapping1) {
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
ioptions_.compaction_pri = kMinOverlappingRatio;
|
||||
mutable_cf_options_.target_file_size_base = 100000000000;
|
||||
mutable_cf_options_.target_file_size_base = 10000000;
|
||||
mutable_cf_options_.target_file_size_multiplier = 10;
|
||||
mutable_cf_options_.max_bytes_for_level_base = 10 * 1024 * 1024;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
|
||||
Add(2, 6U, "150", "179", 50000000U);
|
||||
Add(2, 7U, "180", "220", 50000000U);
|
||||
@@ -552,8 +543,6 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping1) {
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
// Pick file 8 because it overlaps with 0 files on level 3.
|
||||
ASSERT_EQ(8U, compaction->input(0, 0)->fd.GetNumber());
|
||||
// Compaction input size * 1.1
|
||||
ASSERT_GE(uint64_t{55000000}, compaction->OutputFilePreallocationSize());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, CompactionPriMinOverlapping2) {
|
||||
@@ -863,80 +852,6 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys9) {
|
||||
ASSERT_EQ(8U, compaction->input(1, 1)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, OverlappingUserKeys10) {
|
||||
// Locked file encountered when pulling in extra input-level files with same
|
||||
// user keys. Verify we pick the next-best file from the same input level.
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.max_compaction_bytes = 100000000000u;
|
||||
|
||||
// file_number 2U is largest and thus first choice. But it overlaps with
|
||||
// file_number 1U which is being compacted. So instead we pick the next-
|
||||
// biggest file, 3U, which is eligible for compaction.
|
||||
Add(1 /* level */, 1U /* file_number */, "100" /* smallest */,
|
||||
"150" /* largest */, 1U /* file_size */);
|
||||
file_map_[1U].first->being_compacted = true;
|
||||
Add(1 /* level */, 2U /* file_number */, "150" /* smallest */,
|
||||
"200" /* largest */, 1000000000U /* file_size */, 0 /* smallest_seq */,
|
||||
0 /* largest_seq */);
|
||||
Add(1 /* level */, 3U /* file_number */, "201" /* smallest */,
|
||||
"250" /* largest */, 900000000U /* file_size */);
|
||||
Add(2 /* level */, 4U /* file_number */, "100" /* smallest */,
|
||||
"150" /* largest */, 1U /* file_size */);
|
||||
Add(2 /* level */, 5U /* file_number */, "151" /* smallest */,
|
||||
"200" /* largest */, 1U /* file_size */);
|
||||
Add(2 /* level */, 6U /* file_number */, "201" /* smallest */,
|
||||
"250" /* largest */, 1U /* file_size */);
|
||||
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(2U, compaction->num_input_levels());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(1U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(6U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, OverlappingUserKeys11) {
|
||||
// Locked file encountered when pulling in extra output-level files with same
|
||||
// user keys. Expected to skip that compaction and pick the next-best choice.
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.max_compaction_bytes = 100000000000u;
|
||||
|
||||
// score(L1) = 3.7
|
||||
// score(L2) = 1.85
|
||||
// There is no eligible file in L1 to compact since both candidates pull in
|
||||
// file_number 5U, which overlaps with a file pending compaction (6U). The
|
||||
// first eligible compaction is from L2->L3.
|
||||
Add(1 /* level */, 2U /* file_number */, "151" /* smallest */,
|
||||
"200" /* largest */, 1000000000U /* file_size */);
|
||||
Add(1 /* level */, 3U /* file_number */, "201" /* smallest */,
|
||||
"250" /* largest */, 1U /* file_size */);
|
||||
Add(2 /* level */, 4U /* file_number */, "100" /* smallest */,
|
||||
"149" /* largest */, 5000000000U /* file_size */);
|
||||
Add(2 /* level */, 5U /* file_number */, "150" /* smallest */,
|
||||
"201" /* largest */, 1U /* file_size */);
|
||||
Add(2 /* level */, 6U /* file_number */, "201" /* smallest */,
|
||||
"249" /* largest */, 1U /* file_size */, 0 /* smallest_seq */,
|
||||
0 /* largest_seq */);
|
||||
file_map_[6U].first->being_compacted = true;
|
||||
Add(3 /* level */, 7U /* file_number */, "100" /* smallest */,
|
||||
"149" /* largest */, 1U /* file_size */);
|
||||
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(2U, compaction->num_input_levels());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(1U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(4U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(7U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri1) {
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
||||
@@ -1401,49 +1316,6 @@ TEST_F(CompactionPickerTest, IsTrivialMoveOff) {
|
||||
ASSERT_FALSE(compaction->IsTrivialMove());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, CacheNextCompactionIndex) {
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.max_compaction_bytes = 100000000000u;
|
||||
|
||||
Add(1 /* level */, 1U /* file_number */, "100" /* smallest */,
|
||||
"149" /* largest */, 1000000000U /* file_size */);
|
||||
file_map_[1U].first->being_compacted = true;
|
||||
Add(1 /* level */, 2U /* file_number */, "150" /* smallest */,
|
||||
"199" /* largest */, 900000000U /* file_size */);
|
||||
Add(1 /* level */, 3U /* file_number */, "200" /* smallest */,
|
||||
"249" /* largest */, 800000000U /* file_size */);
|
||||
Add(1 /* level */, 4U /* file_number */, "250" /* smallest */,
|
||||
"299" /* largest */, 700000000U /* file_size */);
|
||||
Add(2 /* level */, 5U /* file_number */, "150" /* smallest */,
|
||||
"199" /* largest */, 1U /* file_size */);
|
||||
file_map_[5U].first->being_compacted = true;
|
||||
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(1U, compaction->num_input_levels());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(0U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(2, vstorage_->NextCompactionIndex(1 /* level */));
|
||||
|
||||
compaction.reset(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(1U, compaction->num_input_levels());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(0U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(4U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(3, vstorage_->NextCompactionIndex(1 /* level */));
|
||||
|
||||
compaction.reset(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() == nullptr);
|
||||
ASSERT_EQ(4, vstorage_->NextCompactionIndex(1 /* level */));
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace {
|
||||
// and the index of the file in that level
|
||||
|
||||
struct InputFileInfo {
|
||||
InputFileInfo() : f(nullptr), level(0), index(0) {}
|
||||
InputFileInfo() : f(nullptr) {}
|
||||
|
||||
FileMetaData* f;
|
||||
size_t level;
|
||||
@@ -204,8 +204,7 @@ void UniversalCompactionPicker::SortedRun::DumpSizeInfo(
|
||||
|
||||
std::vector<UniversalCompactionPicker::SortedRun>
|
||||
UniversalCompactionPicker::CalculateSortedRuns(
|
||||
const VersionStorageInfo& vstorage, const ImmutableCFOptions& /*ioptions*/,
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
const VersionStorageInfo& vstorage, const ImmutableCFOptions& ioptions) {
|
||||
std::vector<UniversalCompactionPicker::SortedRun> ret;
|
||||
for (FileMetaData* f : vstorage.LevelFiles(0)) {
|
||||
ret.emplace_back(0, f, f->fd.GetFileSize(), f->compensated_file_size,
|
||||
@@ -219,8 +218,7 @@ UniversalCompactionPicker::CalculateSortedRuns(
|
||||
for (FileMetaData* f : vstorage.LevelFiles(level)) {
|
||||
total_compensated_size += f->compensated_file_size;
|
||||
total_size += f->fd.GetFileSize();
|
||||
if (mutable_cf_options.compaction_options_universal.allow_trivial_move ==
|
||||
true) {
|
||||
if (ioptions.compaction_options_universal.allow_trivial_move == true) {
|
||||
if (f->being_compacted) {
|
||||
being_compacted = f->being_compacted;
|
||||
}
|
||||
@@ -229,8 +227,7 @@ UniversalCompactionPicker::CalculateSortedRuns(
|
||||
// non-zero level, all the files should share the same being_compacted
|
||||
// value.
|
||||
// This assumption is only valid when
|
||||
// mutable_cf_options.compaction_options_universal.allow_trivial_move is
|
||||
// false
|
||||
// ioptions.compaction_options_universal.allow_trivial_move is false
|
||||
assert(is_first || f->being_compacted == being_compacted);
|
||||
}
|
||||
if (is_first) {
|
||||
@@ -248,13 +245,14 @@ UniversalCompactionPicker::CalculateSortedRuns(
|
||||
|
||||
// Universal style of compaction. Pick files that are contiguous in
|
||||
// time-range to compact.
|
||||
//
|
||||
Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer) {
|
||||
const int kLevel0 = 0;
|
||||
double score = vstorage->CompactionScore(kLevel0);
|
||||
std::vector<SortedRun> sorted_runs =
|
||||
CalculateSortedRuns(*vstorage, ioptions_, mutable_cf_options);
|
||||
CalculateSortedRuns(*vstorage, ioptions_);
|
||||
|
||||
if (sorted_runs.size() == 0 ||
|
||||
sorted_runs.size() <
|
||||
@@ -281,8 +279,7 @@ Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
} else {
|
||||
// Size amplification is within limits. Try reducing read
|
||||
// amplification while maintaining file size ratios.
|
||||
unsigned int ratio =
|
||||
mutable_cf_options.compaction_options_universal.size_ratio;
|
||||
unsigned int ratio = ioptions_.compaction_options_universal.size_ratio;
|
||||
|
||||
if ((c = PickCompactionToReduceSortedRuns(
|
||||
cf_name, mutable_cf_options, vstorage, score, ratio, UINT_MAX,
|
||||
@@ -330,8 +327,7 @@ Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mutable_cf_options.compaction_options_universal.allow_trivial_move ==
|
||||
true) {
|
||||
if (ioptions_.compaction_options_universal.allow_trivial_move == true) {
|
||||
c->set_is_trivial_move(IsInputFilesNonOverlapping(c));
|
||||
}
|
||||
|
||||
@@ -377,7 +373,6 @@ Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
c->inputs(0)->size());
|
||||
|
||||
RegisterCompaction(c);
|
||||
vstorage->ComputeCompactionScore(ioptions_, mutable_cf_options);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("UniversalCompactionPicker::PickCompaction:Return",
|
||||
c);
|
||||
@@ -385,8 +380,7 @@ Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
}
|
||||
|
||||
uint32_t UniversalCompactionPicker::GetPathId(
|
||||
const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options, uint64_t file_size) {
|
||||
const ImmutableCFOptions& ioptions, uint64_t file_size) {
|
||||
// Two conditions need to be satisfied:
|
||||
// (1) the target path needs to be able to hold the file's size
|
||||
// (2) Total size left in this and previous paths need to be not
|
||||
@@ -403,12 +397,12 @@ uint32_t UniversalCompactionPicker::GetPathId(
|
||||
// that case. We need to improve it.
|
||||
uint64_t accumulated_size = 0;
|
||||
uint64_t future_size =
|
||||
file_size *
|
||||
(100 - mutable_cf_options.compaction_options_universal.size_ratio) / 100;
|
||||
file_size * (100 - ioptions.compaction_options_universal.size_ratio) /
|
||||
100;
|
||||
uint32_t p = 0;
|
||||
assert(!ioptions.cf_paths.empty());
|
||||
for (; p < ioptions.cf_paths.size() - 1; p++) {
|
||||
uint64_t target_size = ioptions.cf_paths[p].target_size;
|
||||
assert(!ioptions.db_paths.empty());
|
||||
for (; p < ioptions.db_paths.size() - 1; p++) {
|
||||
uint64_t target_size = ioptions.db_paths[p].target_size;
|
||||
if (target_size > file_size &&
|
||||
accumulated_size + (target_size - file_size) > future_size) {
|
||||
return p;
|
||||
@@ -428,9 +422,9 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSortedRuns(
|
||||
unsigned int max_number_of_files_to_compact,
|
||||
const std::vector<SortedRun>& sorted_runs, LogBuffer* log_buffer) {
|
||||
unsigned int min_merge_width =
|
||||
mutable_cf_options.compaction_options_universal.min_merge_width;
|
||||
ioptions_.compaction_options_universal.min_merge_width;
|
||||
unsigned int max_merge_width =
|
||||
mutable_cf_options.compaction_options_universal.max_merge_width;
|
||||
ioptions_.compaction_options_universal.max_merge_width;
|
||||
|
||||
const SortedRun* sr = nullptr;
|
||||
bool done = false;
|
||||
@@ -497,7 +491,7 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSortedRuns(
|
||||
if (sz < static_cast<double>(succeeding_sr->size)) {
|
||||
break;
|
||||
}
|
||||
if (mutable_cf_options.compaction_options_universal.stop_style ==
|
||||
if (ioptions_.compaction_options_universal.stop_style ==
|
||||
kCompactionStopStyleSimilarSize) {
|
||||
// Similar-size stopping rule: also check the last picked file isn't
|
||||
// far larger than the next candidate file.
|
||||
@@ -540,7 +534,7 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSortedRuns(
|
||||
// size ratio of compression.
|
||||
bool enable_compression = true;
|
||||
int ratio_to_compress =
|
||||
mutable_cf_options.compaction_options_universal.compression_size_percent;
|
||||
ioptions_.compaction_options_universal.compression_size_percent;
|
||||
if (ratio_to_compress >= 0) {
|
||||
uint64_t total_size = 0;
|
||||
for (auto& sorted_run : sorted_runs) {
|
||||
@@ -561,8 +555,7 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSortedRuns(
|
||||
for (unsigned int i = 0; i < first_index_after; i++) {
|
||||
estimated_total_size += sorted_runs[i].size;
|
||||
}
|
||||
uint32_t path_id =
|
||||
GetPathId(ioptions_, mutable_cf_options, estimated_total_size);
|
||||
uint32_t path_id = GetPathId(ioptions_, estimated_total_size);
|
||||
int start_level = sorted_runs[start_index].level;
|
||||
int output_level;
|
||||
if (first_index_after == sorted_runs.size()) {
|
||||
@@ -603,19 +596,17 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSortedRuns(
|
||||
|
||||
CompactionReason compaction_reason;
|
||||
if (max_number_of_files_to_compact == UINT_MAX) {
|
||||
compaction_reason = CompactionReason::kUniversalSizeRatio;
|
||||
} else {
|
||||
compaction_reason = CompactionReason::kUniversalSortedRunNum;
|
||||
} else {
|
||||
compaction_reason = CompactionReason::kUniversalSizeRatio;
|
||||
}
|
||||
return new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(inputs), output_level,
|
||||
MaxFileSizeForLevel(mutable_cf_options, output_level,
|
||||
kCompactionStyleUniversal),
|
||||
LLONG_MAX, path_id,
|
||||
mutable_cf_options.MaxFileSizeForLevel(output_level), LLONG_MAX, path_id,
|
||||
GetCompressionType(ioptions_, vstorage, mutable_cf_options, start_level,
|
||||
1, enable_compression),
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
score, false /* deletion_compaction */, compaction_reason);
|
||||
/* grandparents */ {}, /* is manual */ false, score,
|
||||
false /* deletion_compaction */, compaction_reason);
|
||||
}
|
||||
|
||||
// Look at overall size amplification. If size amplification
|
||||
@@ -629,8 +620,8 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSizeAmp(
|
||||
VersionStorageInfo* vstorage, double score,
|
||||
const std::vector<SortedRun>& sorted_runs, LogBuffer* log_buffer) {
|
||||
// percentage flexibility while reducing size amplification
|
||||
uint64_t ratio = mutable_cf_options.compaction_options_universal
|
||||
.max_size_amplification_percent;
|
||||
uint64_t ratio =
|
||||
ioptions_.compaction_options_universal.max_size_amplification_percent;
|
||||
|
||||
unsigned int candidate_count = 0;
|
||||
uint64_t candidate_size = 0;
|
||||
@@ -708,8 +699,7 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSizeAmp(
|
||||
for (size_t loop = start_index; loop < sorted_runs.size(); loop++) {
|
||||
estimated_total_size += sorted_runs[loop].size;
|
||||
}
|
||||
uint32_t path_id =
|
||||
GetPathId(ioptions_, mutable_cf_options, estimated_total_size);
|
||||
uint32_t path_id = GetPathId(ioptions_, estimated_total_size);
|
||||
int start_level = sorted_runs[start_index].level;
|
||||
|
||||
std::vector<CompactionInputFiles> inputs(vstorage->num_levels());
|
||||
@@ -744,13 +734,12 @@ Compaction* UniversalCompactionPicker::PickCompactionToReduceSizeAmp(
|
||||
|
||||
return new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, std::move(inputs),
|
||||
output_level, MaxFileSizeForLevel(mutable_cf_options, output_level,
|
||||
kCompactionStyleUniversal),
|
||||
output_level, mutable_cf_options.MaxFileSizeForLevel(output_level),
|
||||
/* max_grandparent_overlap_bytes */ LLONG_MAX, path_id,
|
||||
GetCompressionType(ioptions_, vstorage, mutable_cf_options,
|
||||
output_level, 1),
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
score, false /* deletion_compaction */,
|
||||
/* grandparents */ {}, /* is manual */ false, score,
|
||||
false /* deletion_compaction */,
|
||||
CompactionReason::kUniversalSizeAmplification);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -80,13 +80,11 @@ class UniversalCompactionPicker : public CompactionPicker {
|
||||
bool IsInputFilesNonOverlapping(Compaction* c);
|
||||
|
||||
static std::vector<SortedRun> CalculateSortedRuns(
|
||||
const VersionStorageInfo& vstorage, const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
const VersionStorageInfo& vstorage, const ImmutableCFOptions& ioptions);
|
||||
|
||||
// Pick a path ID to place a newly generated file, with its estimated file
|
||||
// size.
|
||||
static uint32_t GetPathId(const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
uint64_t file_size);
|
||||
};
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-149
@@ -2,7 +2,6 @@
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@@ -189,10 +188,10 @@ class DoubleComparator : public Comparator {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
virtual void FindShortestSeparator(std::string* /*start*/,
|
||||
const Slice& /*limit*/) const override {}
|
||||
virtual void FindShortestSeparator(std::string* start,
|
||||
const Slice& limit) const override {}
|
||||
|
||||
virtual void FindShortSuccessor(std::string* /*key*/) const override {}
|
||||
virtual void FindShortSuccessor(std::string* key) const override {}
|
||||
};
|
||||
|
||||
class HashComparator : public Comparator {
|
||||
@@ -212,10 +211,10 @@ class HashComparator : public Comparator {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
virtual void FindShortestSeparator(std::string* /*start*/,
|
||||
const Slice& /*limit*/) const override {}
|
||||
virtual void FindShortestSeparator(std::string* start,
|
||||
const Slice& limit) const override {}
|
||||
|
||||
virtual void FindShortSuccessor(std::string* /*key*/) const override {}
|
||||
virtual void FindShortSuccessor(std::string* key) const override {}
|
||||
};
|
||||
|
||||
class TwoStrComparator : public Comparator {
|
||||
@@ -244,10 +243,10 @@ class TwoStrComparator : public Comparator {
|
||||
}
|
||||
return a2.compare(b2);
|
||||
}
|
||||
virtual void FindShortestSeparator(std::string* /*start*/,
|
||||
const Slice& /*limit*/) const override {}
|
||||
virtual void FindShortestSeparator(std::string* start,
|
||||
const Slice& limit) const override {}
|
||||
|
||||
virtual void FindShortSuccessor(std::string* /*key*/) const override {}
|
||||
virtual void FindShortSuccessor(std::string* key) const override {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -434,145 +433,6 @@ TEST_F(ComparatorDBTest, TwoStrComparator) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ComparatorDBTest, FindShortestSeparator) {
|
||||
std::string s1 = "abc1xyz";
|
||||
std::string s2 = "abc3xy";
|
||||
|
||||
BytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_EQ("abc2", s1);
|
||||
|
||||
s1 = "abc5xyztt";
|
||||
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_EQ("abc5", s1);
|
||||
|
||||
s1 = "abc3";
|
||||
s2 = "abc2xy";
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_EQ("abc3", s1);
|
||||
|
||||
s1 = "abc3xyz";
|
||||
s2 = "abc2xy";
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_EQ("abc3", s1);
|
||||
|
||||
s1 = "abc3xyz";
|
||||
s2 = "abc2";
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_EQ("abc3", s1);
|
||||
|
||||
std::string old_s1 = s1 = "abc2xy";
|
||||
s2 = "abc2";
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
|
||||
ASSERT_TRUE(old_s1 >= s1);
|
||||
ASSERT_TRUE(s1 > s2);
|
||||
}
|
||||
|
||||
TEST_F(ComparatorDBTest, SeparatorSuccessorRandomizeTest) {
|
||||
// Char list for boundary cases.
|
||||
std::array<unsigned char, 6> char_list{{0, 1, 2, 253, 254, 255}};
|
||||
Random rnd(301);
|
||||
|
||||
for (int attempts = 0; attempts < 1000; attempts++) {
|
||||
uint32_t size1 = rnd.Skewed(4);
|
||||
uint32_t size2;
|
||||
|
||||
if (rnd.OneIn(2)) {
|
||||
// size2 to be random size
|
||||
size2 = rnd.Skewed(4);
|
||||
} else {
|
||||
// size1 is within [-2, +2] of size1
|
||||
int diff = static_cast<int>(rnd.Uniform(5)) - 2;
|
||||
int tmp_size2 = static_cast<int>(size1) + diff;
|
||||
if (tmp_size2 < 0) {
|
||||
tmp_size2 = 0;
|
||||
}
|
||||
size2 = static_cast<uint32_t>(tmp_size2);
|
||||
}
|
||||
|
||||
std::string s1;
|
||||
std::string s2;
|
||||
for (uint32_t i = 0; i < size1; i++) {
|
||||
if (rnd.OneIn(2)) {
|
||||
// Use random byte
|
||||
s1 += static_cast<char>(rnd.Uniform(256));
|
||||
} else {
|
||||
// Use one byte in char_list
|
||||
char c = static_cast<char>(char_list[rnd.Uniform(sizeof(char_list))]);
|
||||
s1 += c;
|
||||
}
|
||||
}
|
||||
|
||||
// First set s2 to be the same as s1, and then modify s2.
|
||||
s2 = s1;
|
||||
s2.resize(size2);
|
||||
// We start from the back of the string
|
||||
if (size2 > 0) {
|
||||
uint32_t pos = size2 - 1;
|
||||
do {
|
||||
if (pos >= size1 || rnd.OneIn(4)) {
|
||||
// For 1/4 chance, use random byte
|
||||
s2[pos] = static_cast<char>(rnd.Uniform(256));
|
||||
} else if (rnd.OneIn(4)) {
|
||||
// In 1/4 chance, stop here.
|
||||
break;
|
||||
} else {
|
||||
// Create a char within [-2, +2] of the matching char of s1.
|
||||
int diff = static_cast<int>(rnd.Uniform(5)) - 2;
|
||||
// char may be signed or unsigned based on platform.
|
||||
int s1_char = static_cast<int>(static_cast<unsigned char>(s1[pos]));
|
||||
int s2_char = s1_char + diff;
|
||||
if (s2_char < 0) {
|
||||
s2_char = 0;
|
||||
}
|
||||
if (s2_char > 255) {
|
||||
s2_char = 255;
|
||||
}
|
||||
s2[pos] = static_cast<char>(s2_char);
|
||||
}
|
||||
} while (pos-- != 0);
|
||||
}
|
||||
|
||||
// Test separators
|
||||
for (int rev = 0; rev < 2; rev++) {
|
||||
if (rev == 1) {
|
||||
// switch s1 and s2
|
||||
std::string t = s1;
|
||||
s1 = s2;
|
||||
s2 = t;
|
||||
}
|
||||
std::string separator = s1;
|
||||
BytewiseComparator()->FindShortestSeparator(&separator, s2);
|
||||
std::string rev_separator = s1;
|
||||
ReverseBytewiseComparator()->FindShortestSeparator(&rev_separator, s2);
|
||||
|
||||
if (s1 == s2) {
|
||||
ASSERT_EQ(s1, separator);
|
||||
ASSERT_EQ(s2, rev_separator);
|
||||
} else if (s1 < s2) {
|
||||
ASSERT_TRUE(s1 <= separator);
|
||||
ASSERT_TRUE(s2 > separator);
|
||||
ASSERT_LE(separator.size(), std::max(s1.size(), s2.size()));
|
||||
ASSERT_EQ(s1, rev_separator);
|
||||
} else {
|
||||
ASSERT_TRUE(s1 >= rev_separator);
|
||||
ASSERT_TRUE(s2 < rev_separator);
|
||||
ASSERT_LE(rev_separator.size(), std::max(s1.size(), s2.size()));
|
||||
ASSERT_EQ(s1, separator);
|
||||
}
|
||||
}
|
||||
|
||||
// Test successors
|
||||
std::string succ = s1;
|
||||
BytewiseComparator()->FindShortSuccessor(&succ);
|
||||
ASSERT_TRUE(succ >= s1);
|
||||
|
||||
succ = s1;
|
||||
ReverseBytewiseComparator()->FindShortSuccessor(&succ);
|
||||
ASSERT_TRUE(succ <= s1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
+4
-44
@@ -9,57 +9,17 @@
|
||||
#include "rocksdb/convenience.h"
|
||||
|
||||
#include "db/db_impl.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
void CancelAllBackgroundWork(DB* db, bool wait) {
|
||||
(static_cast_with_check<DBImpl, DB>(db->GetRootDB()))
|
||||
->CancelAllBackgroundWork(wait);
|
||||
(dynamic_cast<DBImpl*>(db->GetRootDB()))->CancelAllBackgroundWork(wait);
|
||||
}
|
||||
|
||||
Status DeleteFilesInRange(DB* db, ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end,
|
||||
bool include_end) {
|
||||
RangePtr range(begin, end);
|
||||
return DeleteFilesInRanges(db, column_family, &range, 1, include_end);
|
||||
}
|
||||
|
||||
Status DeleteFilesInRanges(DB* db, ColumnFamilyHandle* column_family,
|
||||
const RangePtr* ranges, size_t n,
|
||||
bool include_end) {
|
||||
return (static_cast_with_check<DBImpl, DB>(db->GetRootDB()))
|
||||
->DeleteFilesInRanges(column_family, ranges, n, include_end);
|
||||
}
|
||||
|
||||
Status VerifySstFileChecksum(const Options& options,
|
||||
const EnvOptions& env_options,
|
||||
const std::string& file_path) {
|
||||
unique_ptr<RandomAccessFile> file;
|
||||
uint64_t file_size;
|
||||
InternalKeyComparator internal_comparator(options.comparator);
|
||||
ImmutableCFOptions ioptions(options);
|
||||
|
||||
Status s = ioptions.env->NewRandomAccessFile(file_path, &file, env_options);
|
||||
if (s.ok()) {
|
||||
s = ioptions.env->GetFileSize(file_path, &file_size);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
unique_ptr<TableReader> table_reader;
|
||||
std::unique_ptr<RandomAccessFileReader> file_reader(
|
||||
new RandomAccessFileReader(std::move(file), file_path));
|
||||
s = ioptions.table_factory->NewTableReader(
|
||||
TableReaderOptions(ioptions, options.prefix_extractor.get(), env_options,
|
||||
internal_comparator, false /* skip_filters */,
|
||||
-1 /* level */),
|
||||
std::move(file_reader), file_size, &table_reader,
|
||||
false /* prefetch_index_and_filter_in_cache */);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
s = table_reader->VerifyChecksum();
|
||||
return s;
|
||||
const Slice* begin, const Slice* end) {
|
||||
return (dynamic_cast<DBImpl*>(db->GetRootDB()))
|
||||
->DeleteFilesInRange(column_family, begin, end);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
+5
-16
@@ -20,7 +20,6 @@
|
||||
#include "db/log_format.h"
|
||||
#include "db/version_set.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
@@ -153,7 +152,7 @@ class CorruptionTest : public testing::Test {
|
||||
struct stat sbuf;
|
||||
if (stat(fname.c_str(), &sbuf) != 0) {
|
||||
const char* msg = strerror(errno);
|
||||
FAIL() << fname << ": " << msg;
|
||||
ASSERT_TRUE(false) << fname << ": " << msg;
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
@@ -180,9 +179,6 @@ class CorruptionTest : public testing::Test {
|
||||
}
|
||||
s = WriteStringToFile(Env::Default(), contents, fname);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
Options options;
|
||||
EnvOptions env_options;
|
||||
ASSERT_NOK(VerifySstFileChecksum(options, env_options, fname));
|
||||
}
|
||||
|
||||
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
|
||||
@@ -217,7 +213,7 @@ class CorruptionTest : public testing::Test {
|
||||
return;
|
||||
}
|
||||
}
|
||||
FAIL() << "no file found at level";
|
||||
ASSERT_TRUE(false) << "no file found at level";
|
||||
}
|
||||
|
||||
|
||||
@@ -316,7 +312,6 @@ TEST_F(CorruptionTest, TableFile) {
|
||||
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
Check(99, 99);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
}
|
||||
|
||||
TEST_F(CorruptionTest, TableFileIndexData) {
|
||||
@@ -332,11 +327,9 @@ TEST_F(CorruptionTest, TableFileIndexData) {
|
||||
// corrupt an index block of an entire file
|
||||
Corrupt(kTableFile, -2000, 500);
|
||||
Reopen();
|
||||
dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
// one full file may be readable, since only one was corrupted
|
||||
// one full file should be readable, since only one was corrupted
|
||||
// the other file should be fully non-readable, since index was corrupted
|
||||
Check(0, 5000);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
Check(5000, 5000);
|
||||
}
|
||||
|
||||
TEST_F(CorruptionTest, MissingDescriptor) {
|
||||
@@ -396,12 +389,10 @@ TEST_F(CorruptionTest, CompactionInputError) {
|
||||
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
Check(9, 9);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
|
||||
// Force compactions by writing lots of values
|
||||
Build(10000);
|
||||
Check(10000, 10000);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
}
|
||||
|
||||
TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
|
||||
@@ -433,7 +424,6 @@ TEST_F(CorruptionTest, CompactionInputErrorParanoid) {
|
||||
|
||||
CorruptTableFileAtLevel(0, 100, 1);
|
||||
Check(9, 9);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
|
||||
// Write must eventually fail because of corrupted table
|
||||
Status s;
|
||||
@@ -455,7 +445,6 @@ TEST_F(CorruptionTest, UnrelatedKeys) {
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_FlushMemTable();
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
|
||||
std::string tmp1, tmp2;
|
||||
ASSERT_OK(db_->Put(WriteOptions(), Key(1000, &tmp1), Value(1000, &tmp2)));
|
||||
@@ -510,7 +499,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as RepairDB() is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ TEST_F(CuckooTableDBTest, CompactionIntoMultipleFiles) {
|
||||
|
||||
// Write 28 values, each 10016 B ~ 10KB
|
||||
for (int idx = 0; idx < 28; ++idx) {
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + idx)));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_EQ("1", FilesPerLevel());
|
||||
@@ -250,7 +250,7 @@ TEST_F(CuckooTableDBTest, CompactionIntoMultipleFiles) {
|
||||
true /* disallow trivial move */);
|
||||
ASSERT_EQ("0,2", FilesPerLevel());
|
||||
for (int idx = 0; idx < 28; ++idx) {
|
||||
ASSERT_EQ(std::string(10000, 'a' + char(idx)), Get(Key(idx)));
|
||||
ASSERT_EQ(std::string(10000, 'a' + idx), Get(Key(idx)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,14 +271,14 @@ TEST_F(CuckooTableDBTest, SameKeyInsertedInTwoDifferentFilesAndCompacted) {
|
||||
|
||||
// Generate one more file in level-0, and should trigger level-0 compaction
|
||||
for (int idx = 0; idx < 11; ++idx) {
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + idx)));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
for (int idx = 0; idx < 11; ++idx) {
|
||||
ASSERT_EQ(std::string(10000, 'a' + char(idx)), Get(Key(idx)));
|
||||
ASSERT_EQ(std::string(10000, 'a' + idx), Get(Key(idx)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ int main(int argc, char** argv) {
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
int main(int argc, char** argv) {
|
||||
fprintf(stderr, "SKIPPED as Cuckoo table is not supported in ROCKSDB_LITE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+36
-146
@@ -9,7 +9,6 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "util/fault_injection_test_env.h"
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "util/sync_point.h"
|
||||
#endif
|
||||
@@ -42,7 +41,7 @@ TEST_F(DBBasicTest, ReadOnlyDB) {
|
||||
Close();
|
||||
|
||||
auto options = CurrentOptions();
|
||||
assert(options.env == env_);
|
||||
assert(options.env = env_);
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ASSERT_EQ("v3", Get("foo"));
|
||||
ASSERT_EQ("v2", Get("bar"));
|
||||
@@ -176,8 +175,6 @@ TEST_F(DBBasicTest, LevelLimitReopen) {
|
||||
int i = 0;
|
||||
while (NumTableFilesAtLevel(2, 1) == 0) {
|
||||
ASSERT_OK(Put(1, Key(i++), value));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
}
|
||||
|
||||
options.num_levels = 1;
|
||||
@@ -361,6 +358,7 @@ TEST_F(DBBasicTest, FLUSH) {
|
||||
WriteOptions writeOpt = WriteOptions();
|
||||
writeOpt.disableWAL = true;
|
||||
SetPerfLevel(kEnableTime);
|
||||
;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "foo", "v1"));
|
||||
// this will now also flush the last 2 writes
|
||||
ASSERT_OK(Flush(1));
|
||||
@@ -369,7 +367,6 @@ TEST_F(DBBasicTest, FLUSH) {
|
||||
get_perf_context()->Reset();
|
||||
Get(1, "foo");
|
||||
ASSERT_TRUE((int)get_perf_context()->get_from_output_files_time > 0);
|
||||
ASSERT_EQ(2, (int)get_perf_context()->get_read_bytes);
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, CurrentOptions());
|
||||
ASSERT_EQ("v1", Get(1, "foo"));
|
||||
@@ -571,19 +568,19 @@ TEST_F(DBBasicTest, CompactBetweenSnapshots) {
|
||||
|
||||
TEST_F(DBBasicTest, DBOpen_Options) {
|
||||
Options options = CurrentOptions();
|
||||
Close();
|
||||
Destroy(options);
|
||||
std::string dbname = test::TmpDir(env_) + "/db_options_test";
|
||||
ASSERT_OK(DestroyDB(dbname, options));
|
||||
|
||||
// Does not exist, and create_if_missing == false: error
|
||||
DB* db = nullptr;
|
||||
options.create_if_missing = false;
|
||||
Status s = DB::Open(options, dbname_, &db);
|
||||
Status s = DB::Open(options, dbname, &db);
|
||||
ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != nullptr);
|
||||
ASSERT_TRUE(db == nullptr);
|
||||
|
||||
// Does not exist, and create_if_missing == true: OK
|
||||
options.create_if_missing = true;
|
||||
s = DB::Open(options, dbname_, &db);
|
||||
s = DB::Open(options, dbname, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_TRUE(db != nullptr);
|
||||
|
||||
@@ -593,14 +590,14 @@ TEST_F(DBBasicTest, DBOpen_Options) {
|
||||
// Does exist, and error_if_exists == true: error
|
||||
options.create_if_missing = false;
|
||||
options.error_if_exists = true;
|
||||
s = DB::Open(options, dbname_, &db);
|
||||
s = DB::Open(options, dbname, &db);
|
||||
ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != nullptr);
|
||||
ASSERT_TRUE(db == nullptr);
|
||||
|
||||
// Does exist, and error_if_exists == false: OK
|
||||
options.create_if_missing = true;
|
||||
options.error_if_exists = false;
|
||||
s = DB::Open(options, dbname_, &db);
|
||||
s = DB::Open(options, dbname, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_TRUE(db != nullptr);
|
||||
|
||||
@@ -726,7 +723,6 @@ TEST_F(DBBasicTest, FlushOneColumnFamily) {
|
||||
TEST_F(DBBasicTest, MultiGetSimple) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
SetPerfLevel(kEnableCount);
|
||||
ASSERT_OK(Put(1, "k1", "v1"));
|
||||
ASSERT_OK(Put(1, "k2", "v2"));
|
||||
ASSERT_OK(Put(1, "k3", "v3"));
|
||||
@@ -740,15 +736,12 @@ TEST_F(DBBasicTest, MultiGetSimple) {
|
||||
std::vector<std::string> values(20, "Temporary data to be overwritten");
|
||||
std::vector<ColumnFamilyHandle*> cfs(keys.size(), handles_[1]);
|
||||
|
||||
get_perf_context()->Reset();
|
||||
std::vector<Status> s = db_->MultiGet(ReadOptions(), cfs, keys, &values);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
ASSERT_EQ(values[0], "v1");
|
||||
ASSERT_EQ(values[1], "v2");
|
||||
ASSERT_EQ(values[2], "v3");
|
||||
ASSERT_EQ(values[4], "v5");
|
||||
// four kv pairs * two bytes per value
|
||||
ASSERT_EQ(8, (int)get_perf_context()->multiget_read_bytes);
|
||||
|
||||
ASSERT_OK(s[0]);
|
||||
ASSERT_OK(s[1]);
|
||||
@@ -756,7 +749,6 @@ TEST_F(DBBasicTest, MultiGetSimple) {
|
||||
ASSERT_TRUE(s[3].IsNotFound());
|
||||
ASSERT_OK(s[4]);
|
||||
ASSERT_TRUE(s[5].IsNotFound());
|
||||
SetPerfLevel(kDisable);
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
@@ -793,30 +785,36 @@ TEST_F(DBBasicTest, MultiGetEmpty) {
|
||||
TEST_F(DBBasicTest, ChecksumTest) {
|
||||
BlockBasedTableOptions table_options;
|
||||
Options options = CurrentOptions();
|
||||
// change when new checksum type added
|
||||
int max_checksum = static_cast<int>(kxxHash);
|
||||
const int kNumPerFile = 2;
|
||||
|
||||
// generate one table with each type of checksum
|
||||
for (int i = 0; i <= max_checksum; ++i) {
|
||||
table_options.checksum = static_cast<ChecksumType>(i);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
for (int j = 0; j < kNumPerFile; ++j) {
|
||||
ASSERT_OK(Put(Key(i * kNumPerFile + j), Key(i * kNumPerFile + j)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
table_options.checksum = kCRC32c;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("a", "b"));
|
||||
ASSERT_OK(Put("c", "d"));
|
||||
ASSERT_OK(Flush()); // table with crc checksum
|
||||
|
||||
// verify data with each type of checksum
|
||||
for (int i = 0; i <= kxxHash; ++i) {
|
||||
table_options.checksum = static_cast<ChecksumType>(i);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
for (int j = 0; j < (max_checksum + 1) * kNumPerFile; ++j) {
|
||||
ASSERT_EQ(Key(j), Get(Key(j)));
|
||||
}
|
||||
}
|
||||
table_options.checksum = kxxHash;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("e", "f"));
|
||||
ASSERT_OK(Put("g", "h"));
|
||||
ASSERT_OK(Flush()); // table with xxhash checksum
|
||||
|
||||
table_options.checksum = kCRC32c;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
ASSERT_EQ("b", Get("a"));
|
||||
ASSERT_EQ("d", Get("c"));
|
||||
ASSERT_EQ("f", Get("e"));
|
||||
ASSERT_EQ("h", Get("g"));
|
||||
|
||||
table_options.checksum = kCRC32c;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
ASSERT_EQ("b", Get("a"));
|
||||
ASSERT_EQ("d", Get("c"));
|
||||
ASSERT_EQ("f", Get("e"));
|
||||
ASSERT_EQ("h", Get("g"));
|
||||
}
|
||||
|
||||
// On Windows you can have either memory mapped file or a file
|
||||
@@ -848,114 +846,6 @@ TEST_F(DBBasicTest, MmapAndBufferOptions) {
|
||||
}
|
||||
#endif
|
||||
|
||||
class TestEnv : public EnvWrapper {
|
||||
public:
|
||||
explicit TestEnv() : EnvWrapper(Env::Default()),
|
||||
close_count(0) { }
|
||||
|
||||
class TestLogger : public Logger {
|
||||
public:
|
||||
using Logger::Logv;
|
||||
TestLogger(TestEnv *env_ptr) : Logger() { env = env_ptr; }
|
||||
~TestLogger() {
|
||||
if (!closed_) {
|
||||
CloseHelper();
|
||||
}
|
||||
}
|
||||
virtual void Logv(const char* /*format*/, va_list /*ap*/) override{};
|
||||
|
||||
protected:
|
||||
virtual Status CloseImpl() override {
|
||||
return CloseHelper();
|
||||
}
|
||||
private:
|
||||
Status CloseHelper() {
|
||||
env->CloseCountInc();;
|
||||
return Status::IOError();
|
||||
}
|
||||
TestEnv *env;
|
||||
};
|
||||
|
||||
void CloseCountInc() { close_count++; }
|
||||
|
||||
int GetCloseCount() { return close_count; }
|
||||
|
||||
virtual Status NewLogger(const std::string& /*fname*/,
|
||||
shared_ptr<Logger>* result) {
|
||||
result->reset(new TestLogger(this));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
int close_count;
|
||||
};
|
||||
|
||||
TEST_F(DBBasicTest, DBClose) {
|
||||
Options options = GetDefaultOptions();
|
||||
std::string dbname = test::TmpDir(env_) + "/db_close_test";
|
||||
ASSERT_OK(DestroyDB(dbname, options));
|
||||
|
||||
DB* db = nullptr;
|
||||
TestEnv* env = new TestEnv();
|
||||
options.create_if_missing = true;
|
||||
options.env = env;
|
||||
Status s = DB::Open(options, dbname, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_TRUE(db != nullptr);
|
||||
|
||||
s = db->Close();
|
||||
ASSERT_EQ(env->GetCloseCount(), 1);
|
||||
ASSERT_EQ(s, Status::IOError());
|
||||
|
||||
delete db;
|
||||
ASSERT_EQ(env->GetCloseCount(), 1);
|
||||
|
||||
// Do not call DB::Close() and ensure our logger Close() still gets called
|
||||
s = DB::Open(options, dbname, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_TRUE(db != nullptr);
|
||||
delete db;
|
||||
ASSERT_EQ(env->GetCloseCount(), 2);
|
||||
|
||||
// Provide our own logger and ensure DB::Close() does not close it
|
||||
options.info_log.reset(new TestEnv::TestLogger(env));
|
||||
options.create_if_missing = false;
|
||||
s = DB::Open(options, dbname, &db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_TRUE(db != nullptr);
|
||||
|
||||
s = db->Close();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
delete db;
|
||||
ASSERT_EQ(env->GetCloseCount(), 2);
|
||||
options.info_log.reset();
|
||||
ASSERT_EQ(env->GetCloseCount(), 3);
|
||||
|
||||
delete options.env;
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, DBCloseFlushError) {
|
||||
std::unique_ptr<FaultInjectionTestEnv> fault_injection_env(
|
||||
new FaultInjectionTestEnv(Env::Default()));
|
||||
Options options = GetDefaultOptions();
|
||||
options.create_if_missing = true;
|
||||
options.manual_wal_flush = true;
|
||||
options.write_buffer_size=100;
|
||||
options.env = fault_injection_env.get();
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("key1", "value1"));
|
||||
ASSERT_OK(Put("key2", "value2"));
|
||||
ASSERT_OK(dbfull()->TEST_SwitchMemtable());
|
||||
ASSERT_OK(Put("key3", "value3"));
|
||||
fault_injection_env->SetFilesystemActive(false);
|
||||
Status s = dbfull()->Close();
|
||||
fault_injection_env->SetFilesystemActive(true);
|
||||
ASSERT_NE(s, Status::OK());
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -1,410 +0,0 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// 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 <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "db/column_family.h"
|
||||
#include "db/db_iter.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// kTypeBlobIndex is a value type used by BlobDB only. The base rocksdb
|
||||
// should accept the value type on write, and report not supported value
|
||||
// for reads, unless caller request for it explicitly. The base rocksdb
|
||||
// doesn't understand format of actual blob index (the value).
|
||||
class DBBlobIndexTest : public DBTestBase {
|
||||
public:
|
||||
enum Tier {
|
||||
kMemtable = 0,
|
||||
kImmutableMemtables = 1,
|
||||
kL0SstFile = 2,
|
||||
kLnSstFile = 3,
|
||||
};
|
||||
const std::vector<Tier> kAllTiers = {Tier::kMemtable,
|
||||
Tier::kImmutableMemtables,
|
||||
Tier::kL0SstFile, Tier::kLnSstFile};
|
||||
|
||||
DBBlobIndexTest() : DBTestBase("/db_blob_index_test") {}
|
||||
|
||||
ColumnFamilyHandle* cfh() { return dbfull()->DefaultColumnFamily(); }
|
||||
|
||||
ColumnFamilyData* cfd() {
|
||||
return reinterpret_cast<ColumnFamilyHandleImpl*>(cfh())->cfd();
|
||||
}
|
||||
|
||||
Status PutBlobIndex(WriteBatch* batch, const Slice& key,
|
||||
const Slice& blob_index) {
|
||||
return WriteBatchInternal::PutBlobIndex(batch, cfd()->GetID(), key,
|
||||
blob_index);
|
||||
}
|
||||
|
||||
Status Write(WriteBatch* batch) {
|
||||
return dbfull()->Write(WriteOptions(), batch);
|
||||
}
|
||||
|
||||
std::string GetImpl(const Slice& key, bool* is_blob_index = nullptr,
|
||||
const Snapshot* snapshot = nullptr) {
|
||||
ReadOptions read_options;
|
||||
read_options.snapshot = snapshot;
|
||||
PinnableSlice value;
|
||||
auto s = dbfull()->GetImpl(read_options, cfh(), key, &value,
|
||||
nullptr /*value_found*/, nullptr /*callback*/,
|
||||
is_blob_index);
|
||||
if (s.IsNotFound()) {
|
||||
return "NOT_FOUND";
|
||||
}
|
||||
if (s.IsNotSupported()) {
|
||||
return "NOT_SUPPORTED";
|
||||
}
|
||||
if (!s.ok()) {
|
||||
return s.ToString();
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
std::string GetBlobIndex(const Slice& key,
|
||||
const Snapshot* snapshot = nullptr) {
|
||||
bool is_blob_index = false;
|
||||
std::string value = GetImpl(key, &is_blob_index, snapshot);
|
||||
if (!is_blob_index) {
|
||||
return "NOT_BLOB";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
ArenaWrappedDBIter* GetBlobIterator() {
|
||||
return dbfull()->NewIteratorImpl(
|
||||
ReadOptions(), cfd(), dbfull()->GetLatestSequenceNumber(),
|
||||
nullptr /*read_callback*/, true /*allow_blob*/);
|
||||
}
|
||||
|
||||
Options GetTestOptions() {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.num_levels = 2;
|
||||
options.disable_auto_compactions = true;
|
||||
// Disable auto flushes.
|
||||
options.max_write_buffer_number = 10;
|
||||
options.min_write_buffer_number_to_merge = 10;
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
return options;
|
||||
}
|
||||
|
||||
void MoveDataTo(Tier tier) {
|
||||
switch (tier) {
|
||||
case Tier::kMemtable:
|
||||
break;
|
||||
case Tier::kImmutableMemtables:
|
||||
ASSERT_OK(dbfull()->TEST_SwitchMemtable());
|
||||
break;
|
||||
case Tier::kL0SstFile:
|
||||
ASSERT_OK(Flush());
|
||||
break;
|
||||
case Tier::kLnSstFile:
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("a", "dummy"));
|
||||
ASSERT_OK(Put("z", "dummy"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
#endif // !ROCKSDB_LITE
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Should be able to write kTypeBlobIndex to memtables and SST files.
|
||||
TEST_F(DBBlobIndexTest, Write) {
|
||||
for (auto tier : kAllTiers) {
|
||||
DestroyAndReopen(GetTestOptions());
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
std::string index = ToString(i);
|
||||
WriteBatch batch;
|
||||
ASSERT_OK(PutBlobIndex(&batch, "key" + index, "blob" + index));
|
||||
ASSERT_OK(Write(&batch));
|
||||
}
|
||||
MoveDataTo(tier);
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
std::string index = ToString(i);
|
||||
ASSERT_EQ("blob" + index, GetBlobIndex("key" + index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get should be able to return blob index if is_blob_index is provided,
|
||||
// otherwise return Status::NotSupported status.
|
||||
TEST_F(DBBlobIndexTest, Get) {
|
||||
for (auto tier : kAllTiers) {
|
||||
DestroyAndReopen(GetTestOptions());
|
||||
WriteBatch batch;
|
||||
ASSERT_OK(batch.Put("key", "value"));
|
||||
ASSERT_OK(PutBlobIndex(&batch, "blob_key", "blob_index"));
|
||||
ASSERT_OK(Write(&batch));
|
||||
MoveDataTo(tier);
|
||||
// Verify normal value
|
||||
bool is_blob_index = false;
|
||||
PinnableSlice value;
|
||||
ASSERT_EQ("value", Get("key"));
|
||||
ASSERT_EQ("value", GetImpl("key"));
|
||||
ASSERT_EQ("value", GetImpl("key", &is_blob_index));
|
||||
ASSERT_FALSE(is_blob_index);
|
||||
// Verify blob index
|
||||
ASSERT_TRUE(Get("blob_key", &value).IsNotSupported());
|
||||
ASSERT_EQ("NOT_SUPPORTED", GetImpl("blob_key"));
|
||||
ASSERT_EQ("blob_index", GetImpl("blob_key", &is_blob_index));
|
||||
ASSERT_TRUE(is_blob_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Get should NOT return Status::NotSupported if blob index is updated with
|
||||
// a normal value.
|
||||
TEST_F(DBBlobIndexTest, Updated) {
|
||||
for (auto tier : kAllTiers) {
|
||||
DestroyAndReopen(GetTestOptions());
|
||||
WriteBatch batch;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(PutBlobIndex(&batch, "key" + ToString(i), "blob_index"));
|
||||
}
|
||||
ASSERT_OK(Write(&batch));
|
||||
// Avoid blob values from being purged.
|
||||
const Snapshot* snapshot = dbfull()->GetSnapshot();
|
||||
ASSERT_OK(Put("key1", "new_value"));
|
||||
ASSERT_OK(Merge("key2", "a"));
|
||||
ASSERT_OK(Merge("key2", "b"));
|
||||
ASSERT_OK(Merge("key2", "c"));
|
||||
ASSERT_OK(Delete("key3"));
|
||||
ASSERT_OK(SingleDelete("key4"));
|
||||
ASSERT_OK(Delete("key5"));
|
||||
ASSERT_OK(Merge("key5", "a"));
|
||||
ASSERT_OK(Merge("key5", "b"));
|
||||
ASSERT_OK(Merge("key5", "c"));
|
||||
ASSERT_OK(dbfull()->DeleteRange(WriteOptions(), cfh(), "key6", "key9"));
|
||||
MoveDataTo(tier);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_EQ("blob_index", GetBlobIndex("key" + ToString(i), snapshot));
|
||||
}
|
||||
ASSERT_EQ("new_value", Get("key1"));
|
||||
ASSERT_EQ("NOT_SUPPORTED", GetImpl("key2"));
|
||||
ASSERT_EQ("NOT_FOUND", Get("key3"));
|
||||
ASSERT_EQ("NOT_FOUND", Get("key4"));
|
||||
ASSERT_EQ("a,b,c", GetImpl("key5"));
|
||||
for (int i = 6; i < 9; i++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get("key" + ToString(i)));
|
||||
}
|
||||
ASSERT_EQ("blob_index", GetBlobIndex("key9"));
|
||||
dbfull()->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator should get blob value if allow_blob flag is set,
|
||||
// otherwise return Status::NotSupported status.
|
||||
TEST_F(DBBlobIndexTest, Iterate) {
|
||||
const std::vector<std::vector<ValueType>> data = {
|
||||
/*00*/ {kTypeValue},
|
||||
/*01*/ {kTypeBlobIndex},
|
||||
/*02*/ {kTypeValue},
|
||||
/*03*/ {kTypeBlobIndex, kTypeValue},
|
||||
/*04*/ {kTypeValue},
|
||||
/*05*/ {kTypeValue, kTypeBlobIndex},
|
||||
/*06*/ {kTypeValue},
|
||||
/*07*/ {kTypeDeletion, kTypeBlobIndex},
|
||||
/*08*/ {kTypeValue},
|
||||
/*09*/ {kTypeSingleDeletion, kTypeBlobIndex},
|
||||
/*10*/ {kTypeValue},
|
||||
/*11*/ {kTypeMerge, kTypeMerge, kTypeMerge, kTypeBlobIndex},
|
||||
/*12*/ {kTypeValue},
|
||||
/*13*/
|
||||
{kTypeMerge, kTypeMerge, kTypeMerge, kTypeDeletion, kTypeBlobIndex},
|
||||
/*14*/ {kTypeValue},
|
||||
/*15*/ {kTypeBlobIndex},
|
||||
/*16*/ {kTypeValue},
|
||||
};
|
||||
|
||||
auto get_key = [](int index) {
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "%02d", index);
|
||||
return "key" + std::string(buf);
|
||||
};
|
||||
|
||||
auto get_value = [&](int index, int version) {
|
||||
return get_key(index) + "_value" + ToString(version);
|
||||
};
|
||||
|
||||
auto check_iterator = [&](Iterator* iterator, Status::Code expected_status,
|
||||
const Slice& expected_value) {
|
||||
ASSERT_EQ(expected_status, iterator->status().code());
|
||||
if (expected_status == Status::kOk) {
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ(expected_value, iterator->value());
|
||||
} else {
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
}
|
||||
};
|
||||
|
||||
auto create_normal_iterator = [&]() -> Iterator* {
|
||||
return dbfull()->NewIterator(ReadOptions());
|
||||
};
|
||||
|
||||
auto create_blob_iterator = [&]() -> Iterator* { return GetBlobIterator(); };
|
||||
|
||||
auto check_is_blob = [&](bool is_blob) {
|
||||
return [is_blob](Iterator* iterator) {
|
||||
ASSERT_EQ(is_blob,
|
||||
reinterpret_cast<ArenaWrappedDBIter*>(iterator)->IsBlob());
|
||||
};
|
||||
};
|
||||
|
||||
auto verify = [&](int index, Status::Code expected_status,
|
||||
const Slice& forward_value, const Slice& backward_value,
|
||||
std::function<Iterator*()> create_iterator,
|
||||
std::function<void(Iterator*)> extra_check = nullptr) {
|
||||
// Seek
|
||||
auto* iterator = create_iterator();
|
||||
ASSERT_OK(iterator->Refresh());
|
||||
iterator->Seek(get_key(index));
|
||||
check_iterator(iterator, expected_status, forward_value);
|
||||
if (extra_check) {
|
||||
extra_check(iterator);
|
||||
}
|
||||
delete iterator;
|
||||
|
||||
// Next
|
||||
iterator = create_iterator();
|
||||
ASSERT_OK(iterator->Refresh());
|
||||
iterator->Seek(get_key(index - 1));
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
iterator->Next();
|
||||
check_iterator(iterator, expected_status, forward_value);
|
||||
if (extra_check) {
|
||||
extra_check(iterator);
|
||||
}
|
||||
delete iterator;
|
||||
|
||||
// SeekForPrev
|
||||
iterator = create_iterator();
|
||||
ASSERT_OK(iterator->Refresh());
|
||||
iterator->SeekForPrev(get_key(index));
|
||||
check_iterator(iterator, expected_status, backward_value);
|
||||
if (extra_check) {
|
||||
extra_check(iterator);
|
||||
}
|
||||
delete iterator;
|
||||
|
||||
// Prev
|
||||
iterator = create_iterator();
|
||||
iterator->Seek(get_key(index + 1));
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
iterator->Prev();
|
||||
check_iterator(iterator, expected_status, backward_value);
|
||||
if (extra_check) {
|
||||
extra_check(iterator);
|
||||
}
|
||||
delete iterator;
|
||||
};
|
||||
|
||||
for (auto tier : {Tier::kMemtable} /*kAllTiers*/) {
|
||||
// Avoid values from being purged.
|
||||
std::vector<const Snapshot*> snapshots;
|
||||
DestroyAndReopen(GetTestOptions());
|
||||
|
||||
// fill data
|
||||
for (int i = 0; i < static_cast<int>(data.size()); i++) {
|
||||
for (int j = static_cast<int>(data[i].size()) - 1; j >= 0; j--) {
|
||||
std::string key = get_key(i);
|
||||
std::string value = get_value(i, j);
|
||||
WriteBatch batch;
|
||||
switch (data[i][j]) {
|
||||
case kTypeValue:
|
||||
ASSERT_OK(Put(key, value));
|
||||
break;
|
||||
case kTypeDeletion:
|
||||
ASSERT_OK(Delete(key));
|
||||
break;
|
||||
case kTypeSingleDeletion:
|
||||
ASSERT_OK(SingleDelete(key));
|
||||
break;
|
||||
case kTypeMerge:
|
||||
ASSERT_OK(Merge(key, value));
|
||||
break;
|
||||
case kTypeBlobIndex:
|
||||
ASSERT_OK(PutBlobIndex(&batch, key, value));
|
||||
ASSERT_OK(Write(&batch));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
};
|
||||
}
|
||||
snapshots.push_back(dbfull()->GetSnapshot());
|
||||
}
|
||||
ASSERT_OK(
|
||||
dbfull()->DeleteRange(WriteOptions(), cfh(), get_key(15), get_key(16)));
|
||||
snapshots.push_back(dbfull()->GetSnapshot());
|
||||
MoveDataTo(tier);
|
||||
|
||||
// Normal iterator
|
||||
verify(1, Status::kNotSupported, "", "", create_normal_iterator);
|
||||
verify(3, Status::kNotSupported, "", "", create_normal_iterator);
|
||||
verify(5, Status::kOk, get_value(5, 0), get_value(5, 0),
|
||||
create_normal_iterator);
|
||||
verify(7, Status::kOk, get_value(8, 0), get_value(6, 0),
|
||||
create_normal_iterator);
|
||||
verify(9, Status::kOk, get_value(10, 0), get_value(8, 0),
|
||||
create_normal_iterator);
|
||||
verify(11, Status::kNotSupported, "", "", create_normal_iterator);
|
||||
verify(13, Status::kOk,
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
create_normal_iterator);
|
||||
verify(15, Status::kOk, get_value(16, 0), get_value(14, 0),
|
||||
create_normal_iterator);
|
||||
|
||||
// Iterator with blob support
|
||||
verify(1, Status::kOk, get_value(1, 0), get_value(1, 0),
|
||||
create_blob_iterator, check_is_blob(true));
|
||||
verify(3, Status::kOk, get_value(3, 0), get_value(3, 0),
|
||||
create_blob_iterator, check_is_blob(true));
|
||||
verify(5, Status::kOk, get_value(5, 0), get_value(5, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(7, Status::kOk, get_value(8, 0), get_value(6, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(9, Status::kOk, get_value(10, 0), get_value(8, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(11, Status::kNotSupported, "", "", create_blob_iterator);
|
||||
verify(13, Status::kOk,
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(15, Status::kOk, get_value(16, 0), get_value(14, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
|
||||
for (auto* snapshot : snapshots) {
|
||||
dbfull()->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -47,7 +47,7 @@ class DBBlockCacheTest : public DBTestBase {
|
||||
return options;
|
||||
}
|
||||
|
||||
void InitTable(const Options& /*options*/) {
|
||||
void InitTable(const Options& options) {
|
||||
std::string value(kValueSize, 'a');
|
||||
for (size_t i = 0; i < kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(ToString(i), value.c_str()));
|
||||
@@ -111,31 +111,6 @@ class DBBlockCacheTest : public DBTestBase {
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DBBlockCacheTest, IteratorBlockCacheUsage) {
|
||||
ReadOptions read_options;
|
||||
read_options.fill_cache = false;
|
||||
auto table_options = GetTableOptions();
|
||||
auto options = GetOptions(table_options);
|
||||
InitTable(options);
|
||||
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(0, 0, false);
|
||||
table_options.block_cache = cache;
|
||||
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
RecordCacheCounters(options);
|
||||
|
||||
std::vector<std::unique_ptr<Iterator>> iterators(kNumBlocks - 1);
|
||||
Iterator* iter = nullptr;
|
||||
|
||||
ASSERT_EQ(0, cache->GetUsage());
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(ToString(0));
|
||||
ASSERT_LT(0, cache->GetUsage());
|
||||
delete iter;
|
||||
iter = nullptr;
|
||||
ASSERT_EQ(0, cache->GetUsage());
|
||||
}
|
||||
|
||||
TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) {
|
||||
ReadOptions read_options;
|
||||
auto table_options = GetTableOptions();
|
||||
@@ -305,41 +280,6 @@ TEST_F(DBBlockCacheTest, IndexAndFilterBlocksOfNewTableAddedToCache) {
|
||||
TestGetTickerCount(options, BLOCK_CACHE_INDEX_HIT));
|
||||
}
|
||||
|
||||
// With fill_cache = false, fills up the cache, then iterates over the entire
|
||||
// db, verify dummy entries inserted in `BlockBasedTable::NewDataBlockIterator`
|
||||
// does not cause heap-use-after-free errors in COMPILE_WITH_ASAN=1 runs
|
||||
TEST_F(DBBlockCacheTest, FillCacheAndIterateDB) {
|
||||
ReadOptions read_options;
|
||||
read_options.fill_cache = false;
|
||||
auto table_options = GetTableOptions();
|
||||
auto options = GetOptions(table_options);
|
||||
InitTable(options);
|
||||
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(10, 0, true);
|
||||
table_options.block_cache = cache;
|
||||
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
ASSERT_OK(Put("key1", "val1"));
|
||||
ASSERT_OK(Put("key2", "val2"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("key3", "val3"));
|
||||
ASSERT_OK(Put("key4", "val4"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("key5", "val5"));
|
||||
ASSERT_OK(Put("key6", "val6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
Iterator* iter = nullptr;
|
||||
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(ToString(0));
|
||||
while (iter->Valid()) {
|
||||
iter->Next();
|
||||
}
|
||||
delete iter;
|
||||
iter = nullptr;
|
||||
}
|
||||
|
||||
TEST_F(DBBlockCacheTest, IndexAndFilterBlocksStats) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -557,7 +497,7 @@ TEST_F(DBBlockCacheTest, CompressedCache) {
|
||||
options.compression = kNoCompression;
|
||||
break;
|
||||
default:
|
||||
FAIL();
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
// default column family doesn't have block cache
|
||||
@@ -620,7 +560,7 @@ TEST_F(DBBlockCacheTest, CompressedCache) {
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT), 0);
|
||||
break;
|
||||
default:
|
||||
FAIL();
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
|
||||
options.create_if_missing = true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user