Compare commits

..
2 Commits
Author SHA1 Message Date
Andrew Chang ae8fb3e500 Explicitly mark destructors with override (#13212)
Summary:
I saw these compiler warnings while preparing for the 9.10 release:

```cpp
'~CompactOnDeletionCollectorFactory' overrides a destructor but is not marked 'override' [-Werror,-Wsuggest-destructor-override]

'~CompactForTieringCollectorFactory' overrides a destructor but is not marked 'override' [-Werror,-Wsuggest-destructor-override]
```

This code is from a while ago so I assume that this CI check has been failing for quite some time. We should still clean this up to avoid confusion in the future.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/13212

Test Plan: Existing CI checks should pass, and we should not see this CI check failure the next time we try to make a release/patch.

Reviewed By: jaykorean

Differential Revision: D67287794

Pulled By: archang19

fbshipit-source-id: a11230a919c0b7ef21a7219bf05f567d3d44b2d1
2024-12-16 12:45:14 -08:00
Andrew Chang 6e8dc7455b Add files for 9.10 release 2024-12-13 10:51:47 -08:00
586 changed files with 13232 additions and 34284 deletions

No files matched your search

+905
View File
@@ -0,0 +1,905 @@
version: 2.1
orbs:
win: circleci/windows@5.0.0
commands:
install-cmake-on-macos:
steps:
- run:
name: Install cmake on macos
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake
install-jdk8-on-macos:
steps:
- run:
name: Install JDK 8 on macos
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew tap bell-sw/liberica
HOMEBREW_NO_AUTO_UPDATE=1 brew install --cask liberica-jdk8
increase-max-open-files-on-macos:
steps:
- run:
name: Increase max open files
command: |
sudo sysctl -w kern.maxfiles=1048576
sudo sysctl -w kern.maxfilesperproc=1048576
sudo launchctl limit maxfiles 1048576
pre-steps:
steps:
- checkout
- run:
name: Setup Environment Variables
command: |
echo "export GTEST_THROW_ON_FAILURE=0" >> $BASH_ENV
echo "export GTEST_OUTPUT=\"xml:/tmp/test-results/\"" >> $BASH_ENV
echo "export SKIP_FORMAT_BUCK_CHECKS=1" >> $BASH_ENV
echo "export GTEST_COLOR=1" >> $BASH_ENV
echo "export CTEST_OUTPUT_ON_FAILURE=1" >> $BASH_ENV
echo "export CTEST_TEST_TIMEOUT=300" >> $BASH_ENV
echo "export ZLIB_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zlib" >> $BASH_ENV
echo "export BZIP2_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/bzip2" >> $BASH_ENV
echo "export SNAPPY_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/snappy" >> $BASH_ENV
echo "export LZ4_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/lz4" >> $BASH_ENV
echo "export ZSTD_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zstd" >> $BASH_ENV
windows-build-steps:
steps:
- checkout
- run:
name: "Install thirdparty dependencies"
command: |
echo "Installing CMake..."
choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' -y
choco install liberica8jdk -y
mkdir $Env:THIRDPARTY_HOME
cd $Env:THIRDPARTY_HOME
echo "Building Snappy dependency..."
curl https://github.com/google/snappy/archive/refs/tags/1.1.8.zip -O snappy-1.1.8.zip
unzip -q snappy-1.1.8.zip
cd snappy-1.1.8
mkdir build
cd build
& $Env:CMAKE_BIN -G "$Env:CMAKE_GENERATOR" ..
msbuild.exe Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
- run:
name: "Build RocksDB"
command: |
$env:Path = $env:JAVA_HOME + ";" + $env:Path
mkdir build
cd build
& $Env:CMAKE_BIN -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DJNI=1 ..
cd ..
echo "Building with VS version: $Env:CMAKE_GENERATOR"
msbuild.exe build/rocksdb.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
- run:
name: "Test RocksDB"
shell: powershell.exe
command: |
build_tools\run_ci_db_test.ps1 -SuiteRun arena_test,db_basic_test,db_test,db_test2,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test -Concurrency 16
- run:
name: "Test RocksJava"
command: |
cd build\java
& $Env:CTEST_BIN -C Debug -j 16
pre-steps-macos:
steps:
- pre-steps
post-steps:
steps:
- store_test_results: # store test result if there's any
path: /tmp/test-results
- store_artifacts: # store LOG for debugging if there's any
path: LOG
- run: # on fail, compress Test Logs for diagnosing the issue
name: Compress Test Logs
command: tar -cvzf t.tar.gz t
when: on_fail
- store_artifacts: # on fail, store Test Logs for diagnosing the issue
path: t.tar.gz
destination: test_logs
when: on_fail
- run: # store core dumps if there's any
command: |
mkdir -p /tmp/core_dumps
cp core.* /tmp/core_dumps
when: on_fail
- store_artifacts:
path: /tmp/core_dumps
when: on_fail
post-pmd-steps:
steps:
- store_artifacts:
path: /home/circleci/project/java/target/pmd.xml
when: on_fail
- store_artifacts:
path: /home/circleci/project/java/target/site
when: on_fail
upgrade-cmake:
steps:
- run:
name: Upgrade cmake
command: |
sudo apt remove --purge cmake
sudo snap install cmake --classic
install-gflags:
steps:
- run:
name: Install gflags
command: |
sudo apt-get update -y && sudo apt-get install -y libgflags-dev
install-gflags-on-macos:
steps:
- run:
name: Install gflags on macos
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install gflags
install-maven:
steps:
- run:
name: Install Maven
command: |
wget --no-check-certificate https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
tar zxf apache-maven-3.9.6-bin.tar.gz
echo "export M2_HOME=$(pwd)/apache-maven-3.9.6" >> $BASH_ENV
echo 'export PATH=$M2_HOME/bin:$PATH' >> $BASH_ENV
setup-folly:
steps:
- run:
name: Checkout folly sources
command: |
make checkout_folly
build-folly:
steps:
- run:
name: Build folly and dependencies
command: |
make build_folly
build-for-benchmarks:
steps:
- pre-steps
- run:
name: "Linux build for benchmarks"
command: #sized for the resource-class rocksdb-benchmark-sys1
make V=1 J=8 -j8 release
perform-benchmarks:
steps:
- run:
name: "Test low-variance benchmarks"
command: ./tools/benchmark_ci.py --db_dir /tmp/rocksdb-benchmark-datadir --output_dir /tmp/benchmark-results --num_keys 20000000
environment:
LD_LIBRARY_PATH: /usr/local/lib
# How long to run parts of the test(s)
DURATION_RO: 300
DURATION_RW: 500
# Keep threads within physical capacity of server (much lower than default)
NUM_THREADS: 1
MAX_BACKGROUND_JOBS: 4
# Don't run a couple of "optional" initial tests
CI_TESTS_ONLY: "true"
# Reduce configured size of levels to ensure more levels in the leveled compaction LSM tree
WRITE_BUFFER_SIZE_MB: 16
TARGET_FILE_SIZE_BASE_MB: 16
MAX_BYTES_FOR_LEVEL_BASE_MB: 64
# The benchmark host has 32GB memory
# The following values are tailored to work with that
# Note, tests may not exercise the targeted issues if the memory is increased on new test hosts.
COMPRESSION_TYPE: "none"
CACHE_INDEX_AND_FILTER_BLOCKS: 1
MIN_LEVEL_TO_COMPRESS: 3
CACHE_SIZE_MB: 10240
MB_WRITE_PER_SEC: 2
post-benchmarks:
steps:
- store_artifacts: # store the benchmark output
path: /tmp/benchmark-results
destination: test_logs
- run:
name: Send benchmark report to visualisation
command: |
set +e
set +o pipefail
./build_tools/benchmark_log_tool.py --tsvfile /tmp/benchmark-results/report.tsv --esdocument https://search-rocksdb-bench-k2izhptfeap2hjfxteolsgsynm.us-west-2.es.amazonaws.com/bench_test3_rix/_doc
true
executors:
linux-docker:
docker:
# The image configuration is build_tools/ubuntu20_image/Dockerfile
# To update and build the image:
# $ cd build_tools/ubuntu20_image
# $ docker build -t zjay437/rocksdb:0.5 .
# $ docker push zjay437/rocksdb:0.5
# `zjay437` is the account name for zjay@meta.com which readwrite token is shared internally. To login:
# $ docker login --username zjay437
# Or please feel free to change it to your docker hub account for hosting the image, meta employee should already have the account and able to login with SSO.
# To avoid impacting the existing CI runs, please bump the version every time creating a new image
# to run the CI image environment locally:
# $ docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -it zjay437/rocksdb:0.5 bash
# option `--cap-add=SYS_PTRACE --security-opt seccomp=unconfined` is used to enable gdb to attach an existing process
- image: zjay437/rocksdb:0.6
linux-java-docker:
docker:
# This is the Docker Image used for building RocksJava releases, see: https://github.com/evolvedbinary/docker-rocksjava
- image: evolvedbinary/rocksjava:centos6_x64-be
jobs:
build-macos:
macos:
xcode: 14.3.1
resource_class: macos.m1.medium.gen1
environment:
ROCKSDB_DISABLE_JEMALLOC: 1 # jemalloc cause env_test hang, disable it for now
steps:
- increase-max-open-files-on-macos
- install-gflags-on-macos
- pre-steps-macos
- run: ulimit -S -n `ulimit -H -n` && make V=1 J=16 -j16 all
- post-steps
build-macos-cmake:
macos:
xcode: 14.3.1
resource_class: macos.m1.medium.gen1
parameters:
run_even_tests:
description: run even or odd tests, used to split tests to 2 groups
type: boolean
default: true
steps:
- increase-max-open-files-on-macos
- install-cmake-on-macos
- install-gflags-on-macos
- pre-steps-macos
- run:
name: "cmake generate project file"
command: ulimit -S -n `ulimit -H -n` && mkdir build && cd build && cmake -DWITH_GFLAGS=1 ..
- run:
name: "Build tests"
command: cd build && make V=1 -j16
- when:
condition: << parameters.run_even_tests >>
steps:
- run:
name: "Run even tests"
command: ulimit -S -n `ulimit -H -n` && cd build && ctest -j16 -I 0,,2
- when:
condition:
not: << parameters.run_even_tests >>
steps:
- run:
name: "Run odd tests"
command: ulimit -S -n `ulimit -H -n` && cd build && ctest -j16 -I 1,,2
- post-steps
build-linux:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: make V=1 J=32 -j32 check
- post-steps
build-linux-encrypted_env-no_compression:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: ENCRYPTED_ENV=1 ROCKSDB_DISABLE_SNAPPY=1 ROCKSDB_DISABLE_ZLIB=1 ROCKSDB_DISABLE_BZIP=1 ROCKSDB_DISABLE_LZ4=1 ROCKSDB_DISABLE_ZSTD=1 make V=1 J=32 -j32 check
- run: |
./sst_dump --help | grep -E -q 'Supported compression types: kNoCompression$' # Verify no compiled in compression
- post-steps
build-linux-static_lib-alt_namespace-status_checked:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: ASSERT_STATUS_CHECKED=1 TEST_UINT128_COMPAT=1 ROCKSDB_MODIFY_NPHASH=1 LIB_MODE=static OPT="-DROCKSDB_NAMESPACE=alternative_rocksdb_ns" make V=1 -j24 check
- post-steps
build-linux-release:
executor: linux-docker
resource_class: 2xlarge
steps:
- checkout # check out the code in the project directory
- run: make V=1 -j32 LIB_MODE=shared release
- run: ls librocksdb.so # ensure shared lib built
- run: ./db_stress --version # ensure with gflags
- run: make clean
- run: make V=1 -j32 release
- run: ls librocksdb.a # ensure static lib built
- run: ./db_stress --version # ensure with gflags
- run: make clean
- run: apt-get remove -y libgflags-dev
- run: make V=1 -j32 LIB_MODE=shared release
- run: ls librocksdb.so # ensure shared lib built
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
- run: make clean
- run: make V=1 -j32 release
- run: ls librocksdb.a # ensure static lib built
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
- post-steps
build-linux-release-rtti:
executor: linux-docker
resource_class: xlarge
steps:
- checkout # check out the code in the project directory
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench
- run: ./db_stress --version # ensure with gflags
- run: make clean
- run: apt-get remove -y libgflags-dev
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
build-linux-clang-no_test_run:
executor: linux-docker
resource_class: xlarge
steps:
- checkout # check out the code in the project directory
- run: CC=clang CXX=clang++ USE_CLANG=1 PORTABLE=1 make V=1 -j16 all
- post-steps
build-linux-clang10-asan:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: COMPILE_WITH_ASAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check # aligned new doesn't work for reason we haven't figured out
- post-steps
build-linux-clang10-mini-tsan:
executor: linux-docker
resource_class: 2xlarge+
steps:
- pre-steps
- run: COMPILE_WITH_TSAN=1 CC=clang-13 CXX=clang++-13 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
- post-steps
build-linux-clang10-ubsan:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: COMPILE_WITH_UBSAN=1 OPT="-fsanitize-blacklist=.circleci/ubsan_suppression_list.txt" CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 ubsan_check # aligned new doesn't work for reason we haven't figured out
- post-steps
build-linux-valgrind:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: PORTABLE=1 make V=1 -j32 valgrind_test
- post-steps
build-linux-clang10-clang-analyze:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 CLANG_ANALYZER="/usr/bin/clang++-10" CLANG_SCAN_BUILD=scan-build-10 USE_CLANG=1 make V=1 -j32 analyze # aligned new doesn't work for reason we haven't figured out. For unknown, reason passing "clang++-10" as CLANG_ANALYZER doesn't work, and we need a full path.
- post-steps
- run:
name: "compress test report"
command: tar -cvzf scan_build_report.tar.gz scan_build_report
when: on_fail
- store_artifacts:
path: scan_build_report.tar.gz
destination: scan_build_report
when: on_fail
build-linux-runner:
machine: true
resource_class: facebook/rocksdb-benchmark-sys1
steps:
- pre-steps
- run:
name: "Checked Linux build (Runner)"
command: make V=1 J=8 -j8 check
environment:
LD_LIBRARY_PATH: /usr/local/lib
- post-steps
build-linux-cmake-with-folly:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- setup-folly
- build-folly
- run: (mkdir build && cd build && cmake -DUSE_FOLLY=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 .. && make V=1 -j20 && ctest -j20)
- post-steps
build-linux-cmake-with-folly-lite-no-test:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- setup-folly
- run: (mkdir build && cd build && cmake -DUSE_FOLLY_LITE=1 -DWITH_GFLAGS=1 .. && make V=1 -j20)
- post-steps
build-linux-cmake-with-benchmark:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: mkdir build && cd build && cmake -DWITH_GFLAGS=1 -DWITH_BENCHMARK=1 .. && make V=1 -j20 && ctest -j20
- post-steps
build-linux-unity-and-headers:
docker: # executor type
- image: gcc:latest
environment:
EXTRA_CXXFLAGS: -mno-avx512f # Warnings-as-error in avx512fintrin.h, would be used on newer hardware
resource_class: large
steps:
- checkout # check out the code in the project directory
- run: apt-get update -y && apt-get install -y libgflags-dev
- run:
name: "Unity build"
command: make V=1 -j8 unity_test
no_output_timeout: 20m
- run: make V=1 -j8 -k check-headers # could be moved to a different build
- post-steps
build-linux-gcc-7-with-folly:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- setup-folly
- build-folly
- run: USE_FOLLY=1 LIB_MODE=static CC=gcc-7 CXX=g++-7 V=1 make -j32 check # TODO: LIB_MODE only to work around unresolved linker failures
- post-steps
build-linux-gcc-7-with-folly-lite-no-test:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- setup-folly
- run: USE_FOLLY_LITE=1 CC=gcc-7 CXX=g++-7 V=1 make -j32 all
- post-steps
build-linux-gcc-8-no_test_run:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: CC=gcc-8 CXX=g++-8 V=1 make -j32 all
- post-steps
build-linux-cmake-with-folly-coroutines:
executor: linux-docker
resource_class: 2xlarge
environment:
CC: gcc-10
CXX: g++-10
steps:
- pre-steps
- setup-folly
- build-folly
- run: (mkdir build && cd build && cmake -DUSE_COROUTINES=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 .. && make V=1 -j20 && ctest -j20)
- post-steps
build-linux-gcc-10-cxx20-no_test_run:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: CC=gcc-10 CXX=g++-10 V=1 ROCKSDB_CXX_STANDARD=c++20 make -j32 all
- post-steps
build-linux-gcc-11-no_test_run:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: LIB_MODE=static CC=gcc-11 CXX=g++-11 V=1 make -j32 all microbench # TODO: LIB_MODE only to work around unresolved linker failures
- post-steps
build-linux-clang-13-no_test_run:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j32 all microbench
- post-steps
# Ensure ASAN+UBSAN with folly, and full testsuite with clang 13
build-linux-clang-13-asan-ubsan-with-folly:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- setup-folly
- build-folly
- run: CC=clang-13 CXX=clang++-13 LIB_MODE=static USE_CLANG=1 USE_FOLLY=1 COMPILE_WITH_UBSAN=1 COMPILE_WITH_ASAN=1 make -j32 check # TODO: LIB_MODE only to work around unresolved linker failures
- post-steps
# This job is only to make sure the microbench tests are able to run, the benchmark result is not meaningful as the CI host is changing.
build-linux-run-microbench:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run: DEBUG_LEVEL=0 make -j32 run_microbench
- post-steps
build-linux-mini-crashtest:
executor: linux-docker
resource_class: large
steps:
- pre-steps
- run: ulimit -S -n `ulimit -H -n` && make V=1 -j8 CRASH_TEST_EXT_ARGS='--duration=960 --max_key=2500000' blackbox_crash_test_with_atomic_flush
- post-steps
build-linux-crashtest-tiered-storage-bb:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run:
name: "run crashtest"
command: ulimit -S -n `ulimit -H -n` && make V=1 -j32 CRASH_TEST_EXT_ARGS='--duration=10800' blackbox_crash_test_with_tiered_storage
no_output_timeout: 100m
- post-steps
build-linux-crashtest-tiered-storage-wb:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run:
name: "run crashtest"
command: ulimit -S -n `ulimit -H -n` && make V=1 -j32 CRASH_TEST_EXT_ARGS='--duration=10800' whitebox_crash_test_with_tiered_storage
no_output_timeout: 100m
- post-steps
build-windows-vs2022-avx2:
executor:
name: win/server-2022
size: 2xlarge
environment:
THIRDPARTY_HOME: C:/Users/circleci/thirdparty
CMAKE_HOME: C:/Program Files/CMake
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: C:/Users/circleci/thirdparty/snappy-1.1.8
SNAPPY_INCLUDE: C:/Users/circleci/thirdparty/snappy-1.1.8;C:/Users/circleci/thirdparty/snappy-1.1.8/build
SNAPPY_LIB_DEBUG: C:/Users/circleci/thirdparty/snappy-1.1.8/build/Debug/snappy.lib
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_PORTABLE: AVX2
steps:
- windows-build-steps
build-windows-vs2022:
executor:
name: win/server-2022
size: 2xlarge
environment:
THIRDPARTY_HOME: C:/Users/circleci/thirdparty
CMAKE_HOME: C:/Program Files/CMake
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: C:/Users/circleci/thirdparty/snappy-1.1.8
SNAPPY_INCLUDE: C:/Users/circleci/thirdparty/snappy-1.1.8;C:/Users/circleci/thirdparty/snappy-1.1.8/build
SNAPPY_LIB_DEBUG: C:/Users/circleci/thirdparty/snappy-1.1.8/build/Debug/snappy.lib
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_PORTABLE: 1
steps:
- windows-build-steps
build-windows-vs2019:
executor:
name: win/server-2019
size: 2xlarge
environment:
THIRDPARTY_HOME: C:/Users/circleci/thirdparty
CMAKE_HOME: C:/Program Files/CMake
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: C:/Users/circleci/thirdparty/snappy-1.1.8
SNAPPY_INCLUDE: C:/Users/circleci/thirdparty/snappy-1.1.8;C:/Users/circleci/thirdparty/snappy-1.1.8/build
SNAPPY_LIB_DEBUG: C:/Users/circleci/thirdparty/snappy-1.1.8/build/Debug/snappy.lib
CMAKE_GENERATOR: Visual Studio 16 2019
CMAKE_PORTABLE: 1
steps:
- windows-build-steps
build-linux-java:
executor: linux-java-docker
resource_class: large
steps:
- pre-steps
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Test RocksDBJava"
command: scl enable devtoolset-7 'make V=1 J=8 -j8 jtest'
- post-steps
build-linux-java-pmd:
executor: linux-java-docker
resource_class: large
steps:
- pre-steps
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- install-maven
- run:
name: "PMD RocksDBJava"
command: scl enable devtoolset-7 'make V=1 J=8 -j8 jpmd'
- post-pmd-steps
build-linux-java-static:
executor: linux-java-docker
resource_class: large
steps:
- pre-steps
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Build RocksDBJava Static Library"
command: scl enable devtoolset-7 'make V=1 J=8 -j8 rocksdbjavastatic'
- post-steps
build-macos-java:
macos:
xcode: 14.3.1
resource_class: macos.m1.medium.gen1
environment:
JAVA_HOME: /Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home
ROCKSDB_DISABLE_JEMALLOC: 1 # jemalloc causes java 8 crash
steps:
- increase-max-open-files-on-macos
- install-gflags-on-macos
- install-jdk8-on-macos
- pre-steps-macos
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Test RocksDBJava"
command: make V=1 J=16 -j16 jtest
no_output_timeout: 20m
- post-steps
build-macos-java-static:
macos:
xcode: 14.3.1
resource_class: macos.m1.medium.gen1
environment:
JAVA_HOME: /Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home
steps:
- increase-max-open-files-on-macos
- install-gflags-on-macos
- install-cmake-on-macos
- install-jdk8-on-macos
- pre-steps-macos
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Build RocksDBJava x86 and ARM Static Libraries"
command: make V=1 J=16 -j16 rocksdbjavastaticosx
no_output_timeout: 20m
- post-steps
build-macos-java-static-universal:
macos:
xcode: 14.3.1
resource_class: macos.m1.medium.gen1
environment:
JAVA_HOME: /Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home
steps:
- increase-max-open-files-on-macos
- install-gflags-on-macos
- install-cmake-on-macos
- install-jdk8-on-macos
- pre-steps-macos
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Build RocksDBJava Universal Binary Static Library"
command: make V=1 J=16 -j16 rocksdbjavastaticosx_ub
no_output_timeout: 20m
- post-steps
build-examples:
executor: linux-docker
resource_class: large
steps:
- pre-steps
- run:
name: "Build examples"
command: |
make V=1 -j4 static_lib && cd examples && make V=1 -j4
- post-steps
build-cmake-mingw:
executor: linux-docker
resource_class: large
steps:
- pre-steps
- run: update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
- run:
name: "Build cmake-mingw"
command: |
export PATH=$JAVA_HOME/bin:$PATH
echo "JAVA_HOME=${JAVA_HOME}"
which java && java -version
which javac && javac -version
mkdir build && cd build && cmake -DJNI=1 -DWITH_GFLAGS=OFF .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb rocksdbjni
- post-steps
build-linux-non-shm:
executor: linux-docker
resource_class: 2xlarge
environment:
TEST_TMPDIR: /tmp/rocksdb_test_tmp
steps:
- pre-steps
- run: make V=1 -j32 check
- post-steps
build-linux-arm-test-full:
machine:
image: ubuntu-2004:202111-02
resource_class: arm.large
steps:
- pre-steps
- install-gflags
- run: make V=1 J=4 -j4 check
- post-steps
build-linux-arm:
machine:
image: ubuntu-2004:202111-02
resource_class: arm.large
steps:
- pre-steps
- install-gflags
- run: ROCKSDBTESTS_PLATFORM_DEPENDENT=only make V=1 J=4 -j4 all_but_some_tests check_some
- post-steps
build-linux-arm-cmake-no_test_run:
machine:
image: ubuntu-2004:202111-02
resource_class: arm.large
environment:
JAVA_HOME: /usr/lib/jvm/java-8-openjdk-arm64
steps:
- pre-steps
- install-gflags
- run:
name: "Set Java Environment"
command: |
echo "JAVA_HOME=${JAVA_HOME}"
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
which java && java -version
which javac && javac -version
- run:
name: "Build with cmake"
command: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=0 -DWITH_GFLAGS=1 -DWITH_BENCHMARK_TOOLS=0 -DWITH_TOOLS=0 -DWITH_CORE_TOOLS=1 ..
make -j4
- run:
name: "Build Java with cmake"
command: |
rm -rf build
mkdir build
cd build
cmake -DJNI=1 -DCMAKE_BUILD_TYPE=Release -DWITH_GFLAGS=1 ..
make -j4 rocksdb rocksdbjni
- post-steps
build-format-compatible:
executor: linux-docker
resource_class: 2xlarge
steps:
- pre-steps
- run:
name: "test"
command: |
export TEST_TMPDIR=/dev/shm/rocksdb
rm -rf /dev/shm/rocksdb
mkdir /dev/shm/rocksdb
tools/check_format_compatible.sh
- post-steps
build-fuzzers:
executor: linux-docker
resource_class: large
steps:
- pre-steps
- run:
name: "Build rocksdb lib"
command: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j4 static_lib
- run:
name: "Build fuzzers"
command: cd fuzz && make sst_file_writer_fuzzer db_fuzzer db_map_fuzzer
- post-steps
benchmark-linux: #use a private Circle CI runner (resource_class) to run the job
machine: true
resource_class: facebook/rocksdb-benchmark-sys1
steps:
- build-for-benchmarks
- perform-benchmarks
- post-benchmarks
workflows: # Only jobs that haven't been successfully migrated to GitHub Actions
version: 2
jobs-linux-arm:
jobs:
- build-linux-arm
benchmark-linux:
triggers:
- schedule:
cron: "0 * * * *"
filters:
branches:
only:
- main
jobs:
- benchmark-linux
nightly:
triggers:
- schedule:
cron: "0 9 * * *"
filters:
branches:
only:
- main
jobs:
- build-linux-arm-test-full
+6
View File
@@ -0,0 +1,6 @@
# Supress UBSAN warnings related to stl_tree.h, e.g.
# UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_tree.h:1505:43 in
# /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_tree.h:1505:43:
# runtime error: upcast of address 0x000001fa8820 with insufficient space for an object of type
# 'std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, rocksdb::(anonymous namespace)::LockHoldingInfo> >'
src:*bits/stl_tree.h
+4 -4
View File
@@ -4,8 +4,8 @@ runs:
steps:
- name: Install Maven
run: |
wget --no-check-certificate https://archive.apache.org/dist/maven/maven-3/3.9.11/binaries/apache-maven-3.9.11-bin.tar.gz
tar zxf apache-maven-3.9.11-bin.tar.gz
echo "export M2_HOME=$(pwd)/apache-maven-3.9.11" >> $GITHUB_ENV
echo "$(pwd)/apache-maven-3.9.11/bin" >> $GITHUB_PATH
wget --no-check-certificate https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
tar zxf apache-maven-3.9.6-bin.tar.gz
echo "export M2_HOME=$(pwd)/apache-maven-3.9.6" >> $GITHUB_ENV
echo "$(pwd)/apache-maven-3.9.6/bin" >> $GITHUB_PATH
shell: bash
@@ -11,9 +11,9 @@ runs:
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: ${{ github.workspace }}/thirdparty/snappy-1.2.2
SNAPPY_INCLUDE: ${{ github.workspace }}/thirdparty/snappy-1.2.2;${{ github.workspace }}/thirdparty/snappy-1.2.2/build
SNAPPY_LIB_DEBUG: ${{ github.workspace }}/thirdparty/snappy-1.2.2/build/Debug/snappy.lib
SNAPPY_HOME: ${{ github.workspace }}/thirdparty/snappy-1.1.8
SNAPPY_INCLUDE: ${{ github.workspace }}/thirdparty/snappy-1.1.8;${{ github.workspace }}/thirdparty/snappy-1.1.8/build
SNAPPY_LIB_DEBUG: ${{ github.workspace }}/thirdparty/snappy-1.1.8/build/Debug/snappy.lib
run: |-
# NOTE: if ... Exit $LASTEXITCODE lines needed to exit and report failure
echo ===================== Install Dependencies =====================
@@ -22,14 +22,14 @@ runs:
mkdir $Env:THIRDPARTY_HOME
cd $Env:THIRDPARTY_HOME
echo "Building Snappy dependency..."
curl -Lo snappy-1.2.2.zip https://github.com/google/snappy/archive/refs/tags/1.2.2.zip
curl -Lo snappy-1.1.8.zip https://github.com/google/snappy/archive/refs/tags/1.1.8.zip
if(!$?) { Exit $LASTEXITCODE }
unzip -q snappy-1.2.2.zip
unzip -q snappy-1.1.8.zip
if(!$?) { Exit $LASTEXITCODE }
cd snappy-1.2.2
cd snappy-1.1.8
mkdir build
cd build
& cmake -G "$Env:CMAKE_GENERATOR" .. -DSNAPPY_BUILD_TESTS=OFF -DSNAPPY_BUILD_BENCHMARKS=OFF
& cmake -G "$Env:CMAKE_GENERATOR" ..
if(!$?) { Exit $LASTEXITCODE }
msbuild Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
if(!$?) { Exit $LASTEXITCODE }
@@ -38,7 +38,7 @@ runs:
$env:Path = $env:JAVA_HOME + ";" + $env:Path
mkdir build
cd build
& cmake -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DXPRESS=1 -DJNI=1 ..
& cmake -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DJNI=1 ..
if(!$?) { Exit $LASTEXITCODE }
cd ..
echo "Building with VS version: $Env:CMAKE_GENERATOR"
+21 -56
View File
@@ -27,6 +27,18 @@ jobs:
git config --global --add safe.directory /__w/rocksdb/rocksdb
tools/check_format_compatible.sh
- uses: "./.github/actions/post-steps"
build-linux-run-microbench:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: DEBUG_LEVEL=0 make -j32 run_microbench
- uses: "./.github/actions/post-steps"
build-linux-non-shm:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
@@ -79,6 +91,15 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/windows-build-steps"
build-windows-vs2022:
if: ${{ github.repository_owner == 'facebook' }}
runs-on: windows-2022
env:
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_PORTABLE: 1
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/windows-build-steps"
build-linux-arm-test-full:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
@@ -89,59 +110,3 @@ jobs:
- run: sudo apt-get update && sudo apt-get install -y build-essential libgflags-dev
- run: make V=1 J=4 -j4 check
- uses: "./.github/actions/post-steps"
build-examples:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- name: Build examples
run: make V=1 -j4 static_lib && cd examples && make V=1 -j4
- uses: "./.github/actions/post-steps"
build-fuzzers:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- name: Build rocksdb lib
run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j4 static_lib
- name: Build fuzzers
run: cd fuzz && make sst_file_writer_fuzzer db_fuzzer db_map_fuzzer
- uses: "./.github/actions/post-steps"
build-linux-gcc-11-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: LIB_MODE=static CC=gcc-11 CXX=g++-11 V=1 make -j32 all microbench
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-folly-lite-no-test:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
env:
CC: gcc-10
CXX: g++-10
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-folly"
- run: "(mkdir build && cd build && cmake -DUSE_FOLLY_LITE=1 -DWITH_GFLAGS=1 .. && make V=1 -j20)"
- uses: "./.github/actions/post-steps"
+67 -20
View File
@@ -31,7 +31,7 @@ jobs:
# ======================== Fast Initial Checks ====================== #
check-format-and-targets:
if: ${{ github.repository_owner == 'facebook' }}
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.0
with:
@@ -45,21 +45,13 @@ jobs:
- name: Install argparse
run: pip install argparse
- name: Download clang-format-diff.py
run: wget https://rocksdb-deps.s3.us-west-2.amazonaws.com/llvm/llvm-project/release/12.x/clang/tools/clang-format/clang-format-diff.py
run: wget https://raw.githubusercontent.com/llvm/llvm-project/release/12.x/clang/tools/clang-format/clang-format-diff.py
- name: Check format
run: VERBOSE_CHECK=1 make check-format
- name: Compare buckify output
run: make check-buck-targets
- name: Simple source code checks
run: make check-sources
- name: Sanity check check_format_compatible.sh
run: |-
export TEST_TMPDIR=/dev/shm/rocksdb
rm -rf /dev/shm/rocksdb
mkdir /dev/shm/rocksdb
git reset --hard
git config --global --add safe.directory /__w/rocksdb/rocksdb
SANITY_CHECK=1 LONG_TEST=1 tools/check_format_compatible.sh
# ========================= Linux With Tests ======================== #
build-linux:
if: ${{ github.repository_owner == 'facebook' }}
@@ -109,6 +101,22 @@ jobs:
- uses: "./.github/actions/build-folly"
- run: "(mkdir build && cd build && cmake -DUSE_FOLLY=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 .. && make V=1 -j20 && ctest -j20)"
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-folly-lite-no-test:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
env:
CC: gcc-10
CXX: g++-10
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-folly"
- run: "(mkdir build && cd build && cmake -DUSE_FOLLY_LITE=1 -DWITH_GFLAGS=1 .. && make V=1 -j20)"
- uses: "./.github/actions/post-steps"
build-linux-make-with-folly:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
@@ -182,7 +190,7 @@ jobs:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: ENCRYPTED_ENV=1 ROCKSDB_DISABLE_SNAPPY=1 ROCKSDB_DISABLE_ZLIB=1 ROCKSDB_DISABLE_BZIP=1 ROCKSDB_DISABLE_LZ4=1 ROCKSDB_DISABLE_ZSTD=1 make V=1 J=32 -j32 check
- run: "./sst_dump --help | grep -E -q 'Supported built-in compression types: kNoCompression$' # Verify no compiled in compression\n"
- run: "./sst_dump --help | grep -E -q 'Supported compression types: kNoCompression$' # Verify no compiled in compression\n"
- uses: "./.github/actions/post-steps"
# ======================== Linux No Test Runs ======================= #
build-linux-release:
@@ -226,6 +234,34 @@ jobs:
- run: apt-get remove -y libgflags-dev
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench
- run: if ./db_stress --version; then false; else true; fi
build-examples:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- name: Build examples
run: make V=1 -j4 static_lib && cd examples && make V=1 -j4
- uses: "./.github/actions/post-steps"
build-fuzzers:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- name: Build rocksdb lib
run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j4 static_lib
- name: Build fuzzers
run: cd fuzz && make sst_file_writer_fuzzer db_fuzzer db_map_fuzzer
- uses: "./.github/actions/post-steps"
build-linux-clang-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
@@ -273,7 +309,18 @@ jobs:
- uses: "./.github/actions/pre-steps"
- run: CC=gcc-10 CXX=g++-10 V=1 ROCKSDB_CXX_STANDARD=c++20 make -j32 all
- uses: "./.github/actions/post-steps"
build-linux-gcc-11-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: LIB_MODE=static CC=gcc-11 CXX=g++-11 V=1 make -j32 all microbench
- uses: "./.github/actions/post-steps"
# ======================== Linux Other Checks ======================= #
build-linux-clang10-clang-analyze:
if: ${{ github.repository_owner == 'facebook' }}
@@ -343,9 +390,9 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: COMPILE_WITH_UBSAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 ubsan_check
- run: COMPILE_WITH_UBSAN=1 OPT="-fsanitize-blacklist=.circleci/ubsan_suppression_list.txt" CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 ubsan_check
- uses: "./.github/actions/post-steps"
build-linux-clang13-mini-tsan:
build-linux-clang10-mini-tsan:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
@@ -414,11 +461,11 @@ jobs:
- uses: "./.github/actions/post-steps"
# ======================== Windows with Tests ======================= #
# NOTE: some windows jobs are in "nightly" to save resources
build-windows-vs2022:
build-windows-vs2019:
if: ${{ github.repository_owner == 'facebook' }}
runs-on: windows-2022
runs-on: windows-2019
env:
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_GENERATOR: Visual Studio 16 2019
CMAKE_PORTABLE: 1
steps:
- uses: actions/checkout@v4.1.0
@@ -429,7 +476,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: evolvedbinary/rocksjava:centos7_x64-be
image: evolvedbinary/rocksjava:centos6_x64-be
options: --shm-size=16gb
steps:
# The docker image is intentionally based on an OS that has an older GLIBC version.
@@ -457,7 +504,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: evolvedbinary/rocksjava:centos7_x64-be
image: evolvedbinary/rocksjava:centos6_x64-be
options: --shm-size=16gb
steps:
# The docker image is intentionally based on an OS that has an older GLIBC version.
@@ -552,7 +599,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: evolvedbinary/rocksjava:alpine3_x64-be
image: evolvedbinary/rocksjava:rockylinux8_x64-be
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
-1
View File
@@ -91,7 +91,6 @@ buckifier/__pycache__
.arcconfig
compile_commands.json
meta_gen_cpp_compile_commands.json
clang-format-diff.py
.py3/
-13
View File
@@ -88,7 +88,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"db/memtable_list.cc",
"db/merge_helper.cc",
"db/merge_operator.cc",
"db/multi_scan.cc",
"db/output_validator.cc",
"db/periodic_task_scheduler.cc",
"db/range_del_aggregator.cc",
@@ -215,7 +214,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"table/cuckoo/cuckoo_table_builder.cc",
"table/cuckoo/cuckoo_table_factory.cc",
"table/cuckoo/cuckoo_table_reader.cc",
"table/external_table.cc",
"table/format.cc",
"table/get_context.cc",
"table/iterator.cc",
@@ -250,7 +248,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"trace_replay/trace_record_result.cc",
"trace_replay/trace_replay.cc",
"util/async_file_reader.cc",
"util/auto_tune_compressor.cc",
"util/build_version.cc",
"util/cleanable.cc",
"util/coding.cc",
@@ -269,7 +266,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"util/random.cc",
"util/rate_limiter.cc",
"util/ribbon_config.cc",
"util/simple_mixed_compressor.cc",
"util/slice.cc",
"util/status.cc",
"util/stderr_logger.cc",
@@ -321,8 +317,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"utilities/persistent_cache/block_cache_tier_metadata.cc",
"utilities/persistent_cache/persistent_cache_tier.cc",
"utilities/persistent_cache/volatile_tier_impl.cc",
"utilities/secondary_index/secondary_index_iterator.cc",
"utilities/secondary_index/simple_secondary_index.cc",
"utilities/simulator_cache/cache_simulator.cc",
"utilities/simulator_cache/sim_cache.cc",
"utilities/table_properties_collectors/compact_for_tiering_collector.cc",
@@ -412,7 +406,6 @@ cpp_library_wrapper(name="rocksdb_tools_lib", srcs=[
"tools/block_cache_analyzer/block_cache_trace_analyzer.cc",
"tools/db_bench_tool.cc",
"tools/simulated_hybrid_file_system.cc",
"tools/tool_hooks.cc",
"tools/trace_analyzer_tool.cc",
], deps=[":rocksdb_lib"], headers=[], link_whole=False, extra_test_libs=False)
@@ -4712,12 +4705,6 @@ cpp_unittest_wrapper(name="compressed_secondary_cache_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="compression_test",
srcs=["util/compression_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="configurable_test",
srcs=["options/configurable_test.cc"],
deps=[":rocksdb_test_lib"],
-8
View File
@@ -721,7 +721,6 @@ set(SOURCES
db/memtable_list.cc
db/merge_helper.cc
db/merge_operator.cc
db/multi_scan.cc
db/output_validator.cc
db/periodic_task_scheduler.cc
db/range_del_aggregator.cc
@@ -836,7 +835,6 @@ set(SOURCES
table/cuckoo/cuckoo_table_builder.cc
table/cuckoo/cuckoo_table_factory.cc
table/cuckoo/cuckoo_table_reader.cc
table/external_table.cc
table/format.cc
table/get_context.cc
table/iterator.cc
@@ -875,13 +873,11 @@ set(SOURCES
trace_replay/trace_record.cc
trace_replay/trace_replay.cc
util/async_file_reader.cc
util/auto_tune_compressor.cc
util/cleanable.cc
util/coding.cc
util/compaction_job_stats_impl.cc
util/comparator.cc
util/compression.cc
util/simple_mixed_compressor.cc
util/compression_context_cache.cc
util/concurrent_task_limiter_impl.cc
util/crc32c.cc
@@ -943,8 +939,6 @@ set(SOURCES
utilities/persistent_cache/block_cache_tier_metadata.cc
utilities/persistent_cache/persistent_cache_tier.cc
utilities/persistent_cache/volatile_tier_impl.cc
utilities/secondary_index/secondary_index_iterator.cc
utilities/secondary_index/simple_secondary_index.cc
utilities/simulator_cache/cache_simulator.cc
utilities/simulator_cache/sim_cache.cc
utilities/table_properties_collectors/compact_for_tiering_collector.cc
@@ -1459,7 +1453,6 @@ if(WITH_TESTS)
util/autovector_test.cc
util/bloom_test.cc
util/coding_test.cc
util/compression_test.cc
util/crc32c_test.cc
util/defer_test.cc
util/dynamic_bloom_test.cc
@@ -1578,7 +1571,6 @@ if(WITH_BENCHMARK_TOOLS)
add_executable(db_bench${ARTIFACT_SUFFIX}
tools/simulated_hybrid_file_system.cc
tools/db_bench.cc
tools/tool_hooks.cc
tools/db_bench_tool.cc)
target_link_libraries(db_bench${ARTIFACT_SUFFIX}
${ROCKSDB_LIB} ${THIRDPARTY_LIBS})
-154
View File
@@ -1,160 +1,6 @@
# Rocksdb Change Log
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
## 10.5.4 (08/21/2025)
### Bug Fixes
* Fix a crash in iterator Prepare() when fill_cache=false
## 10.5.3 (08/14/2025)
### Bug Fixes
* Allow a user defined index to be configured from a string.
## 10.5.2 (08/12/2025)
### Bug Fixes
* Make the User Defined Index interface consistently use the user key format, fixing the previous mixed usage of internal and user key.
## 10.5.1 (08/04/2025)
### Bug Fixes
* Fixed a bug in remote compaction that may mistakenly delete live SST file(s) during the cleanup phase when no keys survive the compaction (all expired)
## 10.5.0 (07/21/2025)
### Public API Changes
* DB option skip_checking_sst_file_sizes_on_db_open is deprecated, in favor of validating file size in parallel in a thread pool, when db is opened. When DB is opened, with paranoid check enabled, a file with the wrong size would fail the DB open. With paranoid check disabled, the DB open would succeed, the column family with the corrupted file would not be read or write, while the other healthy column families could be read and write normally. When max_open_files option is not set to -1, only a subset of the files will be opened and checked. The rest of the files will be opened and checked when they are accessed.
* GetTtl() API is now available in TTL DB
### Behavior Changes
* PessimisticTransaction::GetWaitingTxns now returns waiting transaction information even if the current transaction has timed out. This allows the information to be surfaced to users for debugging purposes once it is known that the timeout has occured.
* A new API GetFileSize is added to FSRandomAccessFile interface class. It uses fstat vs stat on the posix implementation which is more efficient. Caller could use it to get file size faster. This function might be required in the future for FileSystem implementation outside of the RocksDB code base.
* RocksDB now triggers eligible compactions every 12 hours when periodic compaction is configured. This solves a limitation of the compaction trigger mechanism, which would only trigger compaction after specific events like flush, compaction, or SetOptions.
### Bug Fixes
* Fix a bug in BackupEngine that can crash backup due to a null FSWritableFile passed to WritableFileWriter.
* Fix DB::NewMultiScan iterator to respect the scan upper bound specified in ScanOptions
### Performance Improvements
* Optimized MultiScan using BlockBasedTable to coalesce I/Os and prefetch all data blocks.
## 10.4.0 (06/20/2025)
### New Features
* Add a new CF option `memtable_avg_op_scan_flush_trigger` that supports triggering memtable flush when an iterator scans through an expensive range of keys, with the average number of skipped keys from the active memtable exceeding the threshold.
* Vector based memtable now supports concurrent writers (DBOptions::allow_concurrent_memtable_write) #13675.
* Add new experimental `TransactionOptions::large_txn_commit_optimize_byte_threshold` to enable optimizations for large transaction commit by transaction batch data size.
* Add a new option `CompactionOptionsUniversal::reduce_file_locking` and if it's true, auto universal compaction picking will adjust to minimize locking of input files when bottom priority compactions are waiting to run. This can increase the likelihood of existing L0s being selected for compaction, thereby improving write stall and reducing read regression.
* Add new `format_version=7` to aid experimental support of custom compression algorithms with CompressionManager and block-based table. This format version includes changing the format of `TableProperties::compression_name`.
### Public API Changes
* Change NewExternalTableFactory to return a unique_ptr instead of shared_ptr.
* Add an optional min file size requirement for deletion triggered compaction. It can be specified when creating `CompactOnDeletionCollectorFactory`.
### Behavior Changes
* `TransactionOptions::large_txn_commit_optimize_threshold` now has default value 0 for disabled. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` now has no effect on transactions.
### Bug Fixes
* Fix a bug where CreateColumnFamilyWithImport() could miss the SST file for the memtable flush it triggered. The exported CF then may not contain the updates in the memtable when CreateColumnFamilyWithImport() is called.
* Fix iterator operations returning NotImplemented status if disallow_memtable_writes and paranoid_memory_checks CF options are both set.
* Fixed handling of file checksums in IngestExternalFile() to allow providing checksums using recognized but not necessarily the DB's preferred checksum function, to ease migration between checksum functions.
## 10.3.0 (05/17/2025)
### New Features
* Add new experimental `CompactionOptionsFIFO::allow_trivial_copy_when_change_temperature` along with `CompactionOptionsFIFO::trivial_copy_buffer_size` to allow optimizing FIFO compactions with tiering when kChangeTemperature to move files from source tier FileSystem to another tier FileSystem via trivial and direct copying raw sst file instead of reading thru the content of the SST file then rebuilding the table files.
* Add a new field to Compaction Stats in LOG files for the pre-compression size written to each level.
* Add new experimental `TransactionOptions::large_txn_commit_optimize_threshold` to enable optimizations for large transaction commit with per transaction threshold. `TransactionDBOptions::txn_commit_bypass_memtable_threshold` is deprecated in favor of this transaction option.
* [internal team use only] Allow an application-defined `request_id` to be passed to RocksDB and propagated to the filesystem via IODebugContext
### Bug Fixes
* Fix a bug where transaction lock upgrade can incorrectly fail with a Deadlock status. This happens when a transaction has a non-zero timeout and tries to upgrade a shared lock that is also held by another transaction.
* Pass wrapped WritableFileWriter pointer to ExternalTableBuilder so that the file checksum can be correctly calculated and returned by SstFileWriter for external table files.
* Fix an infinite-loop bug in transaction locking. This can happen if a transaction reaches lock limit and its time out expires before it attempts to wait for it.
* Fixed a potential data race with `CompressionOptions::parallel_threads > 1` and a `TablePropertiesCollector` overriding `BlockAdd()`.
## 10.2.0 (04/21/2025)
### New Features
* Provide histogram stats `COMPACTION_PREFETCH_BYTES` to measure number of bytes for RocksDB's prefetching (as opposed to file
system's prefetch) on SST file during compaction read
* A new API DB::GetNewestUserDefinedTimestamp is added to return the newest user defined timestamp seen in a column family
* Introduce API `IngestWriteBatchWithIndex()` for ingesting updates into DB while bypassing memtable writes. This improves performance when writing a large write batch to the DB.
* Add a new CF option `memtable_op_scan_flush_trigger` that triggers a flush of the memtable if an iterator's Seek()/Next() scans over a certain number of invisible entries from the memtable.
### Public API Changes
* AdvancedColumnFamilyOptions.max_write_buffer_number_to_maintain is deleted. It's deprecated since introduction of a better option max_write_buffer_size_to_maintain since RocksDB 6.5.0.
* Deprecated API `DB::MaxMemCompactionLevel()`.
* Deprecated `ReadOptions::ignore_range_deletions`.
* Deprecated API `experimental::PromoteL0()`.
* Added arbitrary string map for additional options to be overriden for remote compactions
* The fail_if_options_file_error option in DBOptions has been removed. The behavior now is to always return failure in any API that fails to persist the OPTIONS file.
### Behavior Changes
* Make stats `PREFETCH_BYTES_USEFUL`, `PREFETCH_HITS`, `PREFETCH_BYTES` only account for prefetching during user initiated scan
### Bug Fixes
* Fix a bug in Posix file system that the FSWritableFile created via `FileSystem::ReopenWritableFile` internally does not track the correct file size.
* Fix a bug where tail size of remote compaction output is not persisted in primary db's manifest
## 10.1.0 (03/24/2025)
### New Features
* Added a new `DBOptions.calculate_sst_write_lifetime_hint_set` setting that allows to customize which compaction styles SST write lifetime hint calculation is allowed on. Today RocksDB supports only two modes `kCompactionStyleLevel` and `kCompactionStyleUniversal`.
* Add a new field `num_l0_files` in `CompactionJobInfo` about the number of L0 files in the CF right before and after the compaction
* Added per-key-placement feature in Remote Compaction
* Implemented API DB::GetPropertiesOfTablesByLevel that retrieves table properties for files in each LSM tree level
### Public API Changes
* `GetAllKeyVersions()` now interprets empty slices literally, as valid keys, and uses new `OptSlice` type default value for extreme upper and lower range limits.
* `DeleteFilesInRanges()` now takes `RangeOpt` which is based on `OptSlice`. The overload taking `RangePtr` is deprecated.
* Add an unordered map of name/value pairs, ReadOptions::property_bag, to pass opaque options through to an external table when creating an Iterator.
* Introduced CompactionServiceJobStatus::kAborted to allow handling aborted scenario in Schedule(), Wait() or OnInstallation() APIs in Remote Compactions.
* format\_version < 2 in BlockBasedTableOptions is no longer supported for writing new files. Support for reading such files is deprecated and might be removed in the future. `CompressedSecondaryCacheOptions::compress_format_version == 1` is also deprecated.
### Behavior Changes
* `ldb` now returns an error if the specified `--compression_type` is not supported in the build.
* MultiGet with snapshot and ReadOptions::read_tier = kPersistedTier will now read a consistent view across CFs (instead of potentially reading some CF before and some CF after a flush).
* CreateColumnFamily() is no longer allowed on a read-only DB (OpenForReadOnly())
### Bug Fixes
* Fixed stats for Tiered Storage with preclude_last_level feature
## 10.0.0 (02/21/2025)
### New Features
* Introduced new `auto_refresh_iterator_with_snapshot` opt-in knob that (when enabled) will periodically release obsolete memory and storage resources for as long as the iterator is making progress and its supplied `read_options.snapshot` was initialized with non-nullptr value.
* Added the ability to plug-in a custom table reader implementation. See include/rocksdb/external_table_reader.h for more details.
* Experimental feature: RocksDB now supports FAISS inverted file based indices via the secondary indexing framework. Applications can use FAISS secondary indices to automatically quantize embeddings and perform K-nearest-neighbors similarity searches. See `FaissIVFIndex` and `SecondaryIndex` for more details. Note: the FAISS integration currently requires using the BUCK build.
* Add new DB property `num_running_compaction_sorted_runs` that tracks the number of sorted runs being processed by currently running compactions
* Experimental feature: added support for simple secondary indices that index the specified column as-is. See `SimpleSecondaryIndex` and `SecondaryIndex` for more details.
* Added new `TransactionDBOptions::txn_commit_bypass_memtable_threshold`, which enables optimized transaction commit (see `TransactionOptions::commit_bypass_memtable`) when the transaction size exceeds a configured threshold.
### Public API Changes
* Updated the query API of the experimental secondary indexing feature by removing the earlier `SecondaryIndex::NewIterator` virtual and adding a `SecondaryIndexIterator` class that can be utilized by applications to find the primary keys for a given search target.
* Added back the ability to leverage the primary key when building secondary index entries. This involved changes to the signatures of `SecondaryIndex::GetSecondary{KeyPrefix,Value}` as well as the addition of a new method `SecondaryIndex::FinalizeSecondaryKeyPrefix`. See the API comments for more details.
* Minimum supported version of ZSTD is now 1.4.0, for code simplification. Obsolete `CompressionType` `kZSTDNotFinalCompression` is also removed.
### Behavior Changes
* `VerifyBackup` in `verify_with_checksum`=`true` mode will now evaluate checksums in parallel. As a result, unlike in case of original implementation, the API won't bail out on a very first corruption / mismatch and instead will iterate over all the backup files logging success / _degree_of_failure_ for each.
* Reversed the order of updates to the same key in WriteBatchWithIndex. This means if there are multiple updates to the same key, the most recent update is ordered first. This affects the output of WBWIIterator. When WriteBatchWithIndex is created with `overwrite_key=true`, this affects the output only if Merge is used (#13387).
* Added support for Merge operations in transactions using option `TransactionOptions::commit_bypass_memtable`.
### Bug Fixes
* Fixed GetMergeOperands() API in ReadOnlyDB and SecondaryDB
* Fix a bug in `GetMergeOperands()` that can return incorrect status (MergeInProgress) and incorrect number of merge operands. This can happen when `GetMergeOperandsOptions::continue_cb` is set, both active and immutable memtables have merge operands and the callback stops the look up at the immutable memtable.
## 9.11.0 (01/17/2025)
### New Features
* Introduce CancelAwaitingJobs() in CompactionService interface which will allow users to implement cancellation of running remote compactions from the primary instance
* Experimental feature: RocksDB now supports defining secondary indices, which are automatically maintained by the storage engine. Secondary indices provide a new customization point: applications can provide their own by implementing the new `SecondaryIndex` interface. See the `SecondaryIndex` API comments for more details. Note: this feature is currently only available in conjunction with write-committed pessimistic transactions, and `Merge` is not yet supported.
* Provide a new option `track_and_verify_wals` to track and verify various information about WAL during WAL recovery. This is intended to be a better replacement to `track_and_verify_wals_in_manifest`.
### Public API Changes
* Add `io_buffer_size` to BackupEngineOptions to enable optimal configuration of IO size
* Clean up all the references to `random_access_max_buffer_size`, related rules and all the clients wrappers. This option has been officially deprecated in 5.4.0.
* Add `file_ingestion_nanos` and `file_ingestion_blocking_live_writes_nanos` in PerfContext to observe file ingestions
* Offer new DB::Open and variants that use `std::unique_ptr<DB>*` output parameters and deprecate the old versions that use `DB**` output parameters.
* The DB::DeleteFile API is officially deprecated.
### Behavior Changes
* For leveled compaction, manual compaction (CompactRange()) will be more strict about keeping compaction size under `max_compaction_bytes`. This prevents overly large compactions in some cases (#13306).
* Experimental tiering options `preclude_last_level_data_seconds` and `preserve_internal_time_seconds` are now mutable with `SetOptions()`. Some changes to handling of these features along with long-lived snapshots and range deletes made this possible.
### Bug Fixes
* Fix a longstanding major bug with SetOptions() in which setting changes can be quietly reverted.
## 9.10.0 (12/12/2024)
### New Features
* Introduce `TransactionOptions::commit_bypass_memtable` to enable transaction commit to bypass memtable insertions. This can be beneficial for transactions with many operations, as it reduces commit time that is mostly spent on memtable insertion.
+1 -2
View File
@@ -2,8 +2,7 @@ This is the list of all known third-party language bindings for RocksDB. If some
* Java - https://github.com/facebook/rocksdb/tree/main/java
* Python
* https://github.com/rocksdict/RocksDict
* http://python-rocksdb.readthedocs.io/en/latest/ (unmaintained)
* http://python-rocksdb.readthedocs.io/en/latest/
* http://pyrocksdb.readthedocs.org/en/latest/ (unmaintained)
* Perl - https://metacpan.org/pod/RocksDB
* Node.js - https://npmjs.org/package/rocksdb
+23 -28
View File
@@ -1491,9 +1491,6 @@ db_test: $(OBJ_DIR)/db/db_test.o $(TEST_LIBRARY) $(LIBRARY)
db_test2: $(OBJ_DIR)/db/db_test2.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
compression_test: $(OBJ_DIR)/util/compression_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_logical_block_size_cache_test: $(OBJ_DIR)/db/db_logical_block_size_cache_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -2147,14 +2144,14 @@ ZLIB_DOWNLOAD_BASE ?= http://zlib.net
BZIP2_VER ?= 1.0.8
BZIP2_SHA256 ?= ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269
BZIP2_DOWNLOAD_BASE ?= http://sourceware.org/pub/bzip2
SNAPPY_VER ?= 1.2.2
SNAPPY_SHA256 ?= 90f74bc1fbf78a6c56b3c4a082a05103b3a56bb17bca1a27e052ea11723292dc
SNAPPY_VER ?= 1.2.1
SNAPPY_SHA256 ?= 736aeb64d86566d2236ddffa2865ee5d7a82d26c9016b36218fcc27ea4f09f86
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
LZ4_VER ?= 1.10.0
LZ4_SHA256 ?= 537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b
LZ4_VER ?= 1.9.4
LZ4_SHA256 ?= 0b0e3aa07c8c063ddf40b082bdf7e37a1562bda40a0ff5272957f3e987e0e54b
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
ZSTD_VER ?= 1.5.7
ZSTD_SHA256 ?= 37d7284556b20954e56e1ca85b80226768902e2edabd3b649e9e72c0c9012ee3
ZSTD_VER ?= 1.5.5
ZSTD_SHA256 ?= 98e9c3d949d1b924e28e01eccb7deed865eefebf25c2f21c702e5cd5b63b85e1
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
CURL_SSL_OPTS ?= --tlsv1
@@ -2375,27 +2372,27 @@ rocksdbjavastaticreleasedocker: rocksdbjavastaticosx rocksdbjavastaticdockerx86
rocksdbjavastaticdockerx86:
mkdir -p java/target
docker run --rm --name rocksdb_linux_x86-be --platform linux/386 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_x86-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_x86-be --platform linux/386 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos6_x86-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerx86_64:
mkdir -p java/target
docker run --rm --name rocksdb_linux_x64-be --platform linux/amd64 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_x64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_x64-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos6_x64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerppc64le:
mkdir -p java/target
docker run --rm --name rocksdb_linux_ppc64le-be --platform linux/ppc64le --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_ppc64le-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerarm64v8:
mkdir -p java/target
docker run --rm --name rocksdb_linux_arm64v8-be --platform linux/aarch64 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_arm64v8-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockers390x:
mkdir -p java/target
docker run --rm --name rocksdb_linux_s390x-be --platform linux/s390x --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:ubuntu18_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_s390x-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:ubuntu18_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerriscv64:
mkdir -p java/target
docker run --rm --name rocksdb_linux_riscv64-be --platform linux/riscv64 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:ubuntu20_riscv64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_riscv64-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:ubuntu20_riscv64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerx86musl:
mkdir -p java/target
@@ -2403,19 +2400,19 @@ rocksdbjavastaticdockerx86musl:
rocksdbjavastaticdockerx86_64musl:
mkdir -p java/target
docker run --rm --name rocksdb_linux_x64-musl-be --platform linux/amd64 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_x64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_x64-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_x64-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerppc64lemusl:
mkdir -p java/target
docker run --rm --name rocksdb_linux_ppc64le-musl-be --platform linux/ppc64le --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_ppc64le-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockerarm64v8musl:
mkdir -p java/target
docker run --rm --name rocksdb_linux_arm64v8-musl-be --platform linux/aarch64 --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_arm64v8-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticdockers390xmusl:
mkdir -p java/target
docker run --rm --name rocksdb_linux_s390x-musl-be --platform linux/s390x --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
docker run --rm --name rocksdb_linux_s390x-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) --env J=$(J) evolvedbinary/rocksjava:alpine3_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral
@@ -2470,8 +2467,8 @@ jtest_run:
jtest: rocksdbjava
cd java;$(MAKE) sample test
jpmd: rocksdbjavageneratepom
cd java;$(MAKE) java java_test pmd
jpmd: rocksdbjava rocksdbjavageneratepom
cd java;$(MAKE) pmd
jdb_bench:
cd java;$(MAKE) db_bench;
@@ -2492,13 +2489,11 @@ checkout_folly:
fi
@# Pin to a particular version for public CI, so that PR authors don't
@# need to worry about folly breaking our integration. Update periodically
cd third-party/folly && git reset --hard 5c626dd6a028a02e461edb5396694d48305e9284
@# Apparently missing include
perl -pi -e 's/(#include <atomic>)/$$1\n#include <cstring>/' third-party/folly/folly/lang/Exception.h
@# Warning-as-error on memcpy
perl -pi -e 's/memcpy.&ptr/memcpy((void*)&ptr/' third-party/folly/folly/lang/Exception.cpp
@# const mismatch
perl -pi -e 's/: environ/: (const char**)(environ)/' third-party/folly/folly/Subprocess.cpp
cd third-party/folly && git reset --hard 33f5b67fcaeb8705b04fd1b850873a180dc89aaa
@# NOTE: this hack is required for clang in some cases
perl -pi -e 's/int rv = syscall/int rv = (int)syscall/' third-party/folly/folly/detail/Futex.cpp
@# NOTE: this hack is required for gcc in some cases
perl -pi -e 's/(__has_include.<experimental.memory_resource>.)/__cpp_rtti && $$1/' third-party/folly/folly/memory/MemoryResource.h
@# NOTE: boost source will be needed for any build including `USE_FOLLY_LITE` builds as those depend on boost headers
cd third-party/folly && $(PYTHON) build/fbcode_builder/getdeps.py fetch boost
+1 -5
View File
@@ -360,13 +360,9 @@ EOF
fi
if ! test $ROCKSDB_DISABLE_ZSTD; then
# Test whether zstd library is installed with minimum version
# (Keep in sync with compression.h)
# Test whether zstd library is installed
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
#include <zstd.h>
#if ZSTD_VERSION_NUMBER < 10400
#error "ZSTD support requires version >= 1.4.0 (libzstd-devel)"
#endif // ZSTD_VERSION_NUMBER
int main() {}
EOF
if [ "$?" = 0 ]; then
+1 -1
View File
@@ -59,7 +59,7 @@ fi
if ! test $ROCKSDB_DISABLE_ZSTD; then
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd${MAYBE_PIC}.a"
CFLAGS+=" -DZSTD -DZSTD_STATIC_LINKING_ONLY"
CFLAGS+=" -DZSTD"
fi
# location of gflags headers and libraries
+4 -7
View File
@@ -118,9 +118,6 @@ fi
# fi
set -e
# Exclude third-party from formatting
EXCLUDE=':!third-party/'
uncommitted_code=`git diff HEAD`
# If there's no uncommitted changes, we assume user are doing post-commit
@@ -140,11 +137,11 @@ then
# should be relevant for formatting fixes.
FORMAT_UPSTREAM_MERGE_BASE="$(git merge-base "$FORMAT_UPSTREAM" HEAD)"
# Get the differences
diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" -- $EXCLUDE | $CLANG_FORMAT_DIFF -p 1) || true
diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -p 1) || true
echo "Checking format of changes not yet in $FORMAT_UPSTREAM..."
else
# Check the format of uncommitted lines,
diffs=$(git diff -U0 HEAD -- $EXCLUDE | $CLANG_FORMAT_DIFF -p 1) || true
diffs=$(git diff -U0 HEAD | $CLANG_FORMAT_DIFF -p 1) || true
echo "Checking format of uncommitted changes..."
fi
@@ -190,9 +187,9 @@ fi
# Do in-place format adjustment.
if [ -z "$uncommitted_code" ]
then
git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" -- $EXCLUDE | $CLANG_FORMAT_DIFF -i -p 1
git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -i -p 1
else
git diff -U0 HEAD -- $EXCLUDE | $CLANG_FORMAT_DIFF -i -p 1
git diff -U0 HEAD | $CLANG_FORMAT_DIFF -i -p 1
fi
echo "Files reformatted!"
+1
View File
@@ -118,6 +118,7 @@ Status SecondaryCache::CreateFromString(
sec_cache = NewCompressedSecondaryCache(sec_cache_opts);
}
if (status.ok()) {
result->swap(sec_cache);
}
+2 -1
View File
@@ -191,7 +191,8 @@ namespace {
class SharedState {
public:
explicit SharedState(CacheBench* cache_bench)
: cv_(&mu_), cache_bench_(cache_bench) {}
: cv_(&mu_),
cache_bench_(cache_bench) {}
~SharedState() = default;
+38 -42
View File
@@ -24,14 +24,7 @@ CompressedSecondaryCache::CompressedSecondaryCache(
cache_res_mgr_(std::make_shared<ConcurrentCacheReservationManager>(
std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
cache_))),
disable_cache_(opts.capacity == 0) {
auto mgr =
GetBuiltinCompressionManager(cache_options_.compress_format_version);
compressor_ = mgr->GetCompressor(cache_options_.compression_opts,
cache_options_.compression_type);
decompressor_ =
mgr->GetDecompressorOptimizeFor(cache_options_.compression_type);
}
disable_cache_(opts.capacity == 0) {}
CompressedSecondaryCache::~CompressedSecondaryCache() = default;
@@ -80,16 +73,15 @@ std::unique_ptr<SecondaryCacheResultHandle> CompressedSecondaryCache::Lookup(
ptr = reinterpret_cast<CacheAllocationPtr*>(handle_value);
handle_value_charge = cache_->GetCharge(lru_handle);
data_ptr = ptr->get();
const char* limit = ptr->get() + handle_value_charge;
data_ptr =
GetVarint32Ptr(data_ptr, limit, static_cast<uint32_t*>(&type_32));
data_ptr = GetVarint32Ptr(data_ptr, data_ptr + 1,
static_cast<uint32_t*>(&type_32));
type = static_cast<CompressionType>(type_32);
data_ptr =
GetVarint32Ptr(data_ptr, limit, static_cast<uint32_t*>(&source_32));
data_ptr = GetVarint32Ptr(data_ptr, data_ptr + 1,
static_cast<uint32_t*>(&source_32));
source = static_cast<CacheTier>(source_32);
uint64_t data_size = 0;
data_ptr =
GetVarint64Ptr(data_ptr, limit, static_cast<uint64_t*>(&data_size));
data_ptr = GetVarint64Ptr(data_ptr, ptr->get() + handle_value_charge,
static_cast<uint64_t*>(&data_size));
assert(handle_value_charge > data_size);
handle_value_charge = data_size;
}
@@ -105,24 +97,25 @@ std::unique_ptr<SecondaryCacheResultHandle> CompressedSecondaryCache::Lookup(
kNoCompression, CacheTier::kVolatileTier,
create_context, allocator, &value, &charge);
} else {
// TODO: can we work some magic with create_cb, which might be based on
// custom compression, to decompress without an extra copy in create_cb?
Decompressor::Args args;
args.compressed_data = Slice(data_ptr, handle_value_charge);
args.compression_type = cache_options_.compression_type;
s = decompressor_->ExtractUncompressedSize(args);
assert(s.ok());
if (s.ok()) {
auto uncompressed = std::make_unique<char[]>(args.uncompressed_size);
s = decompressor_->DecompressBlock(args, uncompressed.get());
assert(s.ok());
if (s.ok()) {
s = helper->create_cb(
Slice(uncompressed.get(), args.uncompressed_size), kNoCompression,
CacheTier::kVolatileTier, create_context, allocator, &value,
&charge);
}
UncompressionContext uncompression_context(
cache_options_.compression_type);
UncompressionInfo uncompression_info(uncompression_context,
UncompressionDict::GetEmptyDict(),
cache_options_.compression_type);
size_t uncompressed_size{0};
CacheAllocationPtr uncompressed =
UncompressData(uncompression_info, (char*)data_ptr,
handle_value_charge, &uncompressed_size,
cache_options_.compress_format_version, allocator);
if (!uncompressed) {
cache_->Release(lru_handle, /*erase_if_last_ref=*/true);
return nullptr;
}
s = helper->create_cb(Slice(uncompressed.get(), uncompressed_size),
kNoCompression, CacheTier::kVolatileTier,
create_context, allocator, &value, &charge);
}
} else {
// The item was not compressed by us. Let the helper create_cb
@@ -205,17 +198,20 @@ Status CompressedSecondaryCache::InsertInternal(
type == kNoCompression &&
!cache_options_.do_not_compress_roles.Contains(helper->role)) {
PERF_COUNTER_ADD(compressed_sec_cache_uncompressed_bytes, data_size);
CompressionContext compression_context(cache_options_.compression_type,
cache_options_.compression_opts);
uint64_t sample_for_compression{0};
CompressionInfo compression_info(
cache_options_.compression_opts, compression_context,
CompressionDict::GetEmptyDict(), cache_options_.compression_type,
sample_for_compression);
CompressionType to_type = kNoCompression;
s = compressor_->CompressBlock(val, &compressed_val, &to_type,
nullptr /*working_area*/);
if (!s.ok()) {
return s;
}
// TODO: allow values not compressed when there's no size savings?
assert(to_type == cache_options_.compression_type);
if (to_type != cache_options_.compression_type) {
return Status::Corruption("Failed to compress value.");
bool success =
CompressData(val, compression_info,
cache_options_.compress_format_version, &compressed_val);
if (!success) {
return Status::Corruption("Error compressing value.");
}
val = Slice(compressed_val);
-2
View File
@@ -145,8 +145,6 @@ class CompressedSecondaryCache : public SecondaryCache {
const Cache::CacheItemHelper* GetHelper(bool enable_custom_split_merge) const;
std::shared_ptr<Cache> cache_;
CompressedSecondaryCacheOptions cache_options_;
std::unique_ptr<Compressor> compressor_;
std::shared_ptr<Decompressor> decompressor_;
mutable port::Mutex capacity_mutex_;
std::shared_ptr<ConcurrentCacheReservationManager> cache_res_mgr_;
bool disable_cache_;
+1
View File
@@ -845,6 +845,7 @@ TEST_P(CompressedSecondaryCacheTestWithCompressionParam,
BasicTestHelper(sec_cache, sec_cache_is_compressed_);
}
TEST_P(CompressedSecondaryCacheTestWithCompressionParam, FailsTest) {
FailsTest(sec_cache_is_compressed_);
}
+3 -2
View File
@@ -93,8 +93,9 @@ void LRUHandleTable::Resize() {
uint32_t old_length = uint32_t{1} << length_bits_;
int new_length_bits = length_bits_ + 1;
std::unique_ptr<LRUHandle*[]> new_list{
new LRUHandle* [size_t{1} << new_length_bits] {}};
std::unique_ptr<LRUHandle* []> new_list {
new LRUHandle* [size_t{1} << new_length_bits] {}
};
[[maybe_unused]] uint32_t count = 0;
for (uint32_t i = 0; i < old_length; i++) {
LRUHandle* h = list_[i];
+2 -2
View File
@@ -546,7 +546,7 @@ TYPED_TEST(ClockCacheTest, Limits) {
// verify usage tracking on detached entries.)
{
size_t n = kCapacity * 5 + 1;
std::unique_ptr<HandleImpl*[]> ha{new HandleImpl* [n] {}};
std::unique_ptr<HandleImpl* []> ha { new HandleImpl* [n] {} };
Status s;
for (size_t i = 0; i < n && s.ok(); ++i) {
hkey[1] = i;
@@ -713,7 +713,7 @@ TYPED_TEST(ClockCacheTest, ClockEvictionEffortCapTest) {
// evictable entries are present beyond the cache capacity, despite
// being evictable.
constexpr size_t kCount = kCapacity - 1;
std::unique_ptr<HandleImpl*[]> ha{new HandleImpl* [kCount] {}};
std::unique_ptr<HandleImpl* []> ha { new HandleImpl* [kCount] {} };
for (size_t i = 0; i < 2 * kCount; ++i) {
UniqueId64x2 hkey = this->CheapHash(i);
ASSERT_OK(shard.Insert(
+3 -1
View File
@@ -7,4 +7,6 @@
#include "cache/cache_entry_roles.h"
namespace ROCKSDB_NAMESPACE {} // namespace ROCKSDB_NAMESPACE
namespace ROCKSDB_NAMESPACE {
} // namespace ROCKSDB_NAMESPACE
+5 -14
View File
@@ -121,17 +121,7 @@ CacheWithSecondaryAdapter::~CacheWithSecondaryAdapter() {
assert(s.ok());
assert(placeholder_usage_ == 0);
assert(reserved_usage_ == 0);
bool pri_cache_res_mismatch =
pri_cache_res_->GetTotalMemoryUsed() != sec_capacity;
if (pri_cache_res_mismatch) {
fprintf(stderr,
"~CacheWithSecondaryAdapter: Primary cache reservation: "
"%zu, Secondary cache capacity: %zu, "
"Secondary cache reserved: %zu\n",
pri_cache_res_->GetTotalMemoryUsed(), sec_capacity,
sec_reserved_);
assert(!pri_cache_res_mismatch);
}
assert(pri_cache_res_->GetTotalMemoryUsed() == sec_capacity);
}
#endif // NDEBUG
}
@@ -489,10 +479,12 @@ const char* CacheWithSecondaryAdapter::Name() const {
// as well. At the moment, we don't have a good way of handling the case
// where the new capacity < total cache reservations.
void CacheWithSecondaryAdapter::SetCapacity(size_t capacity) {
size_t sec_capacity = static_cast<size_t>(
capacity * (distribute_cache_res_ ? sec_cache_res_ratio_ : 0.0));
size_t old_sec_capacity = 0;
if (distribute_cache_res_) {
MutexLock m(&cache_res_mutex_);
size_t sec_capacity = static_cast<size_t>(capacity * sec_cache_res_ratio_);
size_t old_sec_capacity = 0;
Status s = secondary_cache_->GetCapacity(old_sec_capacity);
if (!s.ok()) {
@@ -611,7 +603,6 @@ Status CacheWithSecondaryAdapter::UpdateCacheReservationRatio(
// cache utilization (increase in capacity - increase in share of cache
// reservation)
// 3. Increase secondary cache capacity
assert(new_sec_reserved >= sec_reserved_);
s = secondary_cache_->Deflate(new_sec_reserved - sec_reserved_);
assert(s.ok());
s = pri_cache_res_->UpdateCacheReservation(
+5 -13
View File
@@ -951,20 +951,12 @@ TEST_F(DBTieredSecondaryCacheTest, FSBufferTest) {
IODebugContext* dbg) override {
for (size_t i = 0; i < num_reqs; ++i) {
FSReadRequest& req = reqs[i];
// See https://github.com/facebook/rocksdb/pull/13195 for why we
// want to set up our test implementation for FSAllocationPtr this
// way.
char* internalData = new char[req.len];
req.status = Read(req.offset, req.len, options, &req.result,
internalData, dbg);
Slice* internalSlice = new Slice(internalData, req.len);
FSAllocationPtr internalPtr(internalSlice, [](void* ptr) {
delete[] static_cast<const char*>(
static_cast<Slice*>(ptr)->data_);
delete static_cast<Slice*>(ptr);
FSAllocationPtr buffer(new char[req.len], [](void* ptr) {
delete[] static_cast<char*>(ptr);
});
req.fs_scratch = std::move(internalPtr);
req.fs_scratch = std::move(buffer);
req.status = Read(req.offset, req.len, options, &req.result,
static_cast<char*>(req.fs_scratch.get()), dbg);
}
return IOStatus::OK();
}
+15 -61
View File
@@ -11,29 +11,18 @@ CRASHTEST_MAKE=$(MAKE) -f crash_test.mk
CRASHTEST_PY=$(PYTHON) -u tools/db_crashtest.py --stress_cmd=$(DB_STRESS_CMD) --cleanup_cmd='$(DB_CLEANUP_CMD)'
.PHONY: crash_test crash_test_with_atomic_flush crash_test_with_txn \
crash_test_with_wc_txn crash_test_with_wp_txn crash_test_with_wup_txn \
crash_test_with_best_efforts_recovery crash_test_with_ts \
crash_test_with_multiops_wc_txn \
crash_test_with_multiops_wp_txn \
crash_test_with_multiops_wup_txn \
crash_test_with_optimistic_txn \
crash_test_with_tiered_storage \
blackbox_crash_test blackbox_crash_test_with_atomic_flush \
blackbox_crash_test_with_wc_txn blackbox_crash_test_with_wp_txn \
blackbox_crash_test_with_wup_txn \
blackbox_crash_test_with_txn blackbox_crash_test_with_ts \
blackbox_crash_test_with_best_efforts_recovery \
whitebox_crash_test whitebox_crash_test_with_atomic_flush \
whitebox_crash_test_with_txn whitebox_crash_test_with_ts \
blackbox_crash_test_with_multiops_wc_txn \
blackbox_crash_test_with_multiops_wp_txn \
blackbox_crash_test_with_multiops_wup_txn \
blackbox_crash_test_with_optimistic_txn \
blackbox_crash_test_with_tiered_storage \
whitebox_crash_test whitebox_crash_test_with_atomic_flush \
whitebox_crash_test_with_wc_txn whitebox_crash_test_with_wp_txn \
whitebox_crash_test_with_wup_txn \
whitebox_crash_test_with_txn whitebox_crash_test_with_ts \
whitebox_crash_test_with_optimistic_txn \
crash_test_with_tiered_storage blackbox_crash_test_with_tiered_storage \
whitebox_crash_test_with_tiered_storage \
whitebox_crash_test_with_optimistic_txn \
blackbox_crash_test_with_optimistic_txn \
crash_test: $(DB_STRESS_CMD)
# Do not parallelize
@@ -45,20 +34,10 @@ crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) whitebox_crash_test_with_atomic_flush
$(CRASHTEST_MAKE) blackbox_crash_test_with_atomic_flush
crash_test_with_wc_txn: $(DB_STRESS_CMD)
crash_test_with_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wc_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wc_txn
crash_test_with_wp_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wp_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wp_txn
crash_test_with_wup_txn: $(DB_STRESS_CMD)
# Do not parallelize
$(CRASHTEST_MAKE) whitebox_crash_test_with_wup_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_wup_txn
$(CRASHTEST_MAKE) whitebox_crash_test_with_txn
$(CRASHTEST_MAKE) blackbox_crash_test_with_txn
crash_test_with_optimistic_txn: $(DB_STRESS_CMD)
# Do not parallelize
@@ -83,9 +62,6 @@ crash_test_with_multiops_wc_txn: $(DB_STRESS_CMD)
crash_test_with_multiops_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) blackbox_crash_test_with_multiops_wp_txn
crash_test_with_multiops_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_MAKE) blackbox_crash_test_with_multiops_wup_txn
blackbox_crash_test: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --simple blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) blackbox $(CRASH_TEST_EXT_ARGS)
@@ -93,14 +69,8 @@ blackbox_crash_test: $(DB_STRESS_CMD)
blackbox_crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --cf_consistency blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 0 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 1 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox --txn_write_policy 2 $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_best_efforts_recovery: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_best_efforts_recovery blackbox $(CRASH_TEST_EXT_ARGS)
@@ -109,13 +79,10 @@ blackbox_crash_test_with_ts: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --enable_ts blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 0 blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_committed blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 1 blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_multiops_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_multiops_txn --txn_write_policy 2 blackbox $(CRASH_TEST_EXT_ARGS)
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_prepared blackbox $(CRASH_TEST_EXT_ARGS)
blackbox_crash_test_with_tiered_storage: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --test_tiered_storage blackbox $(CRASH_TEST_EXT_ARGS)
@@ -137,17 +104,9 @@ whitebox_crash_test_with_atomic_flush: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --cf_consistency whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wc_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 0 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wp_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 1 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_wup_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --txn_write_policy 2 \
--random_kill_odd $(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --txn whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
whitebox_crash_test_with_ts: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --enable_ts whitebox --random_kill_odd \
@@ -160,8 +119,3 @@ whitebox_crash_test_with_tiered_storage: $(DB_STRESS_CMD)
whitebox_crash_test_with_optimistic_txn: $(DB_STRESS_CMD)
$(CRASHTEST_PY) --optimistic_txn whitebox --random_kill_odd \
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
# Old names DEPRECATED
crash_test_with_txn: crash_test_with_wc_txn
whitebox_crash_test_with_txn: whitebox_crash_test_with_wc_txn
blackbox_crash_test_with_txn: blackbox_crash_test_with_wc_txn
+45 -136
View File
@@ -42,9 +42,9 @@ Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
void ArenaWrappedDBIter::Init(
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t version_number,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, bool allow_refresh, ReadOnlyMemTable* active_mem) {
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iteration,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index, bool allow_refresh) {
read_options_ = read_options;
if (!CheckFSFeatureSupport(env->GetFileSystem().get(),
FSSupportedOps::kAsyncIO)) {
@@ -52,128 +52,20 @@ void ArenaWrappedDBIter::Init(
}
read_options_.total_order_seek |= ioptions.prefix_seek_opt_in_only;
db_iter_ = DBIter::NewIter(
env, read_options_, ioptions, mutable_cf_options,
ioptions.user_comparator, /*internal_iter=*/nullptr, version, sequence,
read_callback, active_mem, cfh, expose_blob_index, &arena_);
auto mem = arena_.AllocateAligned(sizeof(DBIter));
db_iter_ = new (mem) DBIter(env, read_options_, ioptions, mutable_cf_options,
ioptions.user_comparator,
/* iter */ nullptr, version, sequence, true,
max_sequential_skip_in_iteration, read_callback,
cfh, expose_blob_index);
sv_number_ = version_number;
allow_refresh_ = allow_refresh;
allow_mark_memtable_for_flush_ = active_mem;
memtable_range_tombstone_iter_ = nullptr;
}
void ArenaWrappedDBIter::MaybeAutoRefresh(bool is_seek,
DBIter::Direction direction) {
if (cfh_ != nullptr && read_options_.snapshot != nullptr && allow_refresh_ &&
read_options_.auto_refresh_iterator_with_snapshot) {
// The intent here is to capture the superversion number change
// reasonably soon from the time it actually happened. As such,
// we're fine with weaker synchronization / ordering guarantees
// provided by relaxed atomic (in favor of less CPU / mem overhead).
uint64_t cur_sv_number = cfh_->cfd()->GetSuperVersionNumberRelaxed();
if ((sv_number_ != cur_sv_number) && status().ok()) {
// Changing iterators' direction is pretty heavy-weight operation and
// could have unintended consequences when it comes to prefix seek.
// Therefore, we need an efficient implementation that does not duplicate
// the effort by doing things like double seek(forprev).
//
// Auto refresh can be triggered on the following groups of operations:
//
// 1. [Seek]: Seek(), SeekForPrev()
// 2. [Non-Seek]: Next(), Prev()
//
// In case of 'Seek' group, procedure is fairly straightforward as we'll
// simply call refresh and then invoke the operation on intended target.
//
// In case of 'Non-Seek' group, we'll first advance the cursor by invoking
// intended user operation (Next() or Prev()), capture the target key T,
// refresh the iterator and then reconcile the refreshed iterator by
// explicitly calling [Seek(T) or SeekForPrev(T)]. Below is an example
// flow for Next(), but same principle applies to Prev():
//
//
// T0: Before the operation T1: Execute Next()
// | |
// | -------------
// | | * capture the key (T)
// DBIter(SV#A) | |
// --------------\ /------\ /---------
// SV #A | ... -> [ X ] -> [ T ] -> ... |
// -----------------------------------
// / |
// / |
// / T2: Refresh iterator
// /
// DBIter(SV#A') /
// ----------------------------------
// SV #A' | ... -> [ T ] -> ... |
// ----------------/ \---------------
// |
// ---- T3: Seek(T)
//
bool valid = false;
std::string key;
if (!is_seek && db_iter_->Valid()) {
// The key() Slice is valid until the iterator state changes.
// Given that refresh is heavy-weight operation it itself,
// we should copy the target key upfront to avoid reading bad value.
valid = true;
key = db_iter_->key().ToString();
}
// It's perfectly fine to unref the corresponding superversion
// as we rely on pinning behavior of snapshot for consistency.
DoRefresh(read_options_.snapshot, cur_sv_number);
if (!is_seek && valid) { // Reconcile new iterator after Next() / Prev()
if (direction == DBIter::kForward) {
db_iter_->Seek(key);
} else {
assert(direction == DBIter::kReverse);
db_iter_->SeekForPrev(key);
}
}
}
}
}
Status ArenaWrappedDBIter::Refresh() { return Refresh(nullptr); }
void ArenaWrappedDBIter::DoRefresh(const Snapshot* snapshot,
[[maybe_unused]] uint64_t sv_number) {
Env* env = db_iter_->env();
// NOTE:
//
// Errors like file deletion (as a part of SV cleanup in ~DBIter) will be
// present in the error log, but won't be reflected in the iterator status.
// This is by design as we expect compaction to clean up those obsolete files
// eventually.
db_iter_->~DBIter();
arena_.~Arena();
new (&arena_) Arena();
auto cfd = cfh_->cfd();
auto db_impl = cfh_->db();
SuperVersion* sv = cfd->GetReferencedSuperVersion(db_impl);
assert(sv->version_number >= sv_number);
SequenceNumber read_seq = GetSeqNum(db_impl, snapshot);
if (read_callback_) {
read_callback_->Refresh(read_seq);
}
Init(env, read_options_, cfd->ioptions(), sv->mutable_cf_options, sv->current,
read_seq, sv->version_number, read_callback_, cfh_, expose_blob_index_,
allow_refresh_, allow_mark_memtable_for_flush_ ? sv->mem : nullptr);
InternalIterator* internal_iter = db_impl->NewInternalIterator(
read_options_, cfd, sv, &arena_, read_seq,
/* allow_unprepared_value */ true, /* db_iter */ this);
SetIterUnderDBIter(internal_iter);
}
Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
if (cfh_ == nullptr || !allow_refresh_) {
return Status::NotSupported("Creating renew iterator is not allowed.");
@@ -193,9 +85,32 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
TEST_SYNC_POINT("ArenaWrappedDBIter::Refresh:1");
TEST_SYNC_POINT("ArenaWrappedDBIter::Refresh:2");
auto reinit_internal_iter = [&]() {
Env* env = db_iter_->env();
db_iter_->~DBIter();
arena_.~Arena();
new (&arena_) Arena();
SuperVersion* sv = cfd->GetReferencedSuperVersion(db_impl);
assert(sv->version_number >= cur_sv_number);
SequenceNumber read_seq = GetSeqNum(db_impl, snapshot);
if (read_callback_) {
read_callback_->Refresh(read_seq);
}
Init(env, read_options_, *(cfd->ioptions()), sv->mutable_cf_options,
sv->current, read_seq,
sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback_, cfh_, expose_blob_index_,
allow_refresh_);
InternalIterator* internal_iter = db_impl->NewInternalIterator(
read_options_, cfd, sv, &arena_, read_seq,
/* allow_unprepared_value */ true, /* db_iter */ this);
SetIterUnderDBIter(internal_iter);
};
while (true) {
if (sv_number_ != cur_sv_number) {
DoRefresh(snapshot, cur_sv_number);
reinit_internal_iter();
break;
} else {
SequenceNumber read_seq = GetSeqNum(db_impl, snapshot);
@@ -223,7 +138,7 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
db_impl->ReturnAndCleanupSuperVersion(cfd, sv);
// The memtable under DBIter did not have range tombstone before
// refresh.
DoRefresh(snapshot, cur_sv_number);
reinit_internal_iter();
break;
} else {
*memtable_range_tombstone_iter_ =
@@ -251,26 +166,20 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
}
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, ColumnFamilyHandleImpl* cfh,
SuperVersion* sv, const SequenceNumber& sequence,
ReadCallback* read_callback, DBImpl* db_impl, bool expose_blob_index,
bool allow_refresh, bool allow_mark_memtable_for_flush) {
ArenaWrappedDBIter* db_iter = new ArenaWrappedDBIter();
db_iter->Init(env, read_options, cfh->cfd()->ioptions(),
sv->mutable_cf_options, sv->current, sequence,
sv->version_number, read_callback, cfh, expose_blob_index,
allow_refresh,
allow_mark_memtable_for_flush ? sv->mem : nullptr);
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iterations,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index, bool allow_refresh) {
ArenaWrappedDBIter* iter = new ArenaWrappedDBIter();
iter->Init(env, read_options, ioptions, mutable_cf_options, version, sequence,
max_sequential_skip_in_iterations, version_number, read_callback,
cfh, expose_blob_index, allow_refresh);
if (cfh != nullptr && allow_refresh) {
db_iter->StoreRefreshInfo(cfh, read_callback, expose_blob_index);
iter->StoreRefreshInfo(cfh, read_callback, expose_blob_index);
}
InternalIterator* internal_iter = db_impl->NewInternalIterator(
db_iter->GetReadOptions(), cfh->cfd(), sv, db_iter->GetArena(), sequence,
/*allow_unprepared_value=*/true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
return iter;
}
} // namespace ROCKSDB_NAMESPACE
+16 -34
View File
@@ -19,6 +19,7 @@
#include "options/cf_options.h"
#include "rocksdb/db.h"
#include "rocksdb/iterator.h"
#include "util/autovector.h"
namespace ROCKSDB_NAMESPACE {
@@ -64,26 +65,12 @@ class ArenaWrappedDBIter : public Iterator {
void SeekToLast() override { db_iter_->SeekToLast(); }
// 'target' does not contain timestamp, even if user timestamp feature is
// enabled.
void Seek(const Slice& target) override {
MaybeAutoRefresh(true /* is_seek */, DBIter::kForward);
db_iter_->Seek(target);
}
void Seek(const Slice& target) override { db_iter_->Seek(target); }
void SeekForPrev(const Slice& target) override {
MaybeAutoRefresh(true /* is_seek */, DBIter::kReverse);
db_iter_->SeekForPrev(target);
}
void Next() override {
db_iter_->Next();
MaybeAutoRefresh(false /* is_seek */, DBIter::kForward);
}
void Prev() override {
db_iter_->Prev();
MaybeAutoRefresh(false /* is_seek */, DBIter::kReverse);
}
void Next() override { db_iter_->Next(); }
void Prev() override { db_iter_->Prev(); }
Slice key() const override { return db_iter_->key(); }
Slice value() const override { return db_iter_->value(); }
const WideColumns& columns() const override { return db_iter_->columns(); }
@@ -98,19 +85,13 @@ class ArenaWrappedDBIter : public Iterator {
bool PrepareValue() override { return db_iter_->PrepareValue(); }
void Prepare(const std::vector<ScanOptions>& scan_opts) override {
db_iter_->Prepare(scan_opts);
}
// FIXME: we could just pass SV in for mutable cf option, version and version
// number, but this is used by SstFileReader which does not have a SV.
void Init(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t version_number,
const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, bool allow_refresh,
ReadOnlyMemTable* active_mem);
bool expose_blob_index, bool allow_refresh);
// Store some parameters so we can refresh the iterator at a later point
// with these same params
@@ -122,9 +103,6 @@ class ArenaWrappedDBIter : public Iterator {
}
private:
void DoRefresh(const Snapshot* snapshot, uint64_t sv_number);
void MaybeAutoRefresh(bool is_seek, DBIter::Direction direction);
DBIter* db_iter_ = nullptr;
Arena arena_;
uint64_t sv_number_;
@@ -133,16 +111,20 @@ class ArenaWrappedDBIter : public Iterator {
ReadCallback* read_callback_;
bool expose_blob_index_ = false;
bool allow_refresh_ = true;
bool allow_mark_memtable_for_flush_ = true;
// If this is nullptr, it means the mutable memtable does not contain range
// tombstone when added under this DBIter.
std::unique_ptr<TruncatedRangeDelIterator>* memtable_range_tombstone_iter_ =
nullptr;
};
// Generate the arena wrapped iterator class.
// `cfh` is used for reneweal. If left null, renewal will not
// be supported.
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, ColumnFamilyHandleImpl* cfh,
SuperVersion* sv, const SequenceNumber& sequence,
ReadCallback* read_callback, DBImpl* db_impl, bool expose_blob_index,
bool allow_refresh, bool allow_mark_memtable_for_flush);
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Version* version,
const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iterations,
uint64_t version_number, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh = nullptr, bool expose_blob_index = false,
bool allow_refresh = true);
} // namespace ROCKSDB_NAMESPACE
+7 -10
View File
@@ -188,12 +188,10 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
}
std::unique_ptr<FSWritableFile> file;
FileOptions fo_copy;
{
assert(file_options_);
fo_copy = *file_options_;
fo_copy.write_hint = write_hint_;
Status s = NewWritableFile(fs_, blob_file_path, &file, fo_copy);
Status s = NewWritableFile(fs_, blob_file_path, &file, *file_options_);
TEST_SYNC_POINT_CALLBACK(
"BlobFileBuilder::OpenBlobFileIfNeeded:NewWritableFile", &s);
@@ -211,9 +209,7 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
assert(file);
file->SetIOPriority(write_options_->rate_limiter_priority);
// Subsequent attempts to override the hint via SetWriteLifeTimeHint
// with the very same value will be ignored by the fs.
file->SetWriteLifeTimeHint(fo_copy.write_hint);
file->SetWriteLifeTimeHint(write_hint_);
FileTypeSet tmp_set = immutable_options_->checksum_handoff_file_types;
Statistics* const statistics = immutable_options_->stats;
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
@@ -267,9 +263,10 @@ Status BlobFileBuilder::CompressBlobIfNeeded(
// TODO: allow user CompressionOptions, including max_compressed_bytes_per_kb
CompressionOptions opts;
CompressionContext context(blob_compression_type_, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
blob_compression_type_);
blob_compression_type_, sample_for_compression);
constexpr uint32_t compression_format_version = 2;
@@ -278,8 +275,8 @@ Status BlobFileBuilder::CompressBlobIfNeeded(
{
StopWatch stop_watch(immutable_options_->clock, immutable_options_->stats,
BLOB_DB_COMPRESSION_MICROS);
success = OLD_CompressData(*blob, info, compression_format_version,
compressed_blob);
success =
CompressData(*blob, info, compression_format_version, compressed_blob);
}
if (!success) {
+2 -1
View File
@@ -405,9 +405,10 @@ TEST_F(BlobFileBuilderTest, Compression) {
CompressionOptions opts;
CompressionContext context(kSnappyCompression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
kSnappyCompression);
kSnappyCompression, sample_for_compression);
std::string compressed_value;
ASSERT_TRUE(Snappy_Compress(info, uncompressed_value.data(),
-1
View File
@@ -6,7 +6,6 @@
#pragma once
#include <cassert>
#include <cstdint>
#include <iosfwd>
#include <memory>
#include <string>
+9 -12
View File
@@ -250,8 +250,7 @@ Status BlobFileReader::ReadFromFile(const RandomAccessFileReader* file_reader,
Status s;
IOOptions io_options;
IODebugContext dbg;
s = file_reader->PrepareIOOptions(read_options, io_options, &dbg);
s = file_reader->PrepareIOOptions(read_options, io_options);
if (!s.ok()) {
return s;
}
@@ -260,13 +259,13 @@ Status BlobFileReader::ReadFromFile(const RandomAccessFileReader* file_reader,
constexpr char* scratch = nullptr;
s = file_reader->Read(io_options, read_offset, read_size, slice, scratch,
aligned_buf, &dbg);
aligned_buf);
} else {
buf->reset(new char[read_size]);
constexpr AlignedBuf* aligned_scratch = nullptr;
s = file_reader->Read(io_options, read_offset, read_size, slice, buf->get(),
aligned_scratch, &dbg);
aligned_scratch);
}
if (!s.ok()) {
@@ -335,8 +334,7 @@ Status BlobFileReader::GetBlob(
constexpr bool for_compaction = true;
IOOptions io_options;
IODebugContext dbg;
s = file_reader_->PrepareIOOptions(read_options, io_options, &dbg);
s = file_reader_->PrepareIOOptions(read_options, io_options);
if (!s.ok()) {
return s;
}
@@ -465,11 +463,10 @@ void BlobFileReader::MultiGetBlob(
PERF_COUNTER_ADD(blob_read_count, num_blobs);
PERF_COUNTER_ADD(blob_read_byte, total_len);
IOOptions opts;
IODebugContext dbg;
s = file_reader_->PrepareIOOptions(read_options, opts, &dbg);
s = file_reader_->PrepareIOOptions(read_options, opts);
if (s.ok()) {
s = file_reader_->MultiRead(opts, read_reqs.data(), read_reqs.size(),
direct_io ? &aligned_buf : nullptr, &dbg);
direct_io ? &aligned_buf : nullptr);
}
if (!s.ok()) {
for (auto& req : read_reqs) {
@@ -605,9 +602,9 @@ Status BlobFileReader::UncompressBlobIfNeeded(
{
PERF_TIMER_GUARD(blob_decompress_time);
StopWatch stop_watch(clock, statistics, BLOB_DB_DECOMPRESSION_MICROS);
output = OLD_UncompressData(info, value_slice.data(), value_slice.size(),
&uncompressed_size, compression_format_version,
allocator);
output = UncompressData(info, value_slice.data(), value_slice.size(),
&uncompressed_size, compression_format_version,
allocator);
}
TEST_SYNC_POINT_CALLBACK(
+4 -3
View File
@@ -75,14 +75,15 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
} else {
CompressionOptions opts;
CompressionContext context(compression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
compression);
compression, sample_for_compression);
constexpr uint32_t compression_format_version = 2;
for (size_t i = 0; i < num; ++i) {
ASSERT_TRUE(OLD_CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
ASSERT_TRUE(CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
blobs_to_write[i] = compressed_blobs[i];
blob_sizes[i] = compressed_blobs[i].size();
}
+2 -2
View File
@@ -82,8 +82,8 @@ Status BlobSource::PutBlobIntoCache(
assert(cached_blob->IsEmpty());
TypedHandle* cache_handle = nullptr;
const Status s = InsertEntryIntoCache(cache_key, blob->get(), &cache_handle,
Cache::Priority::BOTTOM);
const Status s = InsertEntryIntoCache(cache_key, blob->get(),
&cache_handle, Cache::Priority::BOTTOM);
if (s.ok()) {
blob->release();
+4 -3
View File
@@ -77,14 +77,15 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
} else {
CompressionOptions opts;
CompressionContext context(compression, opts);
constexpr uint64_t sample_for_compression = 0;
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
compression);
compression, sample_for_compression);
constexpr uint32_t compression_format_version = 2;
for (size_t i = 0; i < num; ++i) {
ASSERT_TRUE(OLD_CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
ASSERT_TRUE(CompressData(blobs[i], info, compression_format_version,
&compressed_blobs[i]));
blobs_to_write[i] = compressed_blobs[i];
blob_sizes[i] = compressed_blobs[i].size();
}
+8 -22
View File
@@ -74,8 +74,8 @@ Status BuildTable(
EventLogger* event_logger, int job_id, TableProperties* table_properties,
Env::WriteLifeTimeHint write_hint, const std::string* full_history_ts_low,
BlobFileCompletionCallback* blob_callback, Version* version,
uint64_t* memtable_payload_bytes, uint64_t* memtable_garbage_bytes,
InternalStats::CompactionStats* flush_stats) {
uint64_t* num_input_entries, uint64_t* memtable_payload_bytes,
uint64_t* memtable_garbage_bytes) {
assert((tboptions.column_family_id ==
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
tboptions.column_family_name.empty());
@@ -145,9 +145,7 @@ Status BuildTable(
bool use_direct_writes = file_options.use_direct_writes;
TEST_SYNC_POINT_CALLBACK("BuildTable:create_file", &use_direct_writes);
#endif // !NDEBUG
FileOptions fo_copy = file_options;
fo_copy.write_hint = write_hint;
IOStatus io_s = NewWritableFile(fs, fname, &file, fo_copy);
IOStatus io_s = NewWritableFile(fs, fname, &file, file_options);
assert(s.ok());
s = io_s;
if (io_status->ok()) {
@@ -165,9 +163,7 @@ Status BuildTable(
table_file_created = true;
FileTypeSet tmp_set = ioptions.checksum_handoff_file_types;
file->SetIOPriority(tboptions.write_options.rate_limiter_priority);
// Subsequent attempts to override the hint via SetWriteLifeTimeHint
// with the very same value will be ignored by the fs.
file->SetWriteLifeTimeHint(fo_copy.write_hint);
file->SetWriteLifeTimeHint(write_hint);
file_writer.reset(new WritableFileWriter(
std::move(file), fname, file_options, ioptions.clock, io_tracer,
ioptions.stats, Histograms::SST_WRITE_MICROS, ioptions.listeners,
@@ -218,7 +214,8 @@ Status BuildTable(
const Slice& key = c_iter.key();
const Slice& value = c_iter.value();
ParsedInternalKey ikey = c_iter.ikey();
Slice key_after_flush = key;
key_after_flush_buf.assign(key.data(), key.size());
Slice key_after_flush = key_after_flush_buf;
Slice value_after_flush = value;
if (ikey.type == kTypeValuePreferredSeqno) {
@@ -236,7 +233,6 @@ Status BuildTable(
std::min(smallest_preferred_seqno, preferred_seqno);
} else {
// Cannot get a useful preferred seqno, convert it to a kTypeValue.
key_after_flush_buf.assign(key.data(), key.size());
UpdateInternalKey(&key_after_flush_buf, ikey.sequence, kTypeValue);
ikey = ParsedInternalKey(ikey.user_key, ikey.sequence, kTypeValue);
key_after_flush = key_after_flush_buf;
@@ -253,10 +249,6 @@ Status BuildTable(
}
builder->Add(key_after_flush, value_after_flush);
if (flush_stats) {
flush_stats->num_output_records++;
}
s = meta->UpdateBoundaries(key_after_flush, value_after_flush,
ikey.sequence, ikey.type);
if (!s.ok()) {
@@ -288,9 +280,6 @@ Status BuildTable(
auto tombstone = range_del_it->Tombstone();
std::pair<InternalKey, Slice> kv = tombstone.Serialize();
builder->Add(kv.first.Encode(), kv.second);
if (flush_stats) {
flush_stats->num_output_records++;
}
InternalKey tombstone_end = tombstone.SerializeEndKey();
meta->UpdateBoundariesForRange(kv.first, tombstone_end, tombstone.seq_,
tboptions.internal_comparator);
@@ -312,9 +301,9 @@ Status BuildTable(
TEST_SYNC_POINT("BuildTable:BeforeFinishBuildTable");
const bool empty = builder->IsEmpty();
if (flush_stats) {
if (num_input_entries != nullptr) {
assert(c_iter.HasNumInputEntryScanned());
flush_stats->num_input_records =
*num_input_entries =
c_iter.NumInputEntryScanned() + num_unfragmented_tombstones;
}
if (!s.ok() || empty) {
@@ -341,9 +330,6 @@ Status BuildTable(
}
if (s.ok() && !empty) {
if (flush_stats) {
flush_stats->bytes_written_pre_comp = builder->PreCompressionSize();
}
uint64_t file_size = builder->FileSize();
meta->fd.file_size = file_size;
meta->tail_size = builder->GetTailSize();
+4 -5
View File
@@ -10,7 +10,6 @@
#include <utility>
#include <vector>
#include "db/internal_stats.h"
#include "db/range_tombstone_fragmenter.h"
#include "db/seqno_to_time_mapping.h"
#include "db/table_properties_collector.h"
@@ -35,6 +34,7 @@ class SnapshotChecker;
class TableCache;
class TableBuilder;
class WritableFileWriter;
class InternalStats;
class BlobFileCompletionCallback;
// Convenience function for NewTableBuilder on the embedded table_factory.
@@ -49,7 +49,6 @@ TableBuilder* NewTableBuilder(const TableBuilderOptions& tboptions,
//
// @param column_family_name Name of the column family that is also identified
// by column_family_id, or empty string if unknown.
// @param flush_stats treat flush as level 0 compaction in internal stats
Status BuildTable(
const std::string& dbname, VersionSet* versions,
const ImmutableDBOptions& db_options, const TableBuilderOptions& tboptions,
@@ -70,8 +69,8 @@ Status BuildTable(
Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET,
const std::string* full_history_ts_low = nullptr,
BlobFileCompletionCallback* blob_callback = nullptr,
Version* version = nullptr, uint64_t* memtable_payload_bytes = nullptr,
uint64_t* memtable_garbage_bytes = nullptr,
InternalStats::CompactionStats* flush_stats = nullptr);
Version* version = nullptr, uint64_t* num_input_entries = nullptr,
uint64_t* memtable_payload_bytes = nullptr,
uint64_t* memtable_garbage_bytes = nullptr);
} // namespace ROCKSDB_NAMESPACE
+15 -569
View File
@@ -24,14 +24,12 @@
#include "rocksdb/experimental.h"
#include "rocksdb/filter_policy.h"
#include "rocksdb/iterator.h"
#include "rocksdb/listener.h"
#include "rocksdb/memtablerep.h"
#include "rocksdb/merge_operator.h"
#include "rocksdb/options.h"
#include "rocksdb/perf_context.h"
#include "rocksdb/rate_limiter.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/sst_file_manager.h"
#include "rocksdb/statistics.h"
#include "rocksdb/status.h"
#include "rocksdb/table.h"
@@ -51,7 +49,6 @@
#include "util/stderr_logger.h"
#include "utilities/merge_operators.h"
using ROCKSDB_NAMESPACE::BackgroundErrorReason;
using ROCKSDB_NAMESPACE::BackupEngine;
using ROCKSDB_NAMESPACE::BackupEngineOptions;
using ROCKSDB_NAMESPACE::BackupID;
@@ -68,9 +65,7 @@ using ROCKSDB_NAMESPACE::ColumnFamilyMetaData;
using ROCKSDB_NAMESPACE::ColumnFamilyOptions;
using ROCKSDB_NAMESPACE::CompactionFilter;
using ROCKSDB_NAMESPACE::CompactionFilterFactory;
using ROCKSDB_NAMESPACE::CompactionJobInfo;
using ROCKSDB_NAMESPACE::CompactionOptionsFIFO;
using ROCKSDB_NAMESPACE::CompactionReason;
using ROCKSDB_NAMESPACE::CompactRangeOptions;
using ROCKSDB_NAMESPACE::Comparator;
using ROCKSDB_NAMESPACE::CompressionType;
@@ -81,11 +76,8 @@ using ROCKSDB_NAMESPACE::DBOptions;
using ROCKSDB_NAMESPACE::DbPath;
using ROCKSDB_NAMESPACE::Env;
using ROCKSDB_NAMESPACE::EnvOptions;
using ROCKSDB_NAMESPACE::EventListener;
using ROCKSDB_NAMESPACE::ExternalFileIngestionInfo;
using ROCKSDB_NAMESPACE::FileLock;
using ROCKSDB_NAMESPACE::FilterPolicy;
using ROCKSDB_NAMESPACE::FlushJobInfo;
using ROCKSDB_NAMESPACE::FlushOptions;
using ROCKSDB_NAMESPACE::HistogramData;
using ROCKSDB_NAMESPACE::HyperClockCacheOptions;
@@ -98,7 +90,6 @@ using ROCKSDB_NAMESPACE::Logger;
using ROCKSDB_NAMESPACE::LRUCacheOptions;
using ROCKSDB_NAMESPACE::MemoryAllocator;
using ROCKSDB_NAMESPACE::MemoryUtil;
using ROCKSDB_NAMESPACE::MemTableInfo;
using ROCKSDB_NAMESPACE::MergeOperator;
using ROCKSDB_NAMESPACE::NewBloomFilterPolicy;
using ROCKSDB_NAMESPACE::NewCompactOnDeletionCollectorFactory;
@@ -122,12 +113,10 @@ using ROCKSDB_NAMESPACE::Slice;
using ROCKSDB_NAMESPACE::SliceParts;
using ROCKSDB_NAMESPACE::SliceTransform;
using ROCKSDB_NAMESPACE::Snapshot;
using ROCKSDB_NAMESPACE::SstFileManager;
using ROCKSDB_NAMESPACE::SstFileMetaData;
using ROCKSDB_NAMESPACE::SstFileWriter;
using ROCKSDB_NAMESPACE::Status;
using ROCKSDB_NAMESPACE::StderrLogger;
using ROCKSDB_NAMESPACE::SubcompactionJobInfo;
using ROCKSDB_NAMESPACE::TablePropertiesCollectorFactory;
using ROCKSDB_NAMESPACE::Transaction;
using ROCKSDB_NAMESPACE::TransactionDB;
@@ -141,8 +130,6 @@ using ROCKSDB_NAMESPACE::WriteBatch;
using ROCKSDB_NAMESPACE::WriteBatchWithIndex;
using ROCKSDB_NAMESPACE::WriteBufferManager;
using ROCKSDB_NAMESPACE::WriteOptions;
using ROCKSDB_NAMESPACE::WriteStallCondition;
using ROCKSDB_NAMESPACE::WriteStallInfo;
using std::unordered_set;
using std::vector;
@@ -152,9 +139,6 @@ extern "C" {
struct rocksdb_t {
DB* rep;
};
struct rocksdb_status_ptr_t {
Status* rep;
};
struct rocksdb_backup_engine_t {
BackupEngine* rep;
};
@@ -242,15 +226,12 @@ struct rocksdb_cache_t {
struct rocksdb_write_buffer_manager_t {
std::shared_ptr<WriteBufferManager> rep;
};
struct rocksdb_sst_file_manager_t {
std::shared_ptr<SstFileManager> rep;
};
struct rocksdb_livefiles_t {
std::vector<LiveFileMetaData> rep;
};
struct rocksdb_column_family_handle_t {
ColumnFamilyHandle* rep;
bool immortal; /* only true for default cf */
bool immortal; /* only true for default cf */
};
struct rocksdb_column_family_metadata_t {
ColumnFamilyMetaData rep;
@@ -311,28 +292,6 @@ struct rocksdb_compactionfiltercontext_t {
CompactionFilter::Context rep;
};
struct rocksdb_flushjobinfo_t {
FlushJobInfo rep;
};
struct rocksdb_writestallcondition_t {
WriteStallCondition rep;
};
struct rocksdb_writestallinfo_t {
WriteStallInfo rep;
};
struct rocksdb_memtableinfo_t {
MemTableInfo rep;
};
struct rocksdb_compactionjobinfo_t {
CompactionJobInfo rep;
};
struct rocksdb_subcompactionjobinfo_t {
SubcompactionJobInfo rep;
};
struct rocksdb_externalfileingestioninfo_t {
ExternalFileIngestionInfo rep;
};
struct rocksdb_statistics_histogram_data_t {
rocksdb_statistics_histogram_data_t() : rep() {}
HistogramData rep;
@@ -925,10 +884,6 @@ void rocksdb_backup_engine_options_destroy(
delete options;
}
void rocksdb_status_ptr_get_error(rocksdb_status_ptr_t* status, char** errptr) {
SaveError(errptr, *(status->rep));
}
rocksdb_checkpoint_t* rocksdb_checkpoint_object_create(rocksdb_t* db,
char** errptr) {
Checkpoint* checkpoint;
@@ -1903,6 +1858,10 @@ extern ROCKSDB_LIBRARY_API void rocksdb_approximate_sizes_cf_with_flags(
delete[] ranges;
}
void rocksdb_delete_file(rocksdb_t* db, const char* name) {
db->rep->DeleteFile(name);
}
const rocksdb_livefiles_t* rocksdb_livefiles(rocksdb_t* db) {
rocksdb_livefiles_t* result = new rocksdb_livefiles_t;
db->rep->GetLiveFilesMetaData(&result->rep);
@@ -2672,16 +2631,6 @@ rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base(
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
const rocksdb_readoptions_t* options) {
rocksdb_iterator_t* result = new rocksdb_iterator_t;
result->rep =
wbwi->rep->NewIteratorWithBase(base_iterator->rep, &options->rep);
delete base_iterator;
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* column_family) {
@@ -2692,17 +2641,6 @@ rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf(
return result;
}
rocksdb_iterator_t* rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
rocksdb_writebatch_wi_t* wbwi, rocksdb_iterator_t* base_iterator,
rocksdb_column_family_handle_t* column_family,
const rocksdb_readoptions_t* options) {
rocksdb_iterator_t* result = new rocksdb_iterator_t;
result->rep = wbwi->rep->NewIteratorWithBase(
column_family->rep, base_iterator->rep, &options->rep);
delete base_iterator;
return result;
}
char* rocksdb_writebatch_wi_get_from_batch(rocksdb_writebatch_wi_t* wbwi,
const rocksdb_options_t* options,
const char* key, size_t keylen,
@@ -2762,23 +2700,6 @@ char* rocksdb_writebatch_wi_get_from_batch_and_db(
return result;
}
rocksdb_pinnableslice_t* rocksdb_writebatch_wi_get_pinned_from_batch_and_db(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options, const char* key, size_t keylen,
char** errptr) {
rocksdb_pinnableslice_t* v = new (rocksdb_pinnableslice_t);
Status s = wbwi->rep->GetFromBatchAndDB(db->rep, options->rep,
Slice(key, keylen), &v->rep);
if (!s.ok()) {
delete (v);
if (!s.IsNotFound()) {
SaveError(errptr, s);
}
return nullptr;
}
return v;
}
char* rocksdb_writebatch_wi_get_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
@@ -2800,24 +2721,6 @@ char* rocksdb_writebatch_wi_get_from_batch_and_db_cf(
return result;
}
rocksdb_pinnableslice_t* rocksdb_writebatch_wi_get_pinned_from_batch_and_db_cf(
rocksdb_writebatch_wi_t* wbwi, rocksdb_t* db,
const rocksdb_readoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr) {
rocksdb_pinnableslice_t* v = new (rocksdb_pinnableslice_t);
Status s = wbwi->rep->GetFromBatchAndDB(
db->rep, options->rep, column_family->rep, Slice(key, keylen), &v->rep);
if (!s.ok()) {
delete (v);
if (!s.IsNotFound()) {
SaveError(errptr, s);
}
return nullptr;
}
return v;
}
void rocksdb_write_writebatch_wi(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_writebatch_wi_t* wbwi, char** errptr) {
@@ -3031,361 +2934,6 @@ void rocksdb_block_based_options_set_unpartitioned_pinning_tier(
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
}
/* FlushJobInfo */
const char* rocksdb_flushjobinfo_cf_name(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_flushjobinfo_file_path(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.file_path.size();
return info->rep.file_path.data();
}
unsigned char rocksdb_flushjobinfo_triggered_writes_slowdown(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_slowdown;
}
unsigned char rocksdb_flushjobinfo_triggered_writes_stop(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_stop;
}
uint64_t rocksdb_flushjobinfo_largest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.largest_seqno;
}
uint64_t rocksdb_flushjobinfo_smallest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.smallest_seqno;
}
uint32_t rocksdb_flushjobinfo_flush_reason(const rocksdb_flushjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.flush_reason);
}
void rocksdb_reset_status(rocksdb_status_ptr_t* status_ptr) {
auto ptr = status_ptr->rep;
*ptr = Status::OK();
}
/* CompactionJobInfo */
void rocksdb_compactionjobinfo_status(const rocksdb_compactionjobinfo_t* info,
char** errptr) {
SaveError(errptr, info->rep.status);
}
const char* rocksdb_compactionjobinfo_cf_name(
const rocksdb_compactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
size_t rocksdb_compactionjobinfo_input_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.input_files.size();
}
const char* rocksdb_compactionjobinfo_input_file_at(
const rocksdb_compactionjobinfo_t* info, size_t pos, size_t* size) {
assert(info != nullptr);
assert(pos < info->rep.input_files.size());
const std::string& path = info->rep.input_files[pos];
*size = path.size();
return path.data();
}
size_t rocksdb_compactionjobinfo_output_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_files.size();
}
const char* rocksdb_compactionjobinfo_output_file_at(
const rocksdb_compactionjobinfo_t* info, size_t pos, size_t* size) {
assert(info != nullptr);
assert(pos < info->rep.output_files.size());
const std::string& path = info->rep.output_files[pos];
*size = path.size();
return path.data();
}
uint64_t rocksdb_compactionjobinfo_elapsed_micros(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.elapsed_micros;
}
uint64_t rocksdb_compactionjobinfo_num_corrupt_keys(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_corrupt_keys;
}
int rocksdb_compactionjobinfo_base_input_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_compactionjobinfo_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_level;
}
size_t rocksdb_compactionjobinfo_num_input_files(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files;
}
size_t rocksdb_compactionjobinfo_num_input_files_at_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files_at_output_level;
}
uint64_t rocksdb_compactionjobinfo_input_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_records;
}
uint64_t rocksdb_compactionjobinfo_output_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_output_records;
}
uint64_t rocksdb_compactionjobinfo_total_input_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_input_bytes;
}
uint64_t rocksdb_compactionjobinfo_total_output_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_output_bytes;
}
uint32_t rocksdb_compactionjobinfo_compaction_reason(
const rocksdb_compactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compaction_reason);
}
/* SubcompactionJobInfo */
void rocksdb_subcompactionjobinfo_status(
const rocksdb_subcompactionjobinfo_t* info, char** errptr) {
SaveError(errptr, info->rep.status);
}
const char* rocksdb_subcompactionjobinfo_cf_name(
const rocksdb_subcompactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
uint64_t rocksdb_subcompactionjobinfo_thread_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.thread_id;
}
int rocksdb_subcompactionjobinfo_base_input_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_subcompactionjobinfo_output_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.output_level;
}
uint32_t rocksdb_subcompactionjobinfo_compaction_reason(
const rocksdb_subcompactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compaction_reason);
}
/* ExternalFileIngestionInfo */
const char* rocksdb_externalfileingestioninfo_cf_name(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_externalfileingestioninfo_internal_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.internal_file_path.size();
return info->rep.internal_file_path.data();
}
/* External write stall info */
extern ROCKSDB_LIBRARY_API const char* rocksdb_writestallinfo_cf_name(
const rocksdb_writestallinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_cur(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.cur);
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_prev(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.prev);
}
const char* rocksdb_memtableinfo_cf_name(const rocksdb_memtableinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
uint64_t rocksdb_memtableinfo_first_seqno(const rocksdb_memtableinfo_t* info) {
return info->rep.first_seqno;
}
uint64_t rocksdb_memtableinfo_earliest_seqno(
const rocksdb_memtableinfo_t* info) {
return info->rep.earliest_seqno;
}
uint64_t rocksdb_memtableinfo_num_entries(const rocksdb_memtableinfo_t* info) {
return info->rep.num_entries;
}
uint64_t rocksdb_memtableinfo_num_deletes(const rocksdb_memtableinfo_t* info) {
return info->rep.num_deletes;
}
/* event listener */
struct rocksdb_eventlistener_t : public EventListener {
void* state_{};
void (*destructor_)(void*){};
void (*on_flush_begin)(void*, rocksdb_t*, const rocksdb_flushjobinfo_t*){};
void (*on_flush_completed)(void*, rocksdb_t*,
const rocksdb_flushjobinfo_t*){};
void (*on_compaction_begin)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*){};
void (*on_compaction_completed)(void*, rocksdb_t*,
const rocksdb_compactionjobinfo_t*){};
void (*on_subcompaction_begin)(void*,
const rocksdb_subcompactionjobinfo_t*){};
void (*on_subcompaction_completed)(void*,
const rocksdb_subcompactionjobinfo_t*){};
void (*on_external_file_ingested)(
void*, rocksdb_t*, const rocksdb_externalfileingestioninfo_t*){};
void (*on_background_error)(void*, uint32_t, rocksdb_status_ptr_t*){};
void (*on_stall_conditions_changed)(void*, const rocksdb_writestallinfo_t*){};
void (*on_memtable_sealed)(void*, const rocksdb_memtableinfo_t*){};
rocksdb_eventlistener_t() = default;
rocksdb_eventlistener_t(const rocksdb_eventlistener_t&) = delete;
rocksdb_eventlistener_t& operator=(const rocksdb_eventlistener_t&) = delete;
rocksdb_eventlistener_t(rocksdb_eventlistener_t&&) = delete;
rocksdb_eventlistener_t& operator=(rocksdb_eventlistener_t&&) = delete;
void OnFlushBegin(DB* db, const FlushJobInfo& info) override {
rocksdb_t c_db = {db};
on_flush_begin(state_, &c_db,
reinterpret_cast<const rocksdb_flushjobinfo_t*>(&info));
}
void OnFlushCompleted(DB* db, const FlushJobInfo& info) override {
rocksdb_t c_db = {db};
on_flush_completed(state_, &c_db,
reinterpret_cast<const rocksdb_flushjobinfo_t*>(&info));
}
void OnCompactionBegin(DB* db, const CompactionJobInfo& info) override {
rocksdb_t c_db = {db};
on_compaction_begin(
state_, &c_db,
reinterpret_cast<const rocksdb_compactionjobinfo_t*>(&info));
}
void OnCompactionCompleted(DB* db, const CompactionJobInfo& info) override {
rocksdb_t c_db = {db};
on_compaction_completed(
state_, &c_db,
reinterpret_cast<const rocksdb_compactionjobinfo_t*>(&info));
}
void OnSubcompactionBegin(const SubcompactionJobInfo& info) override {
on_subcompaction_begin(
state_, reinterpret_cast<const rocksdb_subcompactionjobinfo_t*>(&info));
}
void OnSubcompactionCompleted(const SubcompactionJobInfo& info) override {
on_subcompaction_completed(
state_, reinterpret_cast<const rocksdb_subcompactionjobinfo_t*>(&info));
}
void OnExternalFileIngested(DB* db,
const ExternalFileIngestionInfo& info) override {
rocksdb_t c_db = {db};
on_external_file_ingested(
state_, &c_db,
reinterpret_cast<const rocksdb_externalfileingestioninfo_t*>(&info));
}
void OnBackgroundError(BackgroundErrorReason reason,
Status* status) override {
rocksdb_status_ptr_t* s = new rocksdb_status_ptr_t;
s->rep = status;
on_background_error(state_, static_cast<uint32_t>(reason), s);
delete s;
}
void OnStallConditionsChanged(const WriteStallInfo& info) override {
on_stall_conditions_changed(
state_, reinterpret_cast<const rocksdb_writestallinfo_t*>(&info));
}
void OnMemTableSealed(const MemTableInfo& info) override {
on_memtable_sealed(state_,
reinterpret_cast<const rocksdb_memtableinfo_t*>(&info));
}
~rocksdb_eventlistener_t() override { destructor_(state_); }
};
rocksdb_eventlistener_t* rocksdb_eventlistener_create(
void* state_, void (*destructor_)(void*), on_flush_begin_cb on_flush_begin,
on_flush_completed_cb on_flush_completed,
on_compaction_begin_cb on_compaction_begin,
on_compaction_completed_cb on_compaction_completed,
on_subcompaction_begin_cb on_subcompaction_begin,
on_subcompaction_completed_cb on_subcompaction_completed,
on_external_file_ingested_cb on_external_file_ingested,
on_background_error_cb on_background_error,
on_stall_conditions_changed_cb on_stall_conditions_changed,
on_memtable_sealed_cb on_memtable_sealed) {
rocksdb_eventlistener_t* et = new rocksdb_eventlistener_t;
et->state_ = state_;
et->destructor_ = destructor_;
et->on_flush_begin = on_flush_begin;
et->on_flush_completed = on_flush_completed;
et->on_compaction_begin = on_compaction_begin;
et->on_compaction_completed = on_compaction_completed;
et->on_subcompaction_begin = on_subcompaction_begin;
et->on_subcompaction_completed = on_subcompaction_completed;
et->on_external_file_ingested = on_external_file_ingested;
et->on_background_error = on_background_error;
et->on_stall_conditions_changed = on_stall_conditions_changed;
et->on_memtable_sealed = on_memtable_sealed;
return et;
}
void rocksdb_eventlistener_destroy(rocksdb_eventlistener_t* t) { delete t; }
void rocksdb_options_add_eventlistener(rocksdb_options_t* opt,
rocksdb_eventlistener_t* t) {
opt->rep.listeners.emplace_back(std::shared_ptr<EventListener>(t));
}
rocksdb_cuckoo_table_options_t* rocksdb_cuckoo_options_create() {
return new rocksdb_cuckoo_table_options_t;
}
@@ -3751,26 +3299,6 @@ uint64_t rocksdb_options_get_periodic_compaction_seconds(
return opt->rep.periodic_compaction_seconds;
}
void rocksdb_options_set_memtable_op_scan_flush_trigger(rocksdb_options_t* opt,
uint32_t n) {
opt->rep.memtable_op_scan_flush_trigger = n;
}
uint32_t rocksdb_options_get_memtable_op_scan_flush_trigger(
rocksdb_options_t* opt) {
return opt->rep.memtable_op_scan_flush_trigger;
}
void rocksdb_options_set_memtable_avg_op_scan_flush_trigger(
rocksdb_options_t* opt, uint32_t n) {
opt->rep.memtable_avg_op_scan_flush_trigger = n;
}
uint32_t rocksdb_options_get_memtable_avg_op_scan_flush_trigger(
rocksdb_options_t* opt) {
return opt->rep.memtable_avg_op_scan_flush_trigger;
}
void rocksdb_options_enable_statistics(rocksdb_options_t* opt) {
opt->rep.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
}
@@ -4280,6 +3808,16 @@ int rocksdb_options_get_min_write_buffer_number_to_merge(
return opt->rep.min_write_buffer_number_to_merge;
}
void rocksdb_options_set_max_write_buffer_number_to_maintain(
rocksdb_options_t* opt, int n) {
opt->rep.max_write_buffer_number_to_maintain = n;
}
int rocksdb_options_get_max_write_buffer_number_to_maintain(
rocksdb_options_t* opt) {
return opt->rep.max_write_buffer_number_to_maintain;
}
void rocksdb_options_set_max_write_buffer_size_to_maintain(
rocksdb_options_t* opt, int64_t n) {
opt->rep.max_write_buffer_size_to_maintain = n;
@@ -4798,8 +4336,6 @@ uint64_t rocksdb_perfcontext_metric(rocksdb_perfcontext_t* context,
return rep->internal_recent_skipped_count;
case rocksdb_internal_merge_count:
return rep->internal_merge_count;
case rocksdb_internal_merge_point_lookup_count:
return rep->internal_merge_point_lookup_count;
case rocksdb_get_snapshot_time:
return rep->get_snapshot_time;
case rocksdb_get_from_memtable_time:
@@ -5464,35 +5000,6 @@ int rocksdb_compactoptions_get_target_level(rocksdb_compactoptions_t* opt) {
return opt->rep.target_level;
}
void rocksdb_compactoptions_set_target_path_id(rocksdb_compactoptions_t* opt,
int n) {
opt->rep.target_path_id = n;
}
int rocksdb_compactoptions_get_target_path_id(rocksdb_compactoptions_t* opt) {
return opt->rep.target_path_id;
}
void rocksdb_compactoptions_set_allow_write_stall(rocksdb_compactoptions_t* opt,
unsigned char v) {
opt->rep.allow_write_stall = v;
}
unsigned char rocksdb_compactoptions_get_allow_write_stall(
rocksdb_compactoptions_t* opt) {
return opt->rep.allow_write_stall;
}
void rocksdb_compactoptions_set_max_subcompactions(
rocksdb_compactoptions_t* opt, int n) {
opt->rep.max_subcompactions = n;
}
int rocksdb_compactoptions_get_max_subcompactions(
rocksdb_compactoptions_t* opt) {
return opt->rep.max_subcompactions;
}
void rocksdb_compactoptions_set_full_history_ts_low(
rocksdb_compactoptions_t* opt, char* ts, size_t tslen) {
if (ts == nullptr) {
@@ -5707,67 +5214,6 @@ ROCKSDB_LIBRARY_API void rocksdb_write_buffer_manager_set_allow_stall(
wbm->rep->SetAllowStall(new_allow_stall);
}
rocksdb_sst_file_manager_t* rocksdb_sst_file_manager_create(
rocksdb_env_t* env) {
rocksdb_sst_file_manager_t* sfm = new rocksdb_sst_file_manager_t;
sfm->rep.reset(ROCKSDB_NAMESPACE::NewSstFileManager(env->rep));
return sfm;
}
void rocksdb_sst_file_manager_destroy(rocksdb_sst_file_manager_t* sfm) {
delete sfm;
}
void rocksdb_sst_file_manager_set_max_allowed_space_usage(
rocksdb_sst_file_manager_t* sfm, uint64_t max_allowed_space) {
sfm->rep->SetMaxAllowedSpaceUsage(max_allowed_space);
}
void rocksdb_sst_file_manager_set_compaction_buffer_size(
rocksdb_sst_file_manager_t* sfm, uint64_t compaction_buffer_size) {
sfm->rep->SetCompactionBufferSize(compaction_buffer_size);
}
bool rocksdb_sst_file_manager_is_max_allowed_space_reached(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->IsMaxAllowedSpaceReached();
}
bool rocksdb_sst_file_manager_is_max_allowed_space_reached_including_compactions(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->IsMaxAllowedSpaceReachedIncludingCompactions();
}
uint64_t rocksdb_sst_file_manager_get_total_size(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetTotalSize();
}
int64_t rocksdb_sst_file_manager_get_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetDeleteRateBytesPerSecond();
}
void rocksdb_sst_file_manager_set_delete_rate_bytes_per_second(
rocksdb_sst_file_manager_t* sfm, int64_t delete_rate) {
return sfm->rep->SetDeleteRateBytesPerSecond(delete_rate);
}
double rocksdb_sst_file_manager_get_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetMaxTrashDBRatio();
}
void rocksdb_sst_file_manager_set_max_trash_db_ratio(
rocksdb_sst_file_manager_t* sfm, double ratio) {
return sfm->rep->SetMaxTrashDBRatio(ratio);
}
uint64_t rocksdb_sst_file_manager_get_total_trash_size(
rocksdb_sst_file_manager_t* sfm) {
return sfm->rep->GetTotalTrashSize();
}
rocksdb_dbpath_t* rocksdb_dbpath_create(const char* path,
uint64_t target_size) {
rocksdb_dbpath_t* result = new rocksdb_dbpath_t;
+24 -133
View File
@@ -103,12 +103,6 @@ static void CheckValue(char* err, const char* expected, char** actual,
Free(actual);
}
static void CheckPinnedValue(char* err, const char* expected,
const char** actual, size_t actual_length) {
CheckNoError(err);
CheckEqual(expected, *actual, actual_length);
}
static void CheckGet(rocksdb_t* db, const rocksdb_readoptions_t* options,
const char* key, const char* expected) {
char* err = NULL;
@@ -1251,8 +1245,6 @@ int main(int argc, char** argv) {
CheckCondition(count == 3);
size_t size;
char* value;
const char* pinned_value;
rocksdb_pinnableslice_t* p;
value = rocksdb_writebatch_wi_get_from_batch(wbi, options, "box", 3, &size,
&err);
CheckValue(err, "c", &value, size);
@@ -1262,19 +1254,9 @@ int main(int argc, char** argv) {
value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions,
"foo", 3, &size, &err);
CheckValue(err, "hello", &value, size);
p = rocksdb_writebatch_wi_get_pinned_from_batch_and_db(wbi, db, roptions,
"foo", 3, &err);
pinned_value = rocksdb_pinnableslice_value(p, &size);
CheckPinnedValue(err, "hello", &pinned_value, size);
rocksdb_pinnableslice_destroy(p);
value = rocksdb_writebatch_wi_get_from_batch_and_db(wbi, db, roptions,
"box", 3, &size, &err);
CheckValue(err, "c", &value, size);
p = rocksdb_writebatch_wi_get_pinned_from_batch_and_db(wbi, db, roptions,
"box", 3, &err);
pinned_value = rocksdb_pinnableslice_value(p, &size);
CheckPinnedValue(err, "c", &pinned_value, size);
rocksdb_pinnableslice_destroy(p);
rocksdb_write_writebatch_wi(db, woptions, wbi, &err);
CheckNoError(err);
CheckGet(db, roptions, "foo", "hello");
@@ -1380,46 +1362,6 @@ int main(int argc, char** argv) {
rocksdb_writebatch_wi_destroy(wbi);
}
StartPhase("wbwi_iter_readoptions");
{
rocksdb_readoptions_t* iter_roptions = rocksdb_readoptions_create();
rocksdb_readoptions_set_iterate_lower_bound(iter_roptions, "boy", 3);
rocksdb_readoptions_set_iterate_upper_bound(iter_roptions, "fool", 4);
rocksdb_iterator_t* base_iter = rocksdb_create_iterator(db, iter_roptions);
rocksdb_writebatch_wi_t* wbi = rocksdb_writebatch_wi_create(0, 1);
rocksdb_writebatch_wi_put(wbi, "bar", 3, "b",
1); // should get filtered out
rocksdb_writebatch_wi_put(wbi, "cat", 3, "miau", 4);
rocksdb_writebatch_wi_put(wbi, "gnu", 3, "muh",
3); // should get filtered out
rocksdb_iterator_t* iter =
rocksdb_writebatch_wi_create_iterator_with_base_readopts(wbi, base_iter,
iter_roptions);
CheckCondition(!rocksdb_iter_valid(iter));
rocksdb_iter_seek_to_first(iter);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "cat", "miau");
rocksdb_iter_next(iter);
CheckIter(iter, "foo", "hello");
rocksdb_iter_prev(iter);
CheckIter(iter, "cat", "miau");
rocksdb_iter_prev(iter);
CheckCondition(!rocksdb_iter_valid(iter));
rocksdb_iter_seek_to_last(iter);
CheckIter(iter, "foo", "hello");
rocksdb_iter_seek(iter, "b", 1);
CheckIter(iter, "cat", "miau");
rocksdb_iter_seek_for_prev(iter, "d", 1);
CheckIter(iter, "cat", "miau");
rocksdb_iter_seek_for_prev(iter, "fool", 3);
CheckIter(iter, "foo", "hello");
rocksdb_iter_get_error(iter, &err);
CheckNoError(err);
rocksdb_iter_destroy(iter);
rocksdb_writebatch_wi_destroy(wbi);
rocksdb_readoptions_destroy(iter_roptions);
}
StartPhase("multiget");
{
const char* keys[3] = {"box", "foo", "notfound"};
@@ -1850,35 +1792,6 @@ int main(int argc, char** argv) {
rocksdb_flush_wal(db, 1, &err);
CheckNoError(err);
// Test WriteBatchWithIndex iteration with Column Family
rocksdb_writebatch_wi_t* wbwi = rocksdb_writebatch_wi_create(0, true);
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "boat", 4, "row",
3); // should be filtered out
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "buffy", 5, "charmed", 7);
rocksdb_writebatch_wi_put_cf(wbwi, handles[1], "bus", 3, "yellow",
6); // should be filtered out
rocksdb_readoptions_t* iter_roptions = rocksdb_readoptions_create();
rocksdb_readoptions_set_iterate_lower_bound(iter_roptions, "bu", 2);
rocksdb_readoptions_set_iterate_upper_bound(iter_roptions, "buffz", 5);
rocksdb_iterator_t* base_iter =
rocksdb_create_iterator_cf(db, iter_roptions, handles[1]);
rocksdb_iterator_t* wbwi_iter =
rocksdb_writebatch_wi_create_iterator_with_base_cf_readopts(
wbwi, base_iter, handles[1], iter_roptions);
CheckCondition(!rocksdb_iter_valid(wbwi_iter));
rocksdb_iter_seek_to_first(wbwi_iter);
CheckCondition(rocksdb_iter_valid(wbwi_iter));
CheckIter(wbwi_iter, "buff", "rocksdb");
rocksdb_iter_next(wbwi_iter);
CheckIter(wbwi_iter, "buffy", "charmed");
rocksdb_iter_next(wbwi_iter);
CheckCondition(!rocksdb_iter_valid(wbwi_iter));
rocksdb_iter_destroy(wbwi_iter);
rocksdb_writebatch_wi_destroy(wbwi);
rocksdb_readoptions_destroy(iter_roptions);
const char* keys[3] = {"box", "box", "barfooxx"};
const rocksdb_column_family_handle_t* get_handles[3] = {
handles[0], handles[1], handles[1]};
@@ -2216,20 +2129,16 @@ int main(int argc, char** argv) {
CheckCondition(100000 ==
rocksdb_options_get_periodic_compaction_seconds(o));
rocksdb_options_set_memtable_op_scan_flush_trigger(o, 100);
CheckCondition(100 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(o));
rocksdb_options_set_memtable_avg_op_scan_flush_trigger(o, 150);
CheckCondition(150 ==
rocksdb_options_get_memtable_avg_op_scan_flush_trigger(o));
rocksdb_options_set_ttl(o, 5000);
CheckCondition(5000 == rocksdb_options_get_ttl(o));
rocksdb_options_set_skip_stats_update_on_db_open(o, 1);
CheckCondition(1 == rocksdb_options_get_skip_stats_update_on_db_open(o));
rocksdb_options_set_skip_checking_sst_file_sizes_on_db_open(o, 1);
CheckCondition(
1 == rocksdb_options_get_skip_checking_sst_file_sizes_on_db_open(o));
rocksdb_options_set_max_write_buffer_number(o, 97);
CheckCondition(97 == rocksdb_options_get_max_write_buffer_number(o));
@@ -2237,6 +2146,10 @@ int main(int argc, char** argv) {
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(o));
rocksdb_options_set_max_write_buffer_number_to_maintain(o, 64);
CheckCondition(64 ==
rocksdb_options_get_max_write_buffer_number_to_maintain(o));
rocksdb_options_set_max_write_buffer_size_to_maintain(o, 50000);
CheckCondition(50000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(o));
@@ -2489,9 +2402,13 @@ int main(int argc, char** argv) {
CheckCondition(2.0 ==
rocksdb_options_get_max_bytes_for_level_multiplier(copy));
CheckCondition(1 == rocksdb_options_get_skip_stats_update_on_db_open(copy));
CheckCondition(
1 == rocksdb_options_get_skip_checking_sst_file_sizes_on_db_open(copy));
CheckCondition(97 == rocksdb_options_get_max_write_buffer_number(copy));
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(copy));
CheckCondition(
64 == rocksdb_options_get_max_write_buffer_number_to_maintain(copy));
CheckCondition(50000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(copy));
CheckCondition(1 == rocksdb_options_get_enable_pipelined_write(copy));
@@ -2655,18 +2572,6 @@ int main(int argc, char** argv) {
CheckCondition(100000 ==
rocksdb_options_get_periodic_compaction_seconds(o));
rocksdb_options_set_memtable_op_scan_flush_trigger(copy, 800);
CheckCondition(800 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(copy));
CheckCondition(100 ==
rocksdb_options_get_memtable_op_scan_flush_trigger(o));
rocksdb_options_set_memtable_avg_op_scan_flush_trigger(copy, 900);
CheckCondition(
900 == rocksdb_options_get_memtable_avg_op_scan_flush_trigger(copy));
CheckCondition(150 ==
rocksdb_options_get_memtable_avg_op_scan_flush_trigger(o));
rocksdb_options_set_ttl(copy, 8000);
CheckCondition(8000 == rocksdb_options_get_ttl(copy));
CheckCondition(5000 == rocksdb_options_get_ttl(o));
@@ -2675,6 +2580,12 @@ int main(int argc, char** argv) {
CheckCondition(0 == rocksdb_options_get_skip_stats_update_on_db_open(copy));
CheckCondition(1 == rocksdb_options_get_skip_stats_update_on_db_open(o));
rocksdb_options_set_skip_checking_sst_file_sizes_on_db_open(copy, 0);
CheckCondition(
0 == rocksdb_options_get_skip_checking_sst_file_sizes_on_db_open(copy));
CheckCondition(
1 == rocksdb_options_get_skip_checking_sst_file_sizes_on_db_open(o));
rocksdb_options_set_max_write_buffer_number(copy, 2000);
CheckCondition(2000 == rocksdb_options_get_max_write_buffer_number(copy));
CheckCondition(97 == rocksdb_options_get_max_write_buffer_number(o));
@@ -2685,6 +2596,12 @@ int main(int argc, char** argv) {
CheckCondition(23 ==
rocksdb_options_get_min_write_buffer_number_to_merge(o));
rocksdb_options_set_max_write_buffer_number_to_maintain(copy, 128);
CheckCondition(
128 == rocksdb_options_get_max_write_buffer_number_to_maintain(copy));
CheckCondition(64 ==
rocksdb_options_get_max_write_buffer_number_to_maintain(o));
rocksdb_options_set_max_write_buffer_size_to_maintain(copy, 9000);
CheckCondition(9000 ==
rocksdb_options_get_max_write_buffer_size_to_maintain(copy));
@@ -3021,15 +2938,6 @@ int main(int argc, char** argv) {
rocksdb_compactoptions_set_target_level(co, 1);
CheckCondition(1 == rocksdb_compactoptions_get_target_level(co));
rocksdb_compactoptions_set_target_path_id(co, 1);
CheckCondition(1 == rocksdb_compactoptions_get_target_path_id(co));
rocksdb_compactoptions_set_allow_write_stall(co, 1);
CheckCondition(1 == rocksdb_compactoptions_get_allow_write_stall(co));
rocksdb_compactoptions_set_max_subcompactions(co, 1);
CheckCondition(1 == rocksdb_compactoptions_get_max_subcompactions(co));
rocksdb_compactoptions_destroy(co);
}
@@ -4135,23 +4043,6 @@ int main(int argc, char** argv) {
rocksdb_cache_destroy(lru);
}
StartPhase("sst_file_manager");
{
rocksdb_sst_file_manager_t* sst_file_manager;
sst_file_manager = rocksdb_sst_file_manager_create(env);
rocksdb_sst_file_manager_set_delete_rate_bytes_per_second(sst_file_manager,
1);
rocksdb_sst_file_manager_set_max_trash_db_ratio(sst_file_manager, 0.75);
CheckCondition(1 ==
rocksdb_sst_file_manager_get_delete_rate_bytes_per_second(
sst_file_manager));
CheckCondition(0.75 == rocksdb_sst_file_manager_get_max_trash_db_ratio(
sst_file_manager));
rocksdb_sst_file_manager_destroy(sst_file_manager);
}
StartPhase("cancel_all_background_work");
rocksdb_cancel_all_background_work(db, 1);
+50 -114
View File
@@ -53,7 +53,7 @@ ColumnFamilyHandleImpl::ColumnFamilyHandleImpl(
ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
if (cfd_ != nullptr) {
for (auto& listener : cfd_->ioptions().listeners) {
for (auto& listener : cfd_->ioptions()->listeners) {
listener->OnColumnFamilyHandleDeletionStarted(this);
}
// Job id == 0 means that this is not our background process, but rather
@@ -110,48 +110,23 @@ void GetInternalTblPropCollFactory(
}
}
Status CheckCompressionSupportedWithManager(
CompressionType type, UnownedPtr<CompressionManager> mgr) {
if (mgr) {
if (!mgr->SupportsCompressionType(type)) {
return Status::NotSupported("Compression type " +
CompressionTypeToString(type) +
" is not recognized/supported by this "
"version of CompressionManager " +
mgr->GetId());
}
} else {
if (!CompressionTypeSupported(type)) {
if (type <= kLastBuiltinCompression) {
return Status::InvalidArgument("Compression type " +
CompressionTypeToString(type) +
" is not linked with the binary.");
} else {
return Status::NotSupported(
"Compression type " + CompressionTypeToString(type) +
" is not recognized/supported by built-in CompressionManager.");
}
}
}
return Status::OK();
}
Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options) {
if (!cf_options.compression_per_level.empty()) {
for (size_t level = 0; level < cf_options.compression_per_level.size();
++level) {
Status s = CheckCompressionSupportedWithManager(
cf_options.compression_per_level[level],
cf_options.compression_manager.get());
if (!s.ok()) {
return s;
if (!CompressionTypeSupported(cf_options.compression_per_level[level])) {
return Status::InvalidArgument(
"Compression type " +
CompressionTypeToString(cf_options.compression_per_level[level]) +
" is not linked with the binary.");
}
}
} else {
Status s = CheckCompressionSupportedWithManager(
cf_options.compression, cf_options.compression_manager.get());
if (!s.ok()) {
return s;
if (!CompressionTypeSupported(cf_options.compression)) {
return Status::InvalidArgument(
"Compression type " +
CompressionTypeToString(cf_options.compression) +
" is not linked with the binary.");
}
}
if (cf_options.compression_opts.zstd_max_train_bytes > 0) {
@@ -193,8 +168,7 @@ Status CheckConcurrentWritesSupported(const ColumnFamilyOptions& cf_options) {
}
if (!cf_options.memtable_factory->IsInsertConcurrentlySupported()) {
return Status::InvalidArgument(
"Memtable doesn't allow concurrent writes "
"(allow_concurrent_memtable_write)");
"Memtable doesn't concurrent writes (allow_concurrent_memtable_write)");
}
return Status::OK();
}
@@ -225,9 +199,8 @@ const uint64_t kDefaultTtl = 0xfffffffffffffffe;
const uint64_t kDefaultPeriodicCompSecs = 0xfffffffffffffffe;
} // anonymous namespace
ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
bool read_only,
const ColumnFamilyOptions& src) {
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
const ColumnFamilyOptions& src) {
ColumnFamilyOptions result = src;
size_t clamp_max = std::conditional<
sizeof(size_t) == 4, std::integral_constant<size_t, 0xffffffff>,
@@ -266,10 +239,6 @@ ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
result.min_write_buffer_number_to_merge = 1;
}
if (result.disallow_memtable_writes) {
// A simple memtable that enforces MarkReadOnly (unlike skip list)
result.memtable_factory = std::make_shared<VectorRepFactory>();
}
if (result.num_levels < 1) {
result.num_levels = 1;
@@ -287,10 +256,15 @@ ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
if (result.max_write_buffer_number < 2) {
result.max_write_buffer_number = 2;
}
// fall back max_write_buffer_number_to_maintain if
// max_write_buffer_size_to_maintain is not set
if (result.max_write_buffer_size_to_maintain < 0) {
result.max_write_buffer_size_to_maintain =
result.max_write_buffer_number *
static_cast<int64_t>(result.write_buffer_size);
} else if (result.max_write_buffer_size_to_maintain == 0 &&
result.max_write_buffer_number_to_maintain < 0) {
result.max_write_buffer_number_to_maintain = result.max_write_buffer_number;
}
// bloom filter size shouldn't exceed 1/4 of memtable size.
if (result.memtable_prefix_bloom_size_ratio > 0.25) {
@@ -461,33 +435,6 @@ ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
result.periodic_compaction_seconds = 0;
}
if (read_only && (result.preserve_internal_time_seconds > 0 ||
result.preclude_last_level_data_seconds > 0)) {
// With no writes coming in, we don't need periodic SeqnoToTime entries.
// Existing SST files may or may not have that info associated with them.
ROCKS_LOG_WARN(
db_options.info_log.get(),
"preserve_internal_time_seconds and preclude_last_level_data_seconds "
"are ignored in read-only DB");
result.preserve_internal_time_seconds = 0;
result.preclude_last_level_data_seconds = 0;
}
if (read_only) {
if (result.memtable_op_scan_flush_trigger) {
ROCKS_LOG_WARN(db_options.info_log.get(),
"option memtable_op_scan_flush_trigger is sanitized to "
"0(disabled) for read only DB.");
result.memtable_op_scan_flush_trigger = 0;
}
if (result.memtable_avg_op_scan_flush_trigger) {
ROCKS_LOG_WARN(
db_options.info_log.get(),
"option memtable_avg_op_scan_flush_trigger is sanitized to "
"0(disabled) for read only DB.");
result.memtable_avg_op_scan_flush_trigger = 0;
}
}
return result;
}
@@ -545,17 +492,6 @@ void SuperVersion::Init(
imm->Ref();
current->Ref();
refs.store(1, std::memory_order_relaxed);
// There should be at least one mapping entry iff time tracking is enabled.
#ifndef NDEBUG
MinAndMaxPreserveSeconds preserve_info{mutable_cf_options};
if (preserve_info.IsEnabled()) {
assert(seqno_to_time_mapping);
assert(!seqno_to_time_mapping->Empty());
} else {
assert(seqno_to_time_mapping == nullptr);
}
#endif // NDEBUG
}
namespace {
@@ -594,7 +530,7 @@ ColumnFamilyData::ColumnFamilyData(
const FileOptions* file_options, ColumnFamilySet* column_family_set,
BlockCacheTracer* const block_cache_tracer,
const std::shared_ptr<IOTracer>& io_tracer, const std::string& db_id,
const std::string& db_session_id, bool read_only)
const std::string& db_session_id)
: id_(id),
name_(name),
dummy_versions_(_dummy_versions),
@@ -604,7 +540,7 @@ ColumnFamilyData::ColumnFamilyData(
dropped_(false),
flush_skip_reschedule_(false),
internal_comparator_(cf_options.comparator),
initial_cf_options_(SanitizeCfOptions(db_options, read_only, cf_options)),
initial_cf_options_(SanitizeOptions(db_options, cf_options)),
ioptions_(db_options, initial_cf_options_),
mutable_cf_options_(initial_cf_options_),
is_delete_range_supported_(
@@ -612,6 +548,7 @@ ColumnFamilyData::ColumnFamilyData(
write_buffer_manager_(write_buffer_manager),
mem_(nullptr),
imm_(ioptions_.min_write_buffer_number_to_merge,
ioptions_.max_write_buffer_number_to_maintain,
ioptions_.max_write_buffer_size_to_maintain),
super_version_(nullptr),
super_version_number_(0),
@@ -656,7 +593,7 @@ ColumnFamilyData::ColumnFamilyData(
block_cache_tracer, io_tracer,
db_session_id));
blob_file_cache_.reset(
new BlobFileCache(_table_cache, &ioptions(), soptions(), id_,
new BlobFileCache(_table_cache, ioptions(), soptions(), id_,
internal_stats_->GetBlobFileReadHist(), io_tracer));
blob_source_.reset(new BlobSource(ioptions_, mutable_cf_options_, db_id,
db_session_id, blob_file_cache_.get()));
@@ -1031,7 +968,7 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
auto write_stall_condition_and_cause = GetWriteStallConditionAndCause(
imm()->NumNotFlushed(), vstorage->l0_delay_trigger_count(),
vstorage->estimated_compaction_needed_bytes(), mutable_cf_options,
ioptions());
*ioptions());
write_stall_condition = write_stall_condition_and_cause.first;
auto write_stall_cause = write_stall_condition_and_cause.second;
@@ -1223,13 +1160,12 @@ MemTable* ColumnFamilyData::ConstructNewMemtable(
write_buffer_manager_, earliest_seq, id_);
}
void ColumnFamilyData::CreateNewMemtable(SequenceNumber earliest_seq) {
void ColumnFamilyData::CreateNewMemtable(
const MutableCFOptions& mutable_cf_options, SequenceNumber earliest_seq) {
if (mem_ != nullptr) {
delete mem_->Unref();
}
// NOTE: db mutex must be locked for SetMemtable, so safe for
// GetLatestMutableCFOptions
SetMemtable(ConstructNewMemtable(GetLatestMutableCFOptions(), earliest_seq));
SetMemtable(ConstructNewMemtable(mutable_cf_options, earliest_seq));
mem_->Ref();
}
@@ -1242,12 +1178,10 @@ Compaction* ColumnFamilyData::PickCompaction(
const MutableCFOptions& mutable_options,
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, LogBuffer* log_buffer,
bool require_max_output_level) {
const SnapshotChecker* snapshot_checker, LogBuffer* log_buffer) {
auto* result = compaction_picker_->PickCompaction(
GetName(), mutable_options, mutable_db_options, existing_snapshots,
snapshot_checker, current_->storage_info(), log_buffer,
require_max_output_level);
snapshot_checker, current_->storage_info(), log_buffer);
if (result != nullptr) {
result->FinalizeInputInfo(current_);
}
@@ -1404,17 +1338,20 @@ bool ColumnFamilyData::ReturnThreadLocalSuperVersion(SuperVersion* sv) {
return false;
}
void ColumnFamilyData::InstallSuperVersion(
SuperVersionContext* sv_context, InstrumentedMutex* db_mutex,
std::optional<std::shared_ptr<SeqnoToTimeMapping>>
new_seqno_to_time_mapping) {
void ColumnFamilyData::InstallSuperVersion(SuperVersionContext* sv_context,
InstrumentedMutex* db_mutex) {
db_mutex->AssertHeld();
return InstallSuperVersion(sv_context, mutable_cf_options_);
}
void ColumnFamilyData::InstallSuperVersion(
SuperVersionContext* sv_context,
const MutableCFOptions& mutable_cf_options) {
SuperVersion* new_superversion = sv_context->new_superversion.release();
new_superversion->mutable_cf_options = GetLatestMutableCFOptions();
new_superversion->mutable_cf_options = mutable_cf_options;
new_superversion->Init(this, mem_, imm_.current(), current_,
new_seqno_to_time_mapping.has_value()
? std::move(new_seqno_to_time_mapping.value())
sv_context->new_seqno_to_time_mapping
? std::move(sv_context->new_seqno_to_time_mapping)
: super_version_
? super_version_->ShareSeqnoToTimeMapping()
: nullptr);
@@ -1427,7 +1364,7 @@ void ColumnFamilyData::InstallSuperVersion(
// currently RecalculateWriteStallConditions() treats it as further slowing
// down is needed.
super_version_->write_stall_condition =
RecalculateWriteStallConditions(new_superversion->mutable_cf_options);
RecalculateWriteStallConditions(mutable_cf_options);
} else {
super_version_->write_stall_condition =
old_superversion->write_stall_condition;
@@ -1440,15 +1377,14 @@ void ColumnFamilyData::InstallSuperVersion(
ResetThreadLocalSuperVersions();
if (old_superversion->mutable_cf_options.write_buffer_size !=
new_superversion->mutable_cf_options.write_buffer_size) {
mem_->UpdateWriteBufferSize(
new_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());
new_superversion->write_stall_condition, GetName(), ioptions());
}
if (old_superversion->Unref()) {
old_superversion->Cleanup();
@@ -1633,8 +1569,6 @@ Status ColumnFamilyData::SetOptions(
Status s = GetColumnFamilyOptionsFromMap(config_opts, cf_opts, options_map,
&cf_opts);
if (s.ok()) {
// FIXME: we should call SanitizeOptions() too or consolidate it with
// ValidateOptions().
s = ValidateOptions(db_opts, cf_opts);
}
if (s.ok()) {
@@ -1745,8 +1679,7 @@ ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
dummy_cfd_(new ColumnFamilyData(
ColumnFamilyData::kDummyColumnFamilyDataId, "", nullptr, nullptr,
nullptr, ColumnFamilyOptions(), *db_options, &file_options_, nullptr,
block_cache_tracer, io_tracer, db_id, db_session_id,
/*read_only*/ true)),
block_cache_tracer, io_tracer, db_id, db_session_id)),
default_cfd_cache_(nullptr),
db_name_(dbname),
db_options_(db_options),
@@ -1818,12 +1751,12 @@ size_t ColumnFamilySet::NumberOfColumnFamilies() const {
// under a DB mutex AND write thread
ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
const std::string& name, uint32_t id, Version* dummy_versions,
const ColumnFamilyOptions& options, bool read_only) {
const ColumnFamilyOptions& options) {
assert(column_families_.find(name) == column_families_.end());
ColumnFamilyData* new_cfd = new ColumnFamilyData(
id, name, dummy_versions, table_cache_, write_buffer_manager_, options,
*db_options_, &file_options_, this, block_cache_tracer_, io_tracer_,
db_id_, db_session_id_, read_only);
db_id_, db_session_id_);
column_families_.insert({name, id});
column_family_data_.insert({id, new_cfd});
auto ucmp = new_cfd->user_comparator();
@@ -1911,7 +1844,10 @@ const ImmutableOptions& GetImmutableOptions(ColumnFamilyHandle* column_family) {
const ColumnFamilyData* const cfd = handle->cfd();
assert(cfd);
return cfd->ioptions();
const ImmutableOptions* ioptions = cfd->ioptions();
assert(ioptions);
return *ioptions;
}
} // namespace ROCKSDB_NAMESPACE
+36 -53
View File
@@ -210,7 +210,6 @@ struct SuperVersion {
ReadOnlyMemTable* mem;
MemTableListVersion* imm;
Version* current;
// TODO: do we really need this in addition to what's in current Version?
MutableCFOptions mutable_cf_options;
// Version number of the current SuperVersion
uint64_t version_number;
@@ -222,8 +221,7 @@ struct SuperVersion {
// enable UDT feature, this is an empty string.
std::string full_history_ts_low;
// An immutable snapshot of the DB's seqno to time mapping, usually shared
// between SuperVersions.
// A shared copy of the DB's seqno to time mapping.
std::shared_ptr<const SeqnoToTimeMapping> seqno_to_time_mapping{nullptr};
// should be called outside the mutex
@@ -281,9 +279,8 @@ Status CheckConcurrentWritesSupported(const ColumnFamilyOptions& cf_options);
Status CheckCFPathsSupported(const DBOptions& db_options,
const ColumnFamilyOptions& cf_options);
ColumnFamilyOptions SanitizeCfOptions(const ImmutableDBOptions& db_options,
bool read_only,
const ColumnFamilyOptions& src);
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
const ColumnFamilyOptions& src);
// Wrap user defined table properties collector factories `from cf_options`
// into internal ones in internal_tbl_prop_coll_factories. Add a system internal
// one too.
@@ -345,17 +342,17 @@ class ColumnFamilyData {
// thread-safe
const FileOptions* soptions() const;
const ImmutableOptions& ioptions() const { return ioptions_; }
const ImmutableOptions* ioptions() const { return &ioptions_; }
// REQUIRES: DB mutex held
// This returns the MutableCFOptions used by current SuperVersion
// You should use this API to reference MutableCFOptions most of the time.
const MutableCFOptions& GetCurrentMutableCFOptions() const {
return super_version_->mutable_cf_options;
const MutableCFOptions* GetCurrentMutableCFOptions() const {
return &(super_version_->mutable_cf_options);
}
// REQUIRES: DB mutex held
// This returns the latest MutableCFOptions, which may be not in effect yet.
const MutableCFOptions& GetLatestMutableCFOptions() const {
return mutable_cf_options_;
const MutableCFOptions* GetLatestMutableCFOptions() const {
return &mutable_cf_options_;
}
// REQUIRES: DB mutex held
@@ -382,20 +379,17 @@ class ColumnFamilyData {
return mem()->GetFirstSequenceNumber() == 0 && imm()->NumNotFlushed() == 0;
}
Version* current() { return current_; }
Version* dummy_versions() { return dummy_versions_; }
Version* current() { return current_; } // REQUIRE: DB mutex held
void SetCurrent(Version* _current); // REQUIRE: DB mutex held
uint64_t GetNumLiveVersions() const; // REQUIRE: DB mutex held
uint64_t GetTotalSstFilesSize() const; // REQUIRE: DB mutex held
uint64_t GetLiveSstFilesSize() const; // REQUIRE: DB mutex held
uint64_t GetTotalBlobFileSize() const; // REQUIRE: DB mutex held
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
uint64_t GetTotalBlobFileSize() const; // REQUIRE: DB mutex held
// REQUIRE: DB mutex held
void SetMemtable(MemTable* new_mem) {
AssignMemtableID(new_mem);
mem_ = new_mem;
if (ioptions_.disallow_memtable_writes) {
mem_->MarkImmutable();
}
}
void AssignMemtableID(ReadOnlyMemTable* new_imm) {
@@ -406,11 +400,10 @@ class ColumnFamilyData {
uint64_t OldestLogToKeep();
// See Memtable constructor for explanation of earliest_seq param.
// `mutable_cf_options` might need to be a saved copy if calling this without
// holding the DB mutex.
MemTable* ConstructNewMemtable(const MutableCFOptions& mutable_cf_options,
SequenceNumber earliest_seq);
void CreateNewMemtable(SequenceNumber earliest_seq);
void CreateNewMemtable(const MutableCFOptions& mutable_cf_options,
SequenceNumber earliest_seq);
TableCache* table_cache() const { return table_cache_.get(); }
BlobFileCache* blob_file_cache() const { return blob_file_cache_.get(); }
@@ -424,8 +417,7 @@ class ColumnFamilyData {
const MutableCFOptions& mutable_options,
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, LogBuffer* log_buffer,
bool require_max_output_level = false);
const SnapshotChecker* snapshot_checker, LogBuffer* log_buffer);
// Check if the passed range overlap with any running compactions.
// REQUIRES: DB mutex held
@@ -489,14 +481,15 @@ class ColumnFamilyData {
uint64_t GetSuperVersionNumber() const {
return super_version_number_.load();
}
uint64_t GetSuperVersionNumberRelaxed() const {
return super_version_number_.load(std::memory_order_relaxed);
}
// Only intended for use by DBImpl::InstallSuperVersion() and variants
// will return a pointer to SuperVersion* if previous SuperVersion
// if its reference count is zero and needs deletion or nullptr if not
// 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,
std::optional<std::shared_ptr<SeqnoToTimeMapping>>
new_seqno_to_time_mapping = {});
const MutableCFOptions& mutable_cf_options);
void InstallSuperVersion(SuperVersionContext* sv_context,
InstrumentedMutex* db_mutex);
void ResetThreadLocalSuperVersions();
@@ -538,12 +531,6 @@ class ColumnFamilyData {
assert(!ts_low.empty());
const Comparator* ucmp = user_comparator();
assert(ucmp);
// Guard against resurrected full_history_ts_low persisted in MANIFEST
// from previous DB sessions. This could happen if UDT was enabled and then
// disabled.
if (ucmp->timestamp_size() == 0) {
return;
}
if (full_history_ts_low_.empty() ||
ucmp->CompareTimestamp(ts_low, full_history_ts_low_) > 0) {
full_history_ts_low_ = std::move(ts_low);
@@ -551,11 +538,6 @@ class ColumnFamilyData {
}
const std::string& GetFullHistoryTsLow() const {
const Comparator* ucmp = user_comparator();
assert(ucmp);
if (ucmp->timestamp_size() == 0) {
assert(full_history_ts_low_.empty());
}
return full_history_ts_low_;
}
@@ -602,14 +584,16 @@ class ColumnFamilyData {
private:
friend class ColumnFamilySet;
ColumnFamilyData(
uint32_t id, const std::string& name, Version* dummy_versions,
Cache* table_cache, WriteBufferManager* write_buffer_manager,
const ColumnFamilyOptions& options, const ImmutableDBOptions& db_options,
const FileOptions* file_options, ColumnFamilySet* column_family_set,
BlockCacheTracer* const block_cache_tracer,
const std::shared_ptr<IOTracer>& io_tracer, const std::string& db_id,
const std::string& db_session_id, bool read_only);
ColumnFamilyData(uint32_t id, const std::string& name,
Version* dummy_versions, Cache* table_cache,
WriteBufferManager* write_buffer_manager,
const ColumnFamilyOptions& options,
const ImmutableDBOptions& db_options,
const FileOptions* file_options,
ColumnFamilySet* column_family_set,
BlockCacheTracer* const block_cache_tracer,
const std::shared_ptr<IOTracer>& io_tracer,
const std::string& db_id, const std::string& db_session_id);
std::vector<std::string> GetDbPaths() const;
@@ -771,8 +755,7 @@ class ColumnFamilySet {
ColumnFamilyData* CreateColumnFamily(const std::string& name, uint32_t id,
Version* dummy_version,
const ColumnFamilyOptions& options,
bool read_only);
const ColumnFamilyOptions& options);
const UnorderedMap<uint32_t, size_t>& GetRunningColumnFamiliesTimestampSize()
const {
+6 -6
View File
@@ -72,6 +72,7 @@ class ColumnFamilyTestBase : public testing::Test {
env_->skip_fsync_ = true;
dbname_ = test::PerThreadDBPath("column_family_test");
db_options_.create_if_missing = true;
db_options_.fail_if_options_file_error = true;
db_options_.env = env_;
}
@@ -270,8 +271,7 @@ class ColumnFamilyTestBase : public testing::Test {
// them.
ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
ConfigOptions(), desc.options,
SanitizeCfOptions(dbfull()->immutable_db_options(),
/*read_only*/ false, current_cf_opt)));
SanitizeOptions(dbfull()->immutable_db_options(), current_cf_opt)));
cfi++;
}
}
@@ -2175,7 +2175,7 @@ TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
ASSERT_TRUE(has_cf2_sst);
ASSERT_OK(Flush(0));
ASSERT_EQ(0, dbfull()->TEST_wals_total_size());
ASSERT_EQ(0, dbfull()->TEST_total_log_size());
Close();
}
@@ -2232,7 +2232,7 @@ TEST_P(ColumnFamilyTest, CreateMissingColumnFamilies) {
ASSERT_EQ(my_fs->options_files_created.load(), 2);
}
TEST_P(ColumnFamilyTest, SanitizeCfOptions) {
TEST_P(ColumnFamilyTest, SanitizeOptions) {
DBOptions db_options;
for (int s = kCompactionStyleLevel; s <= kCompactionStyleUniversal; ++s) {
for (int l = 0; l <= 2; l++) {
@@ -2248,8 +2248,8 @@ TEST_P(ColumnFamilyTest, SanitizeCfOptions) {
original.write_buffer_size =
l * 4 * 1024 * 1024 + i * 1024 * 1024 + j * 1024 + k;
ColumnFamilyOptions result = SanitizeCfOptions(
ImmutableDBOptions(db_options), /*read_only*/ false, original);
ColumnFamilyOptions result =
SanitizeOptions(ImmutableDBOptions(db_options), original);
ASSERT_TRUE(result.level0_stop_writes_trigger >=
result.level0_slowdown_writes_trigger);
ASSERT_TRUE(result.level0_slowdown_writes_trigger >=
+1
View File
@@ -3,6 +3,7 @@
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include <mutex>
#include <string>
#include <thread>
+78 -103
View File
@@ -284,9 +284,9 @@ Compaction::Compaction(
CompressionOptions _compression_opts, Temperature _output_temperature,
uint32_t _max_subcompactions, std::vector<FileMetaData*> _grandparents,
std::optional<SequenceNumber> _earliest_snapshot,
const SnapshotChecker* _snapshot_checker,
CompactionReason _compaction_reason, const std::string& _trim_ts,
double _score, bool l0_files_might_overlap,
const SnapshotChecker* _snapshot_checker, bool _manual_compaction,
const std::string& _trim_ts, double _score, bool _deletion_compaction,
bool l0_files_might_overlap, CompactionReason _compaction_reason,
BlobGarbageCollectionPolicy _blob_garbage_collection_policy,
double _blob_garbage_collection_age_cutoff)
: input_vstorage_(vstorage),
@@ -304,9 +304,7 @@ Compaction::Compaction(
output_compression_(_compression),
output_compression_opts_(_compression_opts),
output_temperature_(_output_temperature),
deletion_compaction_(_compaction_reason == CompactionReason::kFIFOTtl ||
_compaction_reason ==
CompactionReason::kFIFOMaxSize),
deletion_compaction_(_deletion_compaction),
l0_files_might_overlap_(l0_files_might_overlap),
inputs_(PopulateWithAtomicBoundaries(vstorage, std::move(_inputs))),
grandparents_(std::move(_grandparents)),
@@ -323,8 +321,7 @@ Compaction::Compaction(
? false
: IsBottommostLevel(output_level_, vstorage, inputs_)),
is_full_compaction_(IsFullCompaction(vstorage, inputs_)),
is_manual_compaction_(_compaction_reason ==
CompactionReason::kManualCompaction),
is_manual_compaction_(_manual_compaction),
trim_ts_(_trim_ts),
is_trivial_move_(false),
compaction_reason_(_compaction_reason),
@@ -335,23 +332,26 @@ Compaction::Compaction(
: (_blob_garbage_collection_policy ==
BlobGarbageCollectionPolicy::kDisable
? false
: mutable_cf_options().enable_blob_garbage_collection)),
: mutable_cf_options()->enable_blob_garbage_collection)),
blob_garbage_collection_age_cutoff_(
_blob_garbage_collection_age_cutoff < 0 ||
_blob_garbage_collection_age_cutoff > 1
? mutable_cf_options().blob_garbage_collection_age_cutoff
? mutable_cf_options()->blob_garbage_collection_age_cutoff
: _blob_garbage_collection_age_cutoff),
proximal_level_(
// For simplicity, we don't support the concept of "proximal level"
penultimate_level_(
// For simplicity, we don't support the concept of "penultimate level"
// with `CompactionReason::kExternalSstIngestion` and
// `CompactionReason::kRefitLevel`
_compaction_reason == CompactionReason::kExternalSstIngestion ||
_compaction_reason == CompactionReason::kRefitLevel
? Compaction::kInvalidLevel
: EvaluateProximalLevel(vstorage, mutable_cf_options_,
immutable_options_, start_level_,
output_level_)) {
: EvaluatePenultimateLevel(vstorage, mutable_cf_options_,
immutable_options_, start_level_,
output_level_)) {
MarkFilesBeingCompacted(true);
if (is_manual_compaction_) {
compaction_reason_ = CompactionReason::kManualCompaction;
}
if (max_subcompactions_ == 0) {
max_subcompactions_ = _mutable_db_options.max_subcompactions;
}
@@ -405,71 +405,53 @@ Compaction::Compaction(
}
}
PopulateProximalLevelOutputRange();
PopulatePenultimateLevelOutputRange();
}
void Compaction::PopulateProximalLevelOutputRange() {
void Compaction::PopulatePenultimateLevelOutputRange() {
if (!SupportsPerKeyPlacement()) {
assert(keep_in_last_level_through_seqno_ == kMaxSequenceNumber);
return;
}
// exclude the last level, the range of all input levels is the safe range
// of keys that can be moved up.
int exclude_level = number_levels_ - 1;
proximal_output_range_type_ = ProximalOutputRangeType::kNonLastRange;
penultimate_output_range_type_ = PenultimateOutputRangeType::kNonLastRange;
// For universal compaction, the proximal_output_range could be extended if
// all proximal level files are included in the compaction (which includes
// the case that the proximal level is empty).
// For universal compaction, the penultimate_output_range could be extended if
// all penultimate level files are included in the compaction (which includes
// the case that the penultimate level is empty).
if (immutable_options_.compaction_style == kCompactionStyleUniversal) {
exclude_level = kInvalidLevel;
proximal_output_range_type_ = ProximalOutputRangeType::kFullRange;
std::set<uint64_t> proximal_inputs;
penultimate_output_range_type_ = PenultimateOutputRangeType::kFullRange;
std::set<uint64_t> penultimate_inputs;
for (const auto& input_lvl : inputs_) {
if (input_lvl.level == proximal_level_) {
if (input_lvl.level == penultimate_level_) {
for (const auto& file : input_lvl.files) {
proximal_inputs.emplace(file->fd.GetNumber());
penultimate_inputs.emplace(file->fd.GetNumber());
}
}
}
auto proximal_files = input_vstorage_->LevelFiles(proximal_level_);
for (const auto& file : proximal_files) {
if (proximal_inputs.find(file->fd.GetNumber()) == proximal_inputs.end()) {
auto penultimate_files = input_vstorage_->LevelFiles(penultimate_level_);
for (const auto& file : penultimate_files) {
if (penultimate_inputs.find(file->fd.GetNumber()) ==
penultimate_inputs.end()) {
exclude_level = number_levels_ - 1;
proximal_output_range_type_ = ProximalOutputRangeType::kNonLastRange;
penultimate_output_range_type_ =
PenultimateOutputRangeType::kNonLastRange;
break;
}
}
}
// FIXME: should make use of `proximal_output_range_type_`.
// FIXME: should make use of `penultimate_output_range_type_`.
// FIXME: when last level's input range does not overlap with
// proximal level, and proximal level input is empty,
// this call will not set proximal_level_smallest_ or
// proximal_level_largest_. No keys will be compacted up.
GetBoundaryInternalKeys(input_vstorage_, inputs_, &proximal_level_smallest_,
&proximal_level_largest_, exclude_level);
if (proximal_output_range_type_ != ProximalOutputRangeType::kFullRange) {
// If not full range in proximal level, must keep everything already
// in the last level there, because moving it back up might cause
// overlap/placement issues that are difficult to resolve properly in the
// presence of range deletes
SequenceNumber max_last_level_seqno = 0;
for (const auto& input_lvl : inputs_) {
if (input_lvl.level == output_level_) {
for (const auto& file : input_lvl.files) {
max_last_level_seqno =
std::max(max_last_level_seqno, file->fd.largest_seqno);
}
}
}
keep_in_last_level_through_seqno_ = max_last_level_seqno;
} else {
keep_in_last_level_through_seqno_ = 0;
}
// penultimate level, and penultimate level input is empty,
// this call will not set penultimate_level_smallest_ or
// penultimate_level_largest_. No keys will be compacted up.
GetBoundaryInternalKeys(input_vstorage_, inputs_,
&penultimate_level_smallest_,
&penultimate_level_largest_, exclude_level);
}
Compaction::~Compaction() {
@@ -482,23 +464,23 @@ Compaction::~Compaction() {
}
bool Compaction::SupportsPerKeyPlacement() const {
return proximal_level_ != kInvalidLevel;
return penultimate_level_ != kInvalidLevel;
}
int Compaction::GetProximalLevel() const { return proximal_level_; }
int Compaction::GetPenultimateLevel() const { return penultimate_level_; }
// smallest_key and largest_key include timestamps if user-defined timestamp is
// enabled.
bool Compaction::OverlapProximalLevelOutputRange(
bool Compaction::OverlapPenultimateLevelOutputRange(
const Slice& smallest_key, const Slice& largest_key) const {
if (!SupportsPerKeyPlacement()) {
return false;
}
// See FIXME in Compaction::PopulateProximalLevelOutputRange().
// See FIXME in Compaction::PopulatePenultimateLevelOutputRange().
// We do not compact any key up in this case.
if (proximal_level_smallest_.size() == 0 ||
proximal_level_largest_.size() == 0) {
if (penultimate_level_smallest_.size() == 0 ||
penultimate_level_largest_.size() == 0) {
return false;
}
@@ -506,35 +488,28 @@ bool Compaction::OverlapProximalLevelOutputRange(
input_vstorage_->InternalComparator()->user_comparator();
return ucmp->CompareWithoutTimestamp(
smallest_key, proximal_level_largest_.user_key()) <= 0 &&
smallest_key, penultimate_level_largest_.user_key()) <= 0 &&
ucmp->CompareWithoutTimestamp(
largest_key, proximal_level_smallest_.user_key()) >= 0;
largest_key, penultimate_level_smallest_.user_key()) >= 0;
}
// key includes timestamp if user-defined timestamp is enabled.
void Compaction::TEST_AssertWithinProximalLevelOutputRange(
const Slice& user_key, bool expect_failure) const {
#ifdef NDEBUG
(void)user_key;
(void)expect_failure;
#else
assert(SupportsPerKeyPlacement());
bool Compaction::WithinPenultimateLevelOutputRange(
const ParsedInternalKey& ikey) const {
if (!SupportsPerKeyPlacement()) {
return false;
}
assert(proximal_level_smallest_.size() > 0);
assert(proximal_level_largest_.size() > 0);
if (penultimate_level_smallest_.size() == 0 ||
penultimate_level_largest_.size() == 0) {
return false;
}
auto* cmp = input_vstorage_->user_comparator();
const InternalKeyComparator* icmp = input_vstorage_->InternalComparator();
// op_type of a key can change during compaction, e.g. Merge -> Put.
if (!(cmp->Compare(user_key, proximal_level_smallest_.user_key()) >= 0)) {
assert(expect_failure);
} else if (!(cmp->Compare(user_key, proximal_level_largest_.user_key()) <=
0)) {
assert(expect_failure);
} else {
assert(!expect_failure);
}
#endif
return icmp->CompareKeySeq(ikey, penultimate_level_smallest_.Encode()) >= 0 &&
icmp->CompareKeySeq(ikey, penultimate_level_largest_.Encode()) <= 0;
}
bool Compaction::InputCompressionMatchesOutput() const {
@@ -588,7 +563,7 @@ bool Compaction::IsTrivialMove() const {
// input files are non overlapping
if ((mutable_cf_options_.compaction_options_universal.allow_trivial_move) &&
(output_level_ != 0) &&
(cfd_->ioptions().compaction_style == kCompactionStyleUniversal)) {
(cfd_->ioptions()->compaction_style == kCompactionStyleUniversal)) {
return is_trivial_move_;
}
@@ -646,7 +621,7 @@ bool Compaction::KeyNotExistsBeyondOutputLevel(
if (bottommost_level_) {
return true;
} else if (output_level_ != 0 &&
cfd_->ioptions().compaction_style == kCompactionStyleLevel) {
cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
// 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++) {
@@ -687,7 +662,7 @@ bool Compaction::KeyRangeNotExistsBeyondOutputLevel(
if (bottommost_level_) {
return true /* does not overlap */;
} else if (output_level_ != 0 &&
cfd_->ioptions().compaction_style == kCompactionStyleLevel) {
cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
const Comparator* user_cmp = cfd_->user_comparator();
for (int lvl = output_level_ + 1; lvl < number_levels_; lvl++) {
const std::vector<FileMetaData*>& files =
@@ -863,12 +838,12 @@ uint64_t Compaction::OutputFilePreallocationSize() const {
}
std::unique_ptr<CompactionFilter> Compaction::CreateCompactionFilter() const {
if (!cfd_->ioptions().compaction_filter_factory) {
if (!cfd_->ioptions()->compaction_filter_factory) {
return nullptr;
}
if (!cfd_->ioptions()
.compaction_filter_factory->ShouldFilterTableFileCreation(
->compaction_filter_factory->ShouldFilterTableFileCreation(
TableFileCreationReason::kCompaction)) {
return nullptr;
}
@@ -887,7 +862,7 @@ std::unique_ptr<CompactionFilter> Compaction::CreateCompactionFilter() const {
"for compaction.");
}
return cfd_->ioptions().compaction_filter_factory->CreateCompactionFilter(
return cfd_->ioptions()->compaction_filter_factory->CreateCompactionFilter(
context);
}
@@ -921,8 +896,8 @@ bool Compaction::ShouldFormSubcompactions() const {
// Round-Robin pri under leveled compaction allows subcompactions by default
// and the number of subcompactions can be larger than max_subcompactions_
if (cfd_->ioptions().compaction_pri == kRoundRobin &&
cfd_->ioptions().compaction_style == kCompactionStyleLevel) {
if (cfd_->ioptions()->compaction_pri == kRoundRobin &&
cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
return output_level_ > 0;
}
@@ -930,9 +905,9 @@ bool Compaction::ShouldFormSubcompactions() const {
return false;
}
if (cfd_->ioptions().compaction_style == kCompactionStyleLevel) {
if (cfd_->ioptions()->compaction_style == kCompactionStyleLevel) {
return (start_level_ == 0 || is_manual_compaction_) && output_level_ > 0;
} else if (cfd_->ioptions().compaction_style == kCompactionStyleUniversal) {
} else if (cfd_->ioptions()->compaction_style == kCompactionStyleUniversal) {
return number_levels_ > 1 && output_level_ > 0;
} else {
return false;
@@ -1014,7 +989,7 @@ uint64_t Compaction::MinInputFileEpochNumber() const {
return min_epoch_number;
}
int Compaction::EvaluateProximalLevel(
int Compaction::EvaluatePenultimateLevel(
const VersionStorageInfo* vstorage,
const MutableCFOptions& mutable_cf_options,
const ImmutableOptions& immutable_options, const int start_level,
@@ -1029,21 +1004,21 @@ int Compaction::EvaluateProximalLevel(
return kInvalidLevel;
}
int proximal_level = output_level - 1;
assert(proximal_level < immutable_options.num_levels);
if (proximal_level <= 0) {
int penultimate_level = output_level - 1;
assert(penultimate_level < immutable_options.num_levels);
if (penultimate_level <= 0) {
return kInvalidLevel;
}
// If the proximal level is not within input level -> output level range
// check if the proximal output level is empty, if it's empty, it could
// also be locked for the proximal output.
// If the penultimate level is not within input level -> output level range
// check if the penultimate output level is empty, if it's empty, it could
// also be locked for the penultimate output.
// TODO: ideally, it only needs to check if there's a file within the
// compaction output key range. For simplicity, it just check if there's any
// file on the proximal level.
// file on the penultimate level.
if (start_level == immutable_options.num_levels - 1 &&
(immutable_options.compaction_style != kCompactionStyleUniversal ||
!vstorage->LevelFiles(proximal_level).empty())) {
!vstorage->LevelFiles(penultimate_level).empty())) {
return kInvalidLevel;
}
@@ -1057,7 +1032,7 @@ int Compaction::EvaluateProximalLevel(
return kInvalidLevel;
}
return proximal_level;
return penultimate_level;
}
void Compaction::FilterInputsForCompactionIterator() {
+54 -73
View File
@@ -94,20 +94,21 @@ class Compaction {
std::vector<FileMetaData*> grandparents,
std::optional<SequenceNumber> earliest_snapshot,
const SnapshotChecker* snapshot_checker,
CompactionReason compaction_reason,
const std::string& trim_ts = "", double score = -1,
bool manual_compaction = false, const std::string& trim_ts = "",
double score = -1, bool deletion_compaction = false,
bool l0_files_might_overlap = true,
CompactionReason compaction_reason = CompactionReason::kUnknown,
BlobGarbageCollectionPolicy blob_garbage_collection_policy =
BlobGarbageCollectionPolicy::kUseDefault,
double blob_garbage_collection_age_cutoff = -1);
// The type of the proximal level output range
enum class ProximalOutputRangeType : int {
kNotSupported, // it cannot output to the proximal level
kFullRange, // any data could be output to the proximal level
// The type of the penultimate level output range
enum class PenultimateOutputRangeType : int {
kNotSupported, // it cannot output to the penultimate level
kFullRange, // any data could be output to the penultimate level
kNonLastRange, // only the keys within non_last_level compaction inputs can
// be outputted to the proximal level
kDisabled, // no data can be outputted to the proximal level
// be outputted to the penultimate level
kDisabled, // no data can be outputted to the penultimate level
};
// No copying allowed
@@ -282,26 +283,19 @@ class Compaction {
// are non-overlapping and can be trivially moved.
bool is_trivial_move() const { return is_trivial_move_; }
bool is_trivial_copy_compaction() const {
return immutable_options_.compaction_style == kCompactionStyleFIFO &&
compaction_reason_ == CompactionReason::kChangeTemperature &&
mutable_cf_options_.compaction_options_fifo
.allow_trivial_copy_when_change_temperature;
}
// How many total levels are there?
int number_levels() const { return number_levels_; }
// Return the ImmutableOptions that should be used throughout the compaction
// procedure
const ImmutableOptions& immutable_options() const {
return immutable_options_;
const ImmutableOptions* immutable_options() const {
return &immutable_options_;
}
// Return the MutableCFOptions that should be used throughout the compaction
// procedure
const MutableCFOptions& mutable_cf_options() const {
return mutable_cf_options_;
const MutableCFOptions* mutable_cf_options() const {
return &mutable_cf_options_;
}
// Returns the size in bytes that the output file should be preallocated to.
@@ -376,30 +370,30 @@ class Compaction {
Slice GetLargestUserKey() const { return largest_user_key_; }
ProximalOutputRangeType GetProximalOutputRangeType() const {
return proximal_output_range_type_;
PenultimateOutputRangeType GetPenultimateOutputRangeType() const {
return penultimate_output_range_type_;
}
// Return true if the compaction supports per_key_placement
bool SupportsPerKeyPlacement() const;
// Get per_key_placement proximal output level, which is `last_level - 1`
// Get per_key_placement penultimate output level, which is `last_level - 1`
// if per_key_placement feature is supported. Otherwise, return -1.
int GetProximalLevel() const;
int GetPenultimateLevel() const;
// Return true if the given range is overlap with proximal level output
// Return true if the given range is overlap with penultimate level output
// range.
// Both smallest_key and largest_key include timestamps if user-defined
// timestamp is enabled.
bool OverlapProximalLevelOutputRange(const Slice& smallest_key,
const Slice& largest_key) const;
bool OverlapPenultimateLevelOutputRange(const Slice& smallest_key,
const Slice& largest_key) const;
// For testing purposes, check that a key is within proximal level
// output range for per_key_placement feature, which is safe to place the key
// to the proximal level. Different compaction strategies have different
// rules. `user_key` includes timestamp if user-defined timestamp is enabled.
void TEST_AssertWithinProximalLevelOutputRange(
const Slice& user_key, bool expect_failure = false) const;
// Return true if the key is within penultimate level output range for
// per_key_placement feature, which is safe to place the key to the
// penultimate level. different compaction strategy has different rules.
// If per_key_placement is not supported, always return false.
// key includes timestamp if user-defined timestamp is enabled.
bool WithinPenultimateLevelOutputRange(const ParsedInternalKey& ikey) const;
CompactionReason compaction_reason() const { return compaction_reason_; }
@@ -447,37 +441,26 @@ class Compaction {
static constexpr int kInvalidLevel = -1;
// Evaluate proximal output level. If the compaction supports
// per_key_placement feature, it returns the proximal level number.
// Evaluate penultimate output level. If the compaction supports
// per_key_placement feature, it returns the penultimate level number.
// Otherwise, it's set to kInvalidLevel (-1), which means
// output_to_proximal_level is not supported.
// Note: even the proximal level output is supported (ProximalLevel !=
// output_to_penultimate_level is not supported.
// Note: even the penultimate level output is supported (PenultimateLevel !=
// kInvalidLevel), some key range maybe unsafe to be outputted to the
// proximal level. The safe key range is populated by
// `PopulateProximalLevelOutputRange()`.
// Which could potentially disable all proximal level output.
static int EvaluateProximalLevel(const VersionStorageInfo* vstorage,
const MutableCFOptions& mutable_cf_options,
const ImmutableOptions& immutable_options,
const int start_level,
const int output_level);
static bool OutputToNonZeroMaxOutputLevel(int output_level,
int max_output_level) {
return output_level > 0 && output_level == max_output_level;
}
// If some data cannot be safely migrated "up" the LSM tree due to a change
// in the preclude_last_level_data_seconds setting, this indicates a sequence
// number for the newest data that must be kept in the last level.
SequenceNumber GetKeepInLastLevelThroughSeqno() const {
return keep_in_last_level_through_seqno_;
}
// penultimate level. The safe key range is populated by
// `PopulatePenultimateLevelOutputRange()`.
// Which could potentially disable all penultimate level output.
static int EvaluatePenultimateLevel(
const VersionStorageInfo* vstorage,
const MutableCFOptions& mutable_cf_options,
const ImmutableOptions& immutable_options, const int start_level,
const int output_level);
// mark (or clear) all files that are being compacted
void MarkFilesBeingCompacted(bool being_compacted) const;
private:
Status InitInputTableProperties();
// get the smallest and largest key present in files to be compacted
@@ -493,10 +476,10 @@ class Compaction {
InternalKey* smallest_key, InternalKey* largest_key,
int exclude_level = -1);
// populate proximal level output range, which will be used to determine if
// a key is safe to output to the proximal level (details see
// `Compaction::WithinProximalLevelOutputRange()`.
void PopulateProximalLevelOutputRange();
// populate penultimate level output range, which will be used to determine if
// a key is safe to output to the penultimate level (details see
// `Compaction::WithinPenultimateLevelOutputRange()`.
void PopulatePenultimateLevelOutputRange();
// If oldest snapshot is specified at Compaction construction time, we have
// an opportunity to optimize inputs for compaction iterator for this case:
@@ -623,24 +606,22 @@ class Compaction {
// Blob garbage collection age cutoff.
double blob_garbage_collection_age_cutoff_;
SequenceNumber keep_in_last_level_through_seqno_ = kMaxSequenceNumber;
// only set when per_key_placement feature is enabled, -1 (kInvalidLevel)
// means not supported.
const int proximal_level_;
const int penultimate_level_;
// Key range for proximal level output
// Key range for penultimate level output
// includes timestamp if user-defined timestamp is enabled.
// proximal_output_range_type_ shows the range type
InternalKey proximal_level_smallest_;
InternalKey proximal_level_largest_;
ProximalOutputRangeType proximal_output_range_type_ =
ProximalOutputRangeType::kNotSupported;
// penultimate_output_range_type_ shows the range type
InternalKey penultimate_level_smallest_;
InternalKey penultimate_level_largest_;
PenultimateOutputRangeType penultimate_output_range_type_ =
PenultimateOutputRangeType::kNotSupported;
};
#ifndef NDEBUG
// Helper struct only for tests, which contains the data to decide if a key
// should be output to the proximal level.
// should be output to the penultimate level.
// TODO: remove this when the public feature knob is available
struct PerKeyPlacementContext {
const int level;
@@ -648,16 +629,16 @@ struct PerKeyPlacementContext {
const Slice value;
const SequenceNumber seq_num;
bool& output_to_proximal_level;
bool& output_to_penultimate_level;
PerKeyPlacementContext(int _level, Slice _key, Slice _value,
SequenceNumber _seq_num,
bool& _output_to_proximal_level)
bool& _output_to_penultimate_level)
: level(_level),
key(_key),
value(_value),
seq_num(_seq_num),
output_to_proximal_level(_output_to_proximal_level) {}
output_to_penultimate_level(_output_to_penultimate_level) {}
};
#endif /* !NDEBUG */
+86 -7
View File
@@ -38,16 +38,19 @@ CompactionIterator::CompactionIterator(
const std::atomic<bool>* shutting_down,
const std::shared_ptr<Logger> info_log,
const std::string* full_history_ts_low,
std::optional<SequenceNumber> preserve_seqno_min)
const SequenceNumber preserve_time_min_seqno,
const SequenceNumber preclude_last_level_min_seqno)
: CompactionIterator(
input, cmp, merge_helper, last_sequence, snapshots, earliest_snapshot,
earliest_write_conflict_snapshot, job_snapshot, snapshot_checker, env,
report_detailed_time, expect_valid_internal_key, range_del_agg,
blob_file_builder, allow_data_in_errors, enforce_single_del_contracts,
manual_compaction_canceled,
compaction ? std::make_unique<RealCompaction>(compaction) : nullptr,
std::unique_ptr<CompactionProxy>(
compaction ? new RealCompaction(compaction) : nullptr),
must_count_input_entries, compaction_filter, shutting_down, info_log,
full_history_ts_low, preserve_seqno_min) {}
full_history_ts_low, preserve_time_min_seqno,
preclude_last_level_min_seqno) {}
CompactionIterator::CompactionIterator(
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
@@ -65,7 +68,8 @@ CompactionIterator::CompactionIterator(
const std::atomic<bool>* shutting_down,
const std::shared_ptr<Logger> info_log,
const std::string* full_history_ts_low,
std::optional<SequenceNumber> preserve_seqno_min)
const SequenceNumber preserve_time_min_seqno,
const SequenceNumber preclude_last_level_min_seqno)
: input_(input, cmp, must_count_input_entries),
cmp_(cmp),
merge_helper_(merge_helper),
@@ -106,9 +110,10 @@ CompactionIterator::CompactionIterator(
current_key_committed_(false),
cmp_with_history_ts_low_(0),
level_(compaction_ == nullptr ? 0 : compaction_->level()),
preserve_seqno_after_(preserve_seqno_min.value_or(earliest_snapshot)) {
preserve_time_min_seqno_(preserve_time_min_seqno),
preclude_last_level_min_seqno_(preclude_last_level_min_seqno) {
assert(snapshots_ != nullptr);
assert(preserve_seqno_after_ <= earliest_snapshot_);
assert(preserve_time_min_seqno_ <= preclude_last_level_min_seqno_);
if (compaction_ != nullptr) {
level_ptrs_ = std::vector<size_t>(compaction_->number_levels(), 0);
@@ -1013,6 +1018,7 @@ void CompactionIterator::NextFromInput() {
} else {
if (ikey_.sequence != 0) {
iter_stats_.num_timed_put_swap_preferred_seqno++;
saved_seq_for_penul_check_ = ikey_.sequence;
ikey_.sequence = preferred_seqno;
}
ikey_.type = kTypeValue;
@@ -1253,6 +1259,71 @@ void CompactionIterator::GarbageCollectBlobIfNeeded() {
}
}
void CompactionIterator::DecideOutputLevel() {
assert(compaction_->SupportsPerKeyPlacement());
output_to_penultimate_level_ = false;
// if the key is newer than the cutoff sequence or within the earliest
// snapshot, it should output to the penultimate level.
if (ikey_.sequence > preclude_last_level_min_seqno_ ||
ikey_.sequence > earliest_snapshot_) {
output_to_penultimate_level_ = true;
}
#ifndef NDEBUG
// Could be overridden by unittest
PerKeyPlacementContext context(level_, ikey_.user_key, value_, ikey_.sequence,
output_to_penultimate_level_);
TEST_SYNC_POINT_CALLBACK("CompactionIterator::PrepareOutput.context",
&context);
if (ikey_.sequence > earliest_snapshot_) {
output_to_penultimate_level_ = true;
}
#endif // NDEBUG
// saved_seq_for_penul_check_ is populated in `NextFromInput` when the
// entry's sequence number is non zero and validity context for output this
// entry is kSwapPreferredSeqno for use in `DecideOutputLevel`. It should be
// cleared out here unconditionally. Otherwise, it may end up getting consumed
// incorrectly by a different entry.
SequenceNumber seq_for_range_check =
(saved_seq_for_penul_check_.has_value() &&
saved_seq_for_penul_check_.value() != kMaxSequenceNumber)
? saved_seq_for_penul_check_.value()
: ikey_.sequence;
saved_seq_for_penul_check_ = std::nullopt;
ParsedInternalKey ikey_for_range_check = ikey_;
if (seq_for_range_check != ikey_.sequence) {
ikey_for_range_check.sequence = seq_for_range_check;
}
if (output_to_penultimate_level_) {
// If it's decided to output to the penultimate level, but unsafe to do so,
// still output to the last level. For example, moving the data from a lower
// level to a higher level outside of the higher-level input key range is
// considered unsafe, because the key may conflict with higher-level SSTs
// not from this compaction.
// TODO: add statistic for declined output_to_penultimate_level
bool safe_to_penultimate_level =
compaction_->WithinPenultimateLevelOutputRange(ikey_for_range_check);
if (!safe_to_penultimate_level) {
output_to_penultimate_level_ = false;
// It could happen when disable/enable `last_level_temperature` while
// holding a snapshot. When `last_level_temperature` is not set
// (==kUnknown), the data newer than any snapshot is pushed to the last
// level, but when the per_key_placement feature is enabled on the fly,
// the data later than the snapshot has to be moved to the penultimate
// level, which may or may not be safe. So the user needs to make sure all
// snapshot is released before enabling `last_level_temperature` feature
// We will migrate the feature to `last_level_temperature` and maybe make
// it not dynamically changeable.
if (seq_for_range_check > earliest_snapshot_) {
status_ = Status::Corruption(
"Unsafe to store Seq later than snapshot in the last level if "
"per_key_placement is enabled");
}
}
}
}
void CompactionIterator::PrepareOutput() {
if (Valid()) {
if (LIKELY(!is_range_del_)) {
@@ -1261,6 +1332,13 @@ void CompactionIterator::PrepareOutput() {
} else if (ikey_.type == kTypeBlobIndex) {
GarbageCollectBlobIfNeeded();
}
// For range del sentinel, we don't use it to cut files for bottommost
// compaction. So it should not make a difference which output level we
// decide.
if (compaction_ != nullptr && compaction_->SupportsPerKeyPlacement()) {
DecideOutputLevel();
}
}
// Zeroing out the sequence number leads to better compression.
@@ -1278,7 +1356,8 @@ void CompactionIterator::PrepareOutput() {
!compaction_->allow_ingest_behind() && bottommost_level_ &&
DefinitelyInSnapshot(ikey_.sequence, earliest_snapshot_) &&
ikey_.type != kTypeMerge && current_key_committed_ &&
ikey_.sequence <= preserve_seqno_after_ && !is_range_del_) {
!output_to_penultimate_level_ &&
ikey_.sequence < preserve_time_min_seqno_ && !is_range_del_) {
if (ikey_.type == kTypeDeletion ||
(ikey_.type == kTypeSingleDeletion && timestamp_size_ == 0)) {
ROCKS_LOG_FATAL(
+68 -26
View File
@@ -117,6 +117,10 @@ class CompactionIterator {
virtual const Compaction* real_compaction() const = 0;
virtual bool SupportsPerKeyPlacement() const = 0;
// `key` includes timestamp if user-defined timestamp is enabled.
virtual bool WithinPenultimateLevelOutputRange(
const ParsedInternalKey&) const = 0;
};
class RealCompaction : public CompactionProxy {
@@ -124,6 +128,8 @@ class CompactionIterator {
explicit RealCompaction(const Compaction* compaction)
: compaction_(compaction) {
assert(compaction_);
assert(compaction_->immutable_options());
assert(compaction_->mutable_cf_options());
}
int level() const override { return compaction_->level(); }
@@ -145,11 +151,11 @@ class CompactionIterator {
}
bool allow_ingest_behind() const override {
return compaction_->immutable_options().allow_ingest_behind;
return compaction_->immutable_options()->allow_ingest_behind;
}
bool allow_mmap_reads() const override {
return compaction_->immutable_options().allow_mmap_reads;
return compaction_->immutable_options()->allow_mmap_reads;
}
bool enable_blob_garbage_collection() const override {
@@ -161,7 +167,7 @@ class CompactionIterator {
}
uint64_t blob_compaction_readahead_size() const override {
return compaction_->mutable_cf_options().blob_compaction_readahead_size;
return compaction_->mutable_cf_options()->blob_compaction_readahead_size;
}
const Version* input_version() const override {
@@ -178,6 +184,14 @@ class CompactionIterator {
return compaction_->SupportsPerKeyPlacement();
}
// Check if key is within penultimate level output range, to see if it's
// safe to output to the penultimate level for per_key_placement feature.
// `key` includes timestamp if user-defined timestamp is enabled.
bool WithinPenultimateLevelOutputRange(
const ParsedInternalKey& ikey) const override {
return compaction_->WithinPenultimateLevelOutputRange(ikey);
}
private:
const Compaction* compaction_;
};
@@ -202,29 +216,29 @@ class CompactionIterator {
const std::atomic<bool>* shutting_down = nullptr,
const std::shared_ptr<Logger> info_log = nullptr,
const std::string* full_history_ts_low = nullptr,
std::optional<SequenceNumber> preserve_seqno_min = {});
const SequenceNumber preserve_time_min_seqno = kMaxSequenceNumber,
const SequenceNumber preclude_last_level_min_seqno = kMaxSequenceNumber);
// 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_snapshot,
SequenceNumber earliest_write_conflict_snapshot,
SequenceNumber job_snapshot,
const SnapshotChecker* snapshot_checker, Env* env,
bool report_detailed_time, bool expect_valid_internal_key,
CompactionRangeDelAggregator* range_del_agg,
BlobFileBuilder* blob_file_builder,
bool allow_data_in_errors,
bool enforce_single_del_contracts,
const std::atomic<bool>& manual_compaction_canceled,
std::unique_ptr<CompactionProxy> compaction,
bool must_count_input_entries,
const CompactionFilter* compaction_filter = nullptr,
const std::atomic<bool>* shutting_down = nullptr,
const std::shared_ptr<Logger> info_log = nullptr,
const std::string* full_history_ts_low = nullptr,
std::optional<SequenceNumber> preserve_seqno_min = {});
CompactionIterator(
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
SequenceNumber last_sequence, std::vector<SequenceNumber>* snapshots,
SequenceNumber earliest_snapshot,
SequenceNumber earliest_write_conflict_snapshot,
SequenceNumber job_snapshot, const SnapshotChecker* snapshot_checker,
Env* env, bool report_detailed_time, bool expect_valid_internal_key,
CompactionRangeDelAggregator* range_del_agg,
BlobFileBuilder* blob_file_builder, bool allow_data_in_errors,
bool enforce_single_del_contracts,
const std::atomic<bool>& manual_compaction_canceled,
std::unique_ptr<CompactionProxy> compaction,
bool must_count_input_entries,
const CompactionFilter* compaction_filter = nullptr,
const std::atomic<bool>* shutting_down = nullptr,
const std::shared_ptr<Logger> info_log = nullptr,
const std::string* full_history_ts_low = nullptr,
const SequenceNumber preserve_time_min_seqno = kMaxSequenceNumber,
const SequenceNumber preclude_last_level_min_seqno = kMaxSequenceNumber);
~CompactionIterator();
@@ -255,6 +269,11 @@ class CompactionIterator {
const CompactionIterationStats& iter_stats() const { return iter_stats_; }
bool HasNumInputEntryScanned() const { return input_.HasNumItered(); }
uint64_t NumInputEntryScanned() const { return input_.NumItered(); }
// If the current key should be placed on penultimate level, only valid if
// per_key_placement is supported
bool output_to_penultimate_level() const {
return output_to_penultimate_level_;
}
Status InputStatus() const { return input_.status(); }
bool IsDeleteRangeSentinelKey() const { return is_range_del_; }
@@ -266,6 +285,10 @@ class CompactionIterator {
// Do final preparations before presenting the output to the callee.
void PrepareOutput();
// Decide the current key should be output to the last level or penultimate
// level, only call for compaction supports per key placement
void DecideOutputLevel();
// Passes the output value to the blob file builder (if any), and replaces it
// with the corresponding blob reference if it has been actually written to a
// blob file (i.e. if it passed the value size check). Returns true if the
@@ -417,6 +440,16 @@ class CompactionIterator {
// NextFromInput()).
ParsedInternalKey ikey_;
// When a kTypeValuePreferredSeqno entry's preferred seqno is safely swapped
// in in this compaction, this field saves its original sequence number for
// range checking whether it's safe to be placed on the penultimate level.
// This is to ensure when such an entry happens to be the right boundary of
// penultimate safe range, it won't get excluded because with the preferred
// seqno swapped in, it's now larger than the right boundary (itself before
// the swap). This is safe to do, because preferred seqno is swapped in only
// when no entries with the same user key exist on lower levels and this entry
// is already visible in the earliest snapshot.
std::optional<SequenceNumber> saved_seq_for_penul_check_ = kMaxSequenceNumber;
// Stores whether ikey_.user_key is valid. If set to false, the user key is
// not compared against the current key in the underlying iterator.
bool has_current_user_key_ = false;
@@ -474,8 +507,17 @@ class CompactionIterator {
// just been zeroed out during bottommost compaction.
bool last_key_seq_zeroed_{false};
// Max seqno that can be zeroed out at last level (various reasons)
const SequenceNumber preserve_seqno_after_ = kMaxSequenceNumber;
// True if the current key should be output to the penultimate level if
// possible, compaction logic makes the final decision on which level to
// output to.
bool output_to_penultimate_level_{false};
// min seqno for preserving the time information.
const SequenceNumber preserve_time_min_seqno_ = kMaxSequenceNumber;
// min seqno to preclude the data from the last level, if the key seqno larger
// than this, it will be output to penultimate level
const SequenceNumber preclude_last_level_min_seqno_ = kMaxSequenceNumber;
void AdvanceInputIter() { input_.Next(); }
+122
View File
@@ -192,6 +192,11 @@ class FakeCompaction : public CompactionIterator::CompactionProxy {
return supports_per_key_placement;
}
bool WithinPenultimateLevelOutputRange(
const ParsedInternalKey& key) const override {
return (!key.user_key.starts_with("unsafe_pb"));
}
bool key_not_exists_beyond_output_level = false;
bool is_bottommost_level = false;
@@ -839,6 +844,123 @@ TEST_P(CompactionIteratorTest, ZeroSeqOfKeyAndSnapshot) {
INSTANTIATE_TEST_CASE_P(CompactionIteratorTestInstance, CompactionIteratorTest,
testing::Values(true, false));
class PerKeyPlacementCompIteratorTest : public CompactionIteratorTest {
public:
bool SupportsPerKeyPlacement() const override { return true; }
};
TEST_P(PerKeyPlacementCompIteratorTest, SplitLastLevelData) {
std::atomic_uint64_t latest_cold_seq = 0;
SyncPoint::GetInstance()->SetCallBack(
"CompactionIterator::PrepareOutput.context", [&](void* arg) {
auto context = static_cast<PerKeyPlacementContext*>(arg);
context->output_to_penultimate_level =
context->seq_num > latest_cold_seq;
});
SyncPoint::GetInstance()->EnableProcessing();
latest_cold_seq = 5;
InitIterators(
{test::KeyStr("a", 7, kTypeValue), test::KeyStr("b", 6, kTypeValue),
test::KeyStr("c", 5, kTypeValue)},
{"vala", "valb", "valc"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
nullptr, nullptr, true);
c_iter_->SeekToFirst();
ASSERT_TRUE(c_iter_->Valid());
// the first 2 keys are hot, which should has
// `output_to_penultimate_level()==true` and seq num not zeroed out
ASSERT_EQ(test::KeyStr("a", 7, kTypeValue), c_iter_->key().ToString());
ASSERT_TRUE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_TRUE(c_iter_->Valid());
ASSERT_EQ(test::KeyStr("b", 6, kTypeValue), c_iter_->key().ToString());
ASSERT_TRUE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_TRUE(c_iter_->Valid());
// `a` is cold data, which should be output to bottommost
ASSERT_EQ(test::KeyStr("c", 0, kTypeValue), c_iter_->key().ToString());
ASSERT_FALSE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_OK(c_iter_->status());
ASSERT_FALSE(c_iter_->Valid());
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_P(PerKeyPlacementCompIteratorTest, SnapshotData) {
AddSnapshot(5);
InitIterators(
{test::KeyStr("a", 7, kTypeValue), test::KeyStr("b", 6, kTypeDeletion),
test::KeyStr("b", 5, kTypeValue)},
{"vala", "", "valb"}, {}, {}, kMaxSequenceNumber, kMaxSequenceNumber,
nullptr, nullptr, true);
c_iter_->SeekToFirst();
ASSERT_TRUE(c_iter_->Valid());
// The first key and the tombstone are within snapshot, which should output
// to the penultimate level (and seq num cannot be zeroed out).
ASSERT_EQ(test::KeyStr("a", 7, kTypeValue), c_iter_->key().ToString());
ASSERT_TRUE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_TRUE(c_iter_->Valid());
ASSERT_EQ(test::KeyStr("b", 6, kTypeDeletion), c_iter_->key().ToString());
ASSERT_TRUE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_TRUE(c_iter_->Valid());
// `a` is not protected by the snapshot, the sequence number is zero out and
// should output bottommost
ASSERT_EQ(test::KeyStr("b", 0, kTypeValue), c_iter_->key().ToString());
ASSERT_FALSE(c_iter_->output_to_penultimate_level());
c_iter_->Next();
ASSERT_OK(c_iter_->status());
ASSERT_FALSE(c_iter_->Valid());
}
TEST_P(PerKeyPlacementCompIteratorTest, ConflictWithSnapshot) {
std::atomic_uint64_t latest_cold_seq = 0;
SyncPoint::GetInstance()->SetCallBack(
"CompactionIterator::PrepareOutput.context", [&](void* arg) {
auto context = static_cast<PerKeyPlacementContext*>(arg);
context->output_to_penultimate_level =
context->seq_num > latest_cold_seq;
});
SyncPoint::GetInstance()->EnableProcessing();
latest_cold_seq = 6;
AddSnapshot(5);
InitIterators({test::KeyStr("a", 7, kTypeValue),
test::KeyStr("unsafe_pb", 6, kTypeValue),
test::KeyStr("c", 5, kTypeValue)},
{"vala", "valb", "valc"}, {}, {}, kMaxSequenceNumber,
kMaxSequenceNumber, nullptr, nullptr, true);
c_iter_->SeekToFirst();
ASSERT_TRUE(c_iter_->Valid());
ASSERT_EQ(test::KeyStr("a", 7, kTypeValue), c_iter_->key().ToString());
ASSERT_TRUE(c_iter_->output_to_penultimate_level());
// the 2nd key is unsafe to output_to_penultimate_level, but it's within
// snapshot so for per_key_placement feature it has to be outputted to the
// penultimate level. which is a corruption. We should never see
// such case as the data with seq num (within snapshot) should always come
// from higher compaction input level, which makes it safe to
// output_to_penultimate_level.
c_iter_->Next();
ASSERT_TRUE(c_iter_->status().IsCorruption());
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
}
INSTANTIATE_TEST_CASE_P(PerKeyPlacementCompIteratorTest,
PerKeyPlacementCompIteratorTest,
testing::Values(true, false));
// Tests how CompactionIterator work together with SnapshotChecker.
class CompactionIteratorWithSnapshotCheckerTest
: public CompactionIteratorTest {
File diff suppressed because it is too large. Load diff
+92 -117
View File
@@ -67,7 +67,7 @@ class SubcompactionState;
// if needed.
//
// CompactionJob has 2 main stats:
// 1. CompactionJobStats job_stats_
// 1. CompactionJobStats compaction_job_stats_
// CompactionJobStats is a public data structure which is part of Compaction
// event listener that rocksdb share the job stats with the user.
// Internally it's an aggregation of all the compaction_job_stats from each
@@ -81,7 +81,7 @@ class SubcompactionState;
// +------------------------+ |
// | CompactionJob | | +------------------------+
// | | | | SubcompactionState |
// | job_stats +-----+ | |
// | compaction_job_stats +-----+ | |
// | | +--------->| compaction_job_stats |
// | | | | |
// +------------------------+ | +------------------------+
@@ -98,13 +98,16 @@ class SubcompactionState;
// +--------->+ |
// +------------------------+
//
// 2. CompactionStatsFull internal_stats_
// 2. CompactionStatsFull compaction_stats_
// `CompactionStatsFull` is an internal stats about the compaction, which
// is eventually sent to `ColumnFamilyData::internal_stats_` and used for
// logging and public metrics.
// Internally, it's an aggregation of stats_ from each `SubcompactionState`.
// It has 2 parts, ordinary output level stats and the proximal level output
// stats.
// It has 2 parts, normal stats about the main compaction information and
// the penultimate level output stats.
// `SubcompactionState` maintains the CompactionOutputs for normal output and
// the penultimate level output if exists, the per_level stats is
// stored with the outputs.
// +---------------------------+
// | SubcompactionState |
// | |
@@ -116,15 +119,15 @@ class SubcompactionState;
// | | |
// | | +----------------------+ |
// +--------------------------------+ | | | CompactionOutputs | |
// | CompactionJob | | | | (proximal_level) | |
// | CompactionJob | | | | (penultimate_level) | |
// | | +--------->| stats_ | |
// | internal_stats_ | | | | +----------------------+ |
// | compaction_stats_ | | | | +----------------------+ |
// | +-------------------------+ | | | | |
// | |output_level_stats |------|----+ +---------------------------+
// | |stats (normal) |------|----+ +---------------------------+
// | +-------------------------+ | | |
// | | | |
// | +-------------------------+ | | | +---------------------------+
// | |proximal_level_stats |------+ | | SubcompactionState |
// | |penultimate_level_stats +------+ | | SubcompactionState |
// | +-------------------------+ | | | | |
// | | | | | +----------------------+ |
// | | | | | | CompactionOutputs | |
@@ -134,7 +137,7 @@ class SubcompactionState;
// | | |
// | | +----------------------+ |
// | | | CompactionOutputs | |
// | | | (proximal_level) | |
// | | | (penultimate_level) | |
// +--------->| stats_ | |
// | +----------------------+ |
// | |
@@ -142,27 +145,27 @@ class SubcompactionState;
class CompactionJob {
public:
CompactionJob(int job_id, Compaction* compaction,
const ImmutableDBOptions& db_options,
const MutableDBOptions& mutable_db_options,
const FileOptions& file_options, VersionSet* versions,
const std::atomic<bool>* shutting_down, LogBuffer* log_buffer,
FSDirectory* db_directory, FSDirectory* output_directory,
FSDirectory* blob_output_directory, Statistics* stats,
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
JobContext* job_context, 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,
Env::Priority thread_pri,
const std::shared_ptr<IOTracer>& io_tracer,
const std::atomic<bool>& manual_compaction_canceled,
const std::string& db_id = "",
const std::string& db_session_id = "",
std::string full_history_ts_low = "", std::string trim_ts = "",
BlobFileCompletionCallback* blob_callback = nullptr,
int* bg_compaction_scheduled = nullptr,
int* bg_bottom_compaction_scheduled = nullptr);
CompactionJob(
int job_id, Compaction* compaction, const ImmutableDBOptions& db_options,
const MutableDBOptions& mutable_db_options,
const FileOptions& file_options, VersionSet* versions,
const std::atomic<bool>* shutting_down, LogBuffer* log_buffer,
FSDirectory* db_directory, FSDirectory* output_directory,
FSDirectory* blob_output_directory, Statistics* stats,
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
std::vector<SequenceNumber> existing_snapshots,
SequenceNumber earliest_write_conflict_snapshot,
const SnapshotChecker* snapshot_checker, JobContext* job_context,
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,
Env::Priority thread_pri, const std::shared_ptr<IOTracer>& io_tracer,
const std::atomic<bool>& manual_compaction_canceled,
const std::string& db_id = "", const std::string& db_session_id = "",
std::string full_history_ts_low = "", std::string trim_ts = "",
BlobFileCompletionCallback* blob_callback = nullptr,
int* bg_compaction_scheduled = nullptr,
int* bg_bottom_compaction_scheduled = nullptr);
virtual ~CompactionJob();
@@ -173,13 +176,7 @@ class CompactionJob {
// REQUIRED: mutex held
// Prepare for the compaction by setting up boundaries for each subcompaction
// and organizing seqno <-> time info. `known_single_subcompact` is non-null
// if we already have a known single subcompaction, with optional key bounds
// (currently for executing a remote compaction).
void Prepare(
std::optional<std::pair<std::optional<Slice>, std::optional<Slice>>>
known_single_subcompact);
void Prepare();
// REQUIRED mutex not held
// Launch threads for each subcompaction and wait for them to finish. After
// that, verify table is usable and finally do bookkeeping to unify
@@ -190,15 +187,30 @@ class CompactionJob {
// Add compaction input/output to the current version
// Releases compaction file through Compaction::ReleaseCompactionFiles().
// Sets *compaction_released to true if compaction is released.
Status Install(bool* compaction_released);
Status Install(const MutableCFOptions& mutable_cf_options,
bool* compaction_released);
// Return the IO status
IOStatus io_status() const { return io_status_; }
protected:
void UpdateCompactionJobOutputStats(
const InternalStats::CompactionStatsFull& internal_stats) const;
// Update the following stats in compaction_stats_.stats
// - num_input_files_in_non_output_levels
// - num_input_files_in_output_level
// - bytes_read_non_output_levels
// - bytes_read_output_level
// - num_input_records
// - bytes_read_blob
// - num_dropped_records
//
// @param num_input_range_del if non-null, will be set to the number of range
// deletion entries in this compaction input.
//
// Returns true iff compaction_stats_.stats.num_input_records and
// num_input_range_del are calculated successfully.
bool UpdateCompactionStats(uint64_t* num_input_range_del = nullptr);
virtual void UpdateCompactionJobStats(
const InternalStats::CompactionStats& stats) const;
void LogCompaction();
virtual void RecordCompactionIOStats();
void CleanupCompaction();
@@ -207,7 +219,7 @@ class CompactionJob {
void ProcessKeyValueCompaction(SubcompactionState* sub_compact);
CompactionState* compact_;
InternalStats::CompactionStatsFull internal_stats_;
InternalStats::CompactionStatsFull compaction_stats_;
const ImmutableDBOptions& db_options_;
const MutableDBOptions mutable_db_options_copy_;
LogBuffer* log_buffer_;
@@ -220,37 +232,11 @@ class CompactionJob {
IOStatus io_status_;
CompactionJobStats* job_stats_;
CompactionJobStats* compaction_job_stats_;
private:
friend class CompactionJobTestBase;
// Collect the following stats from Input Table Properties
// - num_input_files_in_non_output_levels
// - num_input_files_in_output_level
// - bytes_read_non_output_levels
// - bytes_read_output_level
// - num_input_records
// - bytes_read_blob
// - num_dropped_records
// and set them in internal_stats_.output_level_stats
//
// @param num_input_range_del if non-null, will be set to the number of range
// deletion entries in this compaction input.
//
// Returns true iff internal_stats_.output_level_stats.num_input_records and
// num_input_range_del are calculated successfully.
//
// This should be called only once for compactions (not per subcompaction)
bool BuildStatsFromInputTableProperties(
uint64_t* num_input_range_del = nullptr);
void UpdateCompactionJobInputStats(
const InternalStats::CompactionStatsFull& internal_stats,
uint64_t num_input_range_del) const;
Status VerifyInputRecordCount(uint64_t num_input_range_del) const;
// Generates a histogram representing potential divisions of key ranges from
// the input. It adds the starting and/or ending keys of certain input files
// to the working set and then finds the approximate size of data in between
@@ -290,7 +276,8 @@ class CompactionJob {
const Slice& next_table_min_key,
const Slice* comp_start_user_key,
const Slice* comp_end_user_key);
Status InstallCompactionResults(bool* compaction_released);
Status InstallCompactionResults(const MutableCFOptions& mutable_cf_options,
bool* compaction_released);
Status OpenCompactionOutputFile(SubcompactionState* sub_compact,
CompactionOutputs& outputs);
@@ -321,8 +308,21 @@ class CompactionJob {
FSDirectory* blob_output_directory_;
InstrumentedMutex* db_mutex_;
ErrorHandler* db_error_handler_;
// If there were two snapshots with seq numbers s1 and
// s2 and s1 < s2, and if we find two instances of a key k1 then lies
// entirely within s1 and s2, then the earlier version of k1 can be safely
// deleted because that version is not visible in any snapshot.
std::vector<SequenceNumber> existing_snapshots_;
SequenceNumber earliest_snapshot_;
// This is the earliest snapshot that could be used for write-conflict
// checking by a transaction. For any user-key newer than this snapshot, we
// should make sure not to remove evidence that a write occurred.
SequenceNumber earliest_write_conflict_snapshot_;
const SnapshotChecker* const snapshot_checker_;
JobContext* job_context_;
std::shared_ptr<Cache> table_cache_;
@@ -353,18 +353,15 @@ class CompactionJob {
// it also collects the smallest_seqno -> oldest_ancester_time from the SST.
SeqnoToTimeMapping seqno_to_time_mapping_;
// Max seqno that can be zeroed out in last level, including for preserving
// write times.
SequenceNumber preserve_seqno_after_ = kMaxSequenceNumber;
// Minimal sequence number for preserving the time information. The time info
// older than this sequence number won't be preserved after the compaction and
// if it's bottommost compaction, the seq num will be zeroed out.
SequenceNumber preserve_time_min_seqno_ = kMaxSequenceNumber;
// Minimal sequence number to preclude the data from the last level. If the
// key has bigger (newer) sequence number than this, it will be precluded from
// the last level (output to proximal level).
SequenceNumber proximal_after_seqno_ = kMaxSequenceNumber;
// Options File Number used for Remote Compaction
// Setting this requires DBMutex.
uint64_t options_file_number_ = 0;
// the last level (output to penultimate level).
SequenceNumber preclude_last_level_min_seqno_ = kMaxSequenceNumber;
// Get table file name in where it's outputting to, which should also be in
// `output_directory_`.
@@ -414,9 +411,8 @@ struct CompactionServiceInput {
// CompactionServiceOutputFile is the metadata for the output SST file
struct CompactionServiceOutputFile {
std::string file_name;
uint64_t file_size{};
SequenceNumber smallest_seqno{};
SequenceNumber largest_seqno{};
SequenceNumber smallest_seqno;
SequenceNumber largest_seqno;
std::string smallest_internal_key;
std::string largest_internal_key;
uint64_t oldest_ancester_time = kUnknownOldestAncesterTime;
@@ -424,26 +420,21 @@ struct CompactionServiceOutputFile {
uint64_t epoch_number = kUnknownEpochNumber;
std::string file_checksum = kUnknownFileChecksum;
std::string file_checksum_func_name = kUnknownFileChecksumFuncName;
uint64_t paranoid_hash{};
uint64_t paranoid_hash;
bool marked_for_compaction;
UniqueId64x2 unique_id{};
TableProperties table_properties;
bool is_proximal_level_output;
Temperature file_temperature = Temperature::kUnknown;
CompactionServiceOutputFile() = default;
CompactionServiceOutputFile(
const std::string& name, uint64_t size, SequenceNumber smallest,
SequenceNumber largest, std::string _smallest_internal_key,
std::string _largest_internal_key, uint64_t _oldest_ancester_time,
uint64_t _file_creation_time, uint64_t _epoch_number,
const std::string& _file_checksum,
const std::string& name, SequenceNumber smallest, SequenceNumber largest,
std::string _smallest_internal_key, std::string _largest_internal_key,
uint64_t _oldest_ancester_time, uint64_t _file_creation_time,
uint64_t _epoch_number, const std::string& _file_checksum,
const std::string& _file_checksum_func_name, uint64_t _paranoid_hash,
bool _marked_for_compaction, UniqueId64x2 _unique_id,
const TableProperties& _table_properties, bool _is_proximal_level_output,
Temperature _file_temperature)
const TableProperties& _table_properties)
: file_name(name),
file_size(size),
smallest_seqno(smallest),
largest_seqno(largest),
smallest_internal_key(std::move(_smallest_internal_key)),
@@ -456,9 +447,7 @@ struct CompactionServiceOutputFile {
paranoid_hash(_paranoid_hash),
marked_for_compaction(_marked_for_compaction),
unique_id(std::move(_unique_id)),
table_properties(_table_properties),
is_proximal_level_output(_is_proximal_level_output),
file_temperature(_file_temperature) {}
table_properties(_table_properties) {}
};
// CompactionServiceResult contains the compaction result from a different db
@@ -474,21 +463,8 @@ struct CompactionServiceResult {
uint64_t bytes_read = 0;
uint64_t bytes_written = 0;
// Job-level Compaction Stats.
//
// NOTE: Job level stats cannot be rebuilt from scratch by simply aggregating
// per-level stats due to some fields populated directly during compaction
// (e.g. RecordDroppedKeys()). This is why we need both job-level stats and
// per-level in the serialized result. If rebuilding job-level stats from
// per-level stats become possible in the future, consider deprecating this
// field.
CompactionJobStats stats;
// Per-level Compaction Stats for both output_level_stats and
// proximal_level_stats
InternalStats::CompactionStatsFull internal_stats;
// serialization interface to read and write the object
static Status Read(const std::string& data_str, CompactionServiceResult* obj);
Status Write(std::string* output);
@@ -511,19 +487,15 @@ class CompactionServiceCompactionJob : private CompactionJob {
const std::atomic<bool>* shutting_down, LogBuffer* log_buffer,
FSDirectory* output_directory, Statistics* stats,
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
JobContext* job_context, std::shared_ptr<Cache> table_cache,
EventLogger* event_logger, const std::string& dbname,
const std::shared_ptr<IOTracer>& io_tracer,
std::vector<SequenceNumber> existing_snapshots,
std::shared_ptr<Cache> table_cache, EventLogger* event_logger,
const std::string& dbname, const std::shared_ptr<IOTracer>& io_tracer,
const std::atomic<bool>& manual_compaction_canceled,
const std::string& db_id, const std::string& db_session_id,
std::string output_path,
const CompactionServiceInput& compaction_service_input,
CompactionServiceResult* compaction_service_result);
// REQUIRED: mutex held
// Like CompactionJob::Prepare()
void Prepare();
// Run the compaction in current thread and return the result
Status Run();
@@ -534,6 +506,9 @@ class CompactionServiceCompactionJob : private CompactionJob {
protected:
void RecordCompactionIOStats() override;
void UpdateCompactionJobStats(
const InternalStats::CompactionStats& stats) const override;
private:
// Get table file name in output_path
std::string GetTableFileName(uint64_t file_number) override;
@@ -959,6 +959,7 @@ int main(int argc, char** argv) {
return RUN_ALL_TESTS();
}
#else
int main(int /*argc*/, char** /*argv*/) { return 0; }
+39 -40
View File
@@ -3,6 +3,7 @@
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include "db/compaction/compaction_job.h"
#include <algorithm>
@@ -43,6 +44,7 @@ void VerifyInitializationOfCompactionJobStats(
ASSERT_EQ(compaction_job_stats.elapsed_micros, 0U);
ASSERT_EQ(compaction_job_stats.num_input_records, 0U);
ASSERT_EQ(compaction_job_stats.num_input_files, 0U);
ASSERT_EQ(compaction_job_stats.num_input_files_at_output_level, 0U);
ASSERT_EQ(compaction_job_stats.num_output_records, 0U);
@@ -51,6 +53,7 @@ void VerifyInitializationOfCompactionJobStats(
ASSERT_TRUE(compaction_job_stats.is_manual_compaction);
ASSERT_FALSE(compaction_job_stats.is_remote_compaction);
ASSERT_EQ(compaction_job_stats.total_input_bytes, 0U);
ASSERT_EQ(compaction_job_stats.total_output_bytes, 0U);
ASSERT_EQ(compaction_job_stats.total_input_raw_key_bytes, 0U);
@@ -299,7 +302,7 @@ class CompactionJobTestBase : public testing::Test {
std::unique_ptr<TableBuilder> table_builder(
cf_options_.table_factory->NewTableBuilder(
TableBuilderOptions(
cfd_->ioptions(), mutable_cf_options_, read_options,
*cfd_->ioptions(), mutable_cf_options_, read_options,
write_options, cfd_->internal_comparator(),
cfd_->internal_tbl_prop_coll_factories(),
CompressionType::kNoCompression, CompressionOptions(),
@@ -395,8 +398,8 @@ class CompactionJobTestBase : public testing::Test {
mutex_.Lock();
EXPECT_OK(versions_->LogAndApply(
versions_->GetColumnFamilySet()->GetDefault(), read_options_,
write_options_, &edit, &mutex_, nullptr));
versions_->GetColumnFamilySet()->GetDefault(), mutable_cf_options_,
read_options_, write_options_, &edit, &mutex_, nullptr));
mutex_.Unlock();
}
@@ -458,10 +461,9 @@ class CompactionJobTestBase : public testing::Test {
ReadOptions read_opts;
Status s = cf_options_.table_factory->NewTableReader(
read_opts,
TableReaderOptions(cfd->ioptions(), /*prefix_extractor=*/nullptr,
/*compression_manager=*/nullptr, FileOptions(),
TableReaderOptions(*cfd->ioptions(), nullptr, FileOptions(),
cfd_->internal_comparator(),
/*block_protection_bytes_per_key=*/0),
0 /* block_protection_bytes_per_key */),
std::move(freader), file_size, &table_reader, false);
ASSERT_OK(s);
assert(table_reader);
@@ -594,11 +596,11 @@ class CompactionJobTestBase : public testing::Test {
const std::vector<std::vector<FileMetaData*>>& input_files,
const std::vector<int> input_levels,
std::function<void(Compaction& comp)>&& verify_func,
std::vector<SequenceNumber>&& snapshots = {}) {
const std::vector<SequenceNumber>& snapshots = {}) {
const int kLastLevel = cf_options_.num_levels - 1;
verify_per_key_placement_ = std::move(verify_func);
mock::KVVector empty_map;
RunCompaction(input_files, input_levels, {empty_map}, std::move(snapshots),
RunCompaction(input_files, input_levels, {empty_map}, snapshots,
kMaxSequenceNumber, kLastLevel, false);
}
@@ -607,7 +609,7 @@ class CompactionJobTestBase : public testing::Test {
const std::vector<std::vector<FileMetaData*>>& input_files,
const std::vector<int>& input_levels,
const std::vector<mock::KVVector>& expected_results,
std::vector<SequenceNumber>&& snapshots = {},
const std::vector<SequenceNumber>& snapshots = {},
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber,
int output_level = 1, bool verify = true,
std::vector<uint64_t> expected_oldest_blob_file_numbers = {},
@@ -644,15 +646,14 @@ class CompactionJobTestBase : public testing::Test {
}
Compaction compaction(
cfd->current()->storage_info(), cfd->ioptions(),
cfd->GetLatestMutableCFOptions(), mutable_db_options_,
cfd->current()->storage_info(), *cfd->ioptions(),
*cfd->GetLatestMutableCFOptions(), mutable_db_options_,
compaction_input_files, output_level,
mutable_cf_options_.target_file_size_base,
mutable_cf_options_.max_compaction_bytes, 0, kNoCompression,
cfd->GetLatestMutableCFOptions().compression_opts,
cfd->GetLatestMutableCFOptions()->compression_opts,
Temperature::kUnknown, max_subcompactions, grandparents,
/*earliest_snapshot*/ std::nullopt, /*snapshot_checker*/ nullptr,
CompactionReason::kManualCompaction);
/*earliest_snapshot*/ std::nullopt, /*snapshot_checker*/ nullptr, true);
compaction.FinalizeInputInfo(cfd->current());
assert(db_options_.info_log);
@@ -665,28 +666,27 @@ class CompactionJobTestBase : public testing::Test {
ucmp_->timestamp_size() == full_history_ts_low_.size());
const std::atomic<bool> kManualCompactionCanceledFalse{false};
JobContext job_context(1, false /* create_superversion */);
job_context.InitSnapshotContext(snapshot_checker, nullptr,
earliest_write_conflict_snapshot,
std::move(snapshots));
CompactionJob compaction_job(
0, &compaction, db_options_, mutable_db_options_, env_options_,
versions_.get(), &shutting_down_, &log_buffer, nullptr, nullptr,
nullptr, nullptr, &mutex_, &error_handler_, &job_context, table_cache_,
&event_logger, false, false, dbname_, &compaction_job_stats_,
Env::Priority::USER, nullptr /* IOTracer */,
nullptr, nullptr, &mutex_, &error_handler_, snapshots,
earliest_write_conflict_snapshot, snapshot_checker, &job_context,
table_cache_, &event_logger, false, false, dbname_,
&compaction_job_stats_, Env::Priority::USER, nullptr /* IOTracer */,
/*manual_compaction_canceled=*/kManualCompactionCanceledFalse,
env_->GenerateUniqueId(), DBImpl::GenerateDbSessionId(nullptr),
full_history_ts_low_);
VerifyInitializationOfCompactionJobStats(compaction_job_stats_);
compaction_job.Prepare(std::nullopt /*subcompact to be computed*/);
compaction_job.Prepare();
mutex_.Unlock();
Status s = compaction_job.Run();
ASSERT_OK(s);
ASSERT_OK(compaction_job.io_status());
mutex_.Lock();
bool compaction_released = false;
ASSERT_OK(compaction_job.Install(&compaction_released));
ASSERT_OK(compaction_job.Install(*cfd->GetLatestMutableCFOptions(),
&compaction_released));
ASSERT_OK(compaction_job.io_status());
mutex_.Unlock();
log_buffer.FlushBufferToLog();
@@ -1476,7 +1476,7 @@ TEST_F(CompactionJobTest, OldestBlobFileNumber) {
/* expected_oldest_blob_file_numbers */ {19});
}
TEST_F(CompactionJobTest, VerifyProximalLevelOutput) {
TEST_F(CompactionJobTest, VerifyPenultimateLevelOutput) {
cf_options_.last_level_temperature = Temperature::kCold;
SyncPoint::GetInstance()->SetCallBack(
"Compaction::SupportsPerKeyPlacement:Enabled", [&](void* arg) {
@@ -1489,7 +1489,8 @@ TEST_F(CompactionJobTest, VerifyProximalLevelOutput) {
SyncPoint::GetInstance()->SetCallBack(
"CompactionIterator::PrepareOutput.context", [&](void* arg) {
auto context = static_cast<PerKeyPlacementContext*>(arg);
context->output_to_proximal_level = context->seq_num > latest_cold_seq;
context->output_to_penultimate_level =
context->seq_num > latest_cold_seq;
});
SyncPoint::GetInstance()->EnableProcessing();
@@ -1535,11 +1536,14 @@ TEST_F(CompactionJobTest, VerifyProximalLevelOutput) {
/*verify_func=*/[&](Compaction& comp) {
for (char c = 'a'; c <= 'z'; c++) {
if (c == 'a') {
comp.TEST_AssertWithinProximalLevelOutputRange(
"a", true /*expect_failure*/);
ParsedInternalKey pik("a", 0U, kTypeValue);
ASSERT_FALSE(comp.WithinPenultimateLevelOutputRange(pik));
} else {
std::string c_str{c};
comp.TEST_AssertWithinProximalLevelOutputRange(c_str);
// WithinPenultimateLevelOutputRange checks internal key range.
// 'z' is the last key, so set seqno properly.
ParsedInternalKey pik(c_str, c == 'z' ? 12U : 0U, kTypeValue);
ASSERT_TRUE(comp.WithinPenultimateLevelOutputRange(pik));
}
}
});
@@ -1671,7 +1675,6 @@ TEST_F(CompactionJobTest, ResultSerialization) {
UniqueId64x2 id{rnd64.Uniform(UINT64_MAX), rnd64.Uniform(UINT64_MAX)};
result.output_files.emplace_back(
rnd.RandomString(rnd.Uniform(kStrMaxLen)) /* file_name */,
rnd64.Uniform(UINT64_MAX) /* file_size */,
rnd64.Uniform(UINT64_MAX) /* smallest_seqno */,
rnd64.Uniform(UINT64_MAX) /* largest_seqno */,
rnd.RandomBinaryString(
@@ -1684,8 +1687,7 @@ TEST_F(CompactionJobTest, ResultSerialization) {
file_checksum /* file_checksum */,
file_checksum_func_name /* file_checksum_func_name */,
rnd64.Uniform(UINT64_MAX) /* paranoid_hash */,
rnd.OneIn(2) /* marked_for_compaction */, id /* unique_id */, tp,
false /* is_proximal_level_output */, Temperature::kHot);
rnd.OneIn(2) /* marked_for_compaction */, id /* unique_id */, tp);
}
result.output_level = rnd.Uniform(10);
result.output_path = rnd.RandomString(rnd.Uniform(kStrMaxLen));
@@ -1739,8 +1741,6 @@ TEST_F(CompactionJobTest, ResultSerialization) {
ASSERT_EQ(deserialized_tmp.output_files[0].file_checksum, file_checksum);
ASSERT_EQ(deserialized_tmp.output_files[0].file_checksum_func_name,
file_checksum_func_name);
ASSERT_EQ(deserialized_tmp.output_files[0].file_temperature,
Temperature::kHot);
}
// Test unknown field
@@ -1900,8 +1900,8 @@ TEST_F(CompactionJobTest, CutToSkipGrandparentFile) {
const std::vector<int> input_levels = {0, 1};
auto lvl0_files = cfd_->current()->storage_info()->LevelFiles(0);
auto lvl1_files = cfd_->current()->storage_info()->LevelFiles(1);
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2});
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2});
}
TEST_F(CompactionJobTest, CutToAlignGrandparentBoundary) {
@@ -1975,8 +1975,8 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundary) {
const std::vector<int> input_levels = {0, 1};
auto lvl0_files = cfd_->current()->storage_info()->LevelFiles(0);
auto lvl1_files = cfd_->current()->storage_info()->LevelFiles(1);
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2});
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2});
}
TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
@@ -2037,8 +2037,8 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
for (int i = 80; i <= 100; i++) {
snapshots.emplace_back(i);
}
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2}, std::move(snapshots));
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2}, snapshots);
}
TEST_F(CompactionJobTest, CutForMaxCompactionBytesSameKey) {
@@ -2097,8 +2097,7 @@ TEST_F(CompactionJobTest, CutForMaxCompactionBytesSameKey) {
snapshots.emplace_back(i);
}
RunCompaction({lvl0_files, lvl1_files}, input_levels,
{expected_file1, expected_file2, expected_file3},
std::move(snapshots));
{expected_file1, expected_file2, expected_file3}, snapshots);
}
class CompactionJobTimestampTest : public CompactionJobTestBase {
+17 -24
View File
@@ -54,8 +54,7 @@ Status CompactionOutputs::Finish(
}
current_output().finished = true;
stats_.bytes_written += current_bytes;
stats_.bytes_written_pre_comp += builder_->PreCompressionSize();
stats_.num_output_files = static_cast<int>(outputs_.size());
stats_.num_output_files = outputs_.size();
return s;
}
@@ -321,7 +320,7 @@ bool CompactionOutputs::ShouldStopBefore(const CompactionIterator& c_iter) {
// More details, check PR #1963
const size_t num_skippable_boundaries_crossed =
being_grandparent_gap_ ? 2 : 3;
if (compaction_->immutable_options().compaction_style ==
if (compaction_->immutable_options()->compaction_style ==
kCompactionStyleLevel &&
num_grandparent_boundaries_crossed >=
num_skippable_boundaries_crossed &&
@@ -342,7 +341,7 @@ bool CompactionOutputs::ShouldStopBefore(const CompactionIterator& c_iter) {
// target file size. The test shows it can generate larger files than a
// static threshold like 75% and has a similar write amplification
// improvement.
if (compaction_->immutable_options().compaction_style ==
if (compaction_->immutable_options()->compaction_style ==
kCompactionStyleLevel &&
current_output_file_size_ >=
((compaction_->target_output_file_size() + 99) / 100) *
@@ -456,11 +455,9 @@ void SetMaxSeqAndTs(InternalKey& internal_key, const Slice& user_key,
} // namespace
Status CompactionOutputs::AddRangeDels(
CompactionRangeDelAggregator& range_del_agg,
const Slice* comp_start_user_key, const Slice* comp_end_user_key,
CompactionIterationStats& range_del_out_stats, bool bottommost_level,
const InternalKeyComparator& icmp, SequenceNumber earliest_snapshot,
std::pair<SequenceNumber, SequenceNumber> keep_seqno_range,
const Slice& next_table_min_key, const std::string& full_history_ts_low) {
// The following example does not happen since
// CompactionOutput::ShouldStopBefore() always return false for the first
@@ -473,7 +470,7 @@ Status CompactionOutputs::AddRangeDels(
// Then meta.smallest will be set to comp_start_user_key@seqno
// and meta.largest will be set to comp_start_user_key@kMaxSequenceNumber
// which violates the assumption that meta.smallest should be <= meta.largest.
assert(!range_del_agg.IsEmpty());
assert(HasRangeDel());
FileMetaData& meta = current_output().meta;
const Comparator* ucmp = icmp.user_comparator();
InternalKey lower_bound_buf, upper_bound_buf;
@@ -582,19 +579,13 @@ Status CompactionOutputs::AddRangeDels(
assert(comp_end_user_key == nullptr || upper_bound == nullptr ||
ucmp->CompareWithoutTimestamp(ExtractUserKey(*upper_bound),
*comp_end_user_key) <= 0);
auto it = range_del_agg.NewIterator(lower_bound, upper_bound);
auto it = range_del_agg_->NewIterator(lower_bound, upper_bound);
Slice last_tombstone_start_user_key{};
bool reached_lower_bound = false;
const ReadOptions read_options(Env::IOActivity::kCompaction);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
auto tombstone = it->Tombstone();
auto kv = tombstone.Serialize();
// Filter out by seqno for per-key placement
if (tombstone.seq_ < keep_seqno_range.first ||
tombstone.seq_ >= keep_seqno_range.second) {
continue;
}
InternalKey tombstone_end = tombstone.SerializeEndKey();
// TODO: the underlying iterator should support clamping the bounds.
// tombstone_end.Encode is of form user_key@kMaxSeqno
@@ -753,10 +744,11 @@ Status CompactionOutputs::AddRangeDels(
}
void CompactionOutputs::FillFilesToCutForTtl() {
if (compaction_->immutable_options().compaction_style !=
if (compaction_->immutable_options()->compaction_style !=
kCompactionStyleLevel ||
compaction_->immutable_options().compaction_pri != kMinOverlappingRatio ||
compaction_->mutable_cf_options().ttl == 0 ||
compaction_->immutable_options()->compaction_pri !=
kMinOverlappingRatio ||
compaction_->mutable_cf_options()->ttl == 0 ||
compaction_->num_input_levels() < 2 || compaction_->bottommost_level()) {
return;
}
@@ -764,19 +756,20 @@ void CompactionOutputs::FillFilesToCutForTtl() {
// We define new file with the oldest ancestor time to be younger than 1/4
// TTL, and an old one to be older than 1/2 TTL time.
int64_t temp_current_time;
auto get_time_status = compaction_->immutable_options().clock->GetCurrentTime(
&temp_current_time);
auto get_time_status =
compaction_->immutable_options()->clock->GetCurrentTime(
&temp_current_time);
if (!get_time_status.ok()) {
return;
}
auto current_time = static_cast<uint64_t>(temp_current_time);
if (current_time < compaction_->mutable_cf_options().ttl) {
if (current_time < compaction_->mutable_cf_options()->ttl) {
return;
}
uint64_t old_age_thres =
current_time - compaction_->mutable_cf_options().ttl / 2;
current_time - compaction_->mutable_cf_options()->ttl / 2;
const std::vector<FileMetaData*>& olevel =
*(compaction_->inputs(compaction_->num_input_levels() - 1));
for (FileMetaData* file : olevel) {
@@ -786,15 +779,15 @@ void CompactionOutputs::FillFilesToCutForTtl() {
// of small files.
if (oldest_ancester_time < old_age_thres &&
file->fd.GetFileSize() >
compaction_->mutable_cf_options().target_file_size_base / 2) {
compaction_->mutable_cf_options()->target_file_size_base / 2) {
files_to_cut_for_ttl_.push_back(file);
}
}
}
CompactionOutputs::CompactionOutputs(const Compaction* compaction,
const bool is_proximal_level)
: compaction_(compaction), is_proximal_level_(is_proximal_level) {
const bool is_penultimate_level)
: compaction_(compaction), is_penultimate_level_(is_penultimate_level) {
partitioner_ = compaction->output_level() == 0
? nullptr
: compaction->CreateSstPartitioner();
+45 -34
View File
@@ -30,32 +30,27 @@ class CompactionOutputs {
// compaction output file
struct Output {
Output(FileMetaData&& _meta, const InternalKeyComparator& _icmp,
bool _enable_hash, bool _finished, uint64_t precalculated_hash,
bool _is_proximal_level)
bool _enable_hash, bool _finished, uint64_t precalculated_hash)
: meta(std::move(_meta)),
validator(_icmp, _enable_hash, precalculated_hash),
finished(_finished),
is_proximal_level(_is_proximal_level) {}
finished(_finished) {}
FileMetaData meta;
OutputValidator validator;
bool finished;
bool is_proximal_level;
std::shared_ptr<const TableProperties> table_properties;
};
CompactionOutputs() = delete;
explicit CompactionOutputs(const Compaction* compaction,
const bool is_proximal_level);
bool IsProximalLevel() const { return is_proximal_level_; }
const bool is_penultimate_level);
// Add generated output to the list
void AddOutput(FileMetaData&& meta, const InternalKeyComparator& icmp,
bool enable_hash, bool finished = false,
uint64_t precalculated_hash = 0) {
outputs_.emplace_back(std::move(meta), icmp, enable_hash, finished,
precalculated_hash, is_proximal_level_);
precalculated_hash);
}
// Set new table builder for the current output
@@ -66,29 +61,34 @@ class CompactionOutputs {
file_writer_.reset(writer);
}
// TODO: Remove it when remote compaction support tiered compaction
void AddBytesWritten(uint64_t bytes) { stats_.bytes_written += bytes; }
void SetNumOutputRecords(uint64_t num) { stats_.num_output_records = num; }
void SetNumOutputFiles(uint64_t num) { stats_.num_output_files = num; }
// TODO: Move the BlobDB builder into CompactionOutputs
const std::vector<BlobFileAddition>& GetBlobFileAdditions() const {
if (is_proximal_level_) {
if (is_penultimate_level_) {
assert(blob_file_additions_.empty());
}
return blob_file_additions_;
}
std::vector<BlobFileAddition>* GetBlobFileAdditionsPtr() {
assert(!is_proximal_level_);
assert(!is_penultimate_level_);
return &blob_file_additions_;
}
bool HasBlobFileAdditions() const { return !blob_file_additions_.empty(); }
BlobGarbageMeter* CreateBlobGarbageMeter() {
assert(!is_proximal_level_);
assert(!is_penultimate_level_);
blob_garbage_meter_ = std::make_unique<BlobGarbageMeter>();
return blob_garbage_meter_.get();
}
BlobGarbageMeter* GetBlobGarbageMeter() const {
if (is_proximal_level_) {
if (is_penultimate_level_) {
// blobdb doesn't support per_key_placement yet
assert(blob_garbage_meter_ == nullptr);
return nullptr;
@@ -97,9 +97,8 @@ class CompactionOutputs {
}
void UpdateBlobStats() {
assert(!is_proximal_level_);
stats_.num_output_files_blob =
static_cast<int>(blob_file_additions_.size());
assert(!is_penultimate_level_);
stats_.num_output_files_blob = blob_file_additions_.size();
for (const auto& blob : blob_file_additions_) {
stats_.bytes_written_blob += blob.GetTotalBlobBytes();
}
@@ -183,13 +182,18 @@ class CompactionOutputs {
// @param next_table_min_key internal key lower bound for the next compaction
// output.
// @param full_history_ts_low used for range tombstone garbage collection.
Status AddRangeDels(
CompactionRangeDelAggregator& range_del_agg,
const Slice* comp_start_user_key, const Slice* comp_end_user_key,
CompactionIterationStats& range_del_out_stats, bool bottommost_level,
const InternalKeyComparator& icmp, SequenceNumber earliest_snapshot,
std::pair<SequenceNumber, SequenceNumber> keep_seqno_range,
const Slice& next_table_min_key, const std::string& full_history_ts_low);
Status AddRangeDels(const Slice* comp_start_user_key,
const Slice* comp_end_user_key,
CompactionIterationStats& range_del_out_stats,
bool bottommost_level, const InternalKeyComparator& icmp,
SequenceNumber earliest_snapshot,
const Slice& next_table_min_key,
const std::string& full_history_ts_low);
// if the outputs have range delete, range delete is also data
bool HasRangeDel() const {
return range_del_agg_ && !range_del_agg_->IsEmpty();
}
private:
friend class SubcompactionState;
@@ -255,15 +259,11 @@ class CompactionOutputs {
// Close the current output. `open_file_func` is needed for creating new file
// for range-dels only output file.
Status CloseOutput(const Status& curr_status,
CompactionRangeDelAggregator* range_del_agg,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func) {
Status status = curr_status;
// Handle subcompaction containing only range deletions. They could
// be dropped or sent to another output level, so this is only an
// over-approximate check for whether opening is needed.
if (status.ok() && !HasBuilder() && !HasOutput() && range_del_agg &&
!range_del_agg->IsEmpty()) {
// handle subcompaction containing only range deletions
if (status.ok() && !HasBuilder() && !HasOutput() && HasRangeDel()) {
status = open_file_func(*this);
}
if (HasBuilder()) {
@@ -288,6 +288,16 @@ class CompactionOutputs {
return outputs_.back();
}
// Assign the range_del_agg to the target output level. There's only one
// range-del-aggregator per compaction outputs, for
// output_to_penultimate_level compaction it is only assigned to the
// penultimate level.
void AssignRangeDelAggregator(
std::unique_ptr<CompactionRangeDelAggregator>&& range_del_agg) {
assert(range_del_agg_ == nullptr);
range_del_agg_ = std::move(range_del_agg);
}
const Compaction* compaction_;
// current output builder and writer
@@ -303,12 +313,13 @@ class CompactionOutputs {
std::vector<BlobFileAddition> blob_file_additions_;
std::unique_ptr<BlobGarbageMeter> blob_garbage_meter_;
// Per level's output stat
InternalStats::CompactionStats stats_;
// Basic compaction output stats for this level's outputs
InternalStats::CompactionOutputsStats stats_;
// indicate if this CompactionOutputs obj for proximal_level, should always
// indicate if this CompactionOutputs obj for penultimate_level, should always
// be false if per_key_placement feature is not enabled.
const bool is_proximal_level_;
const bool is_penultimate_level_;
std::unique_ptr<CompactionRangeDelAggregator> range_del_agg_ = nullptr;
// partitioner information
std::string last_key_for_partitioner_;
@@ -362,7 +373,7 @@ class CompactionOutputs {
std::vector<size_t> level_ptrs_;
};
// helper struct to concatenate the last level and proximal level outputs
// helper struct to concatenate the last level and penultimate level outputs
// which could be replaced by std::ranges::join_view() in c++20
struct OutputIterator {
public:
+41 -42
View File
@@ -272,8 +272,8 @@ bool CompactionPicker::RangeOverlapWithCompaction(
return true;
}
if (c->SupportsPerKeyPlacement()) {
if (c->OverlapProximalLevelOutputRange(smallest_user_key,
largest_user_key)) {
if (c->OverlapPenultimateLevelOutputRange(smallest_user_key,
largest_user_key)) {
return true;
}
}
@@ -284,7 +284,7 @@ bool CompactionPicker::RangeOverlapWithCompaction(
bool CompactionPicker::FilesRangeOverlapWithCompaction(
const std::vector<CompactionInputFiles>& inputs, int level,
int proximal_level) const {
int penultimate_level) const {
bool is_empty = true;
for (auto& in : inputs) {
if (!in.empty()) {
@@ -301,18 +301,18 @@ bool CompactionPicker::FilesRangeOverlapWithCompaction(
// files cannot be overlapped in the order of L0 files.
InternalKey smallest, largest;
GetRange(inputs, &smallest, &largest, Compaction::kInvalidLevel);
if (proximal_level != Compaction::kInvalidLevel) {
if (penultimate_level != Compaction::kInvalidLevel) {
if (ioptions_.compaction_style == kCompactionStyleUniversal) {
if (RangeOverlapWithCompaction(smallest.user_key(), largest.user_key(),
proximal_level)) {
penultimate_level)) {
return true;
}
} else {
InternalKey proximal_smallest, proximal_largest;
GetRange(inputs, &proximal_smallest, &proximal_largest, level);
if (RangeOverlapWithCompaction(proximal_smallest.user_key(),
proximal_largest.user_key(),
proximal_level)) {
InternalKey penultimate_smallest, penultimate_largest;
GetRange(inputs, &penultimate_smallest, &penultimate_largest, level);
if (RangeOverlapWithCompaction(penultimate_smallest.user_key(),
penultimate_largest.user_key(),
penultimate_level)) {
return true;
}
}
@@ -337,9 +337,7 @@ Compaction* CompactionPicker::CompactFiles(
const CompactionOptions& compact_options,
const std::vector<CompactionInputFiles>& input_files, int output_level,
VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, uint32_t output_path_id,
std::optional<SequenceNumber> earliest_snapshot,
const SnapshotChecker* snapshot_checker) {
const MutableDBOptions& mutable_db_options, uint32_t output_path_id) {
#ifndef NDEBUG
assert(input_files.size());
// This compaction output should not overlap with a running compaction as
@@ -355,7 +353,7 @@ Compaction* CompactionPicker::CompactFiles(
}
assert(output_level == 0 || !FilesRangeOverlapWithCompaction(
input_files, output_level,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage, mutable_cf_options, ioptions_,
start_level, output_level)));
#endif /* !NDEBUG */
@@ -382,8 +380,8 @@ Compaction* CompactionPicker::CompactFiles(
GetCompressionOptions(mutable_cf_options, vstorage, output_level),
mutable_cf_options.default_write_temperature,
compact_options.max_subcompactions,
/* grandparents */ {}, earliest_snapshot, snapshot_checker,
CompactionReason::kManualCompaction);
/* grandparents */ {}, /* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, true);
RegisterCompaction(c);
return c;
}
@@ -661,9 +659,9 @@ Compaction* CompactionPicker::CompactRange(
// overlaping outputs in the same level.
if (FilesRangeOverlapWithCompaction(
inputs, output_level,
Compaction::EvaluateProximalLevel(vstorage, mutable_cf_options,
ioptions_, start_level,
output_level))) {
Compaction::EvaluatePenultimateLevel(vstorage, mutable_cf_options,
ioptions_, start_level,
output_level))) {
// This compaction output could potentially conflict with the output
// of a currently running compaction, we cannot run it.
*manual_conflict = true;
@@ -682,9 +680,10 @@ Compaction* CompactionPicker::CompactRange(
mutable_cf_options.default_write_temperature,
compact_range_options.max_subcompactions,
/* grandparents */ {}, /* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, CompactionReason::kManualCompaction,
trim_ts, /* score */ -1,
/* l0_files_might_overlap */ true,
/* snapshot_checker */ nullptr,
/* is manual */ true, trim_ts, /* score */ -1,
/* deletion_compaction */ false, /* l0_files_might_overlap */ true,
CompactionReason::kUnknown,
compact_range_options.blob_garbage_collection_policy,
compact_range_options.blob_garbage_collection_age_cutoff);
@@ -722,14 +721,14 @@ Compaction* CompactionPicker::CompactRange(
// two files overlap.
if (input_level > 0) {
const uint64_t limit = mutable_cf_options.max_compaction_bytes;
uint64_t input_level_total = 0;
int hint_index = -1;
assert(!inputs.empty());
// Always include first file for progress.
uint64_t input_level_total = inputs[0]->fd.GetFileSize();
InternalKey* smallest = &(inputs[0]->smallest);
InternalKey* smallest = nullptr;
InternalKey* largest = nullptr;
for (size_t i = 1; i < inputs.size(); ++i) {
// Consider whether to include inputs[i]
for (size_t i = 0; i + 1 < inputs.size(); ++i) {
if (!smallest) {
smallest = &inputs[i]->smallest;
}
largest = &inputs[i]->largest;
uint64_t input_file_size = inputs[i]->fd.GetFileSize();
@@ -745,11 +744,13 @@ Compaction* CompactionPicker::CompactRange(
input_level_total += input_file_size;
if (input_level_total + output_level_total > limit) {
// To ensure compaction size is <= limit, leave out inputs from
// index i onwards.
if (input_level_total + output_level_total >= limit) {
covering_the_whole_range = false;
inputs.files.resize(i);
// still include the current file, so the compaction could be larger
// than max_compaction_bytes, which is also to make sure the compaction
// can make progress even `max_compaction_bytes` is small (e.g. smaller
// than an SST file).
inputs.files.resize(i + 1);
break;
}
}
@@ -818,9 +819,6 @@ Compaction* CompactionPicker::CompactRange(
output_level = vstorage->base_level();
assert(output_level > 0);
}
for (int i = input_level + 1; i < output_level; i++) {
assert(vstorage->NumLevelFiles(i) == 0);
}
output_level_inputs.level = output_level;
if (input_level != output_level) {
int parent_index = -1;
@@ -849,9 +847,9 @@ Compaction* CompactionPicker::CompactRange(
// overlaping outputs in the same level.
if (FilesRangeOverlapWithCompaction(
compaction_inputs, output_level,
Compaction::EvaluateProximalLevel(vstorage, mutable_cf_options,
ioptions_, input_level,
output_level))) {
Compaction::EvaluatePenultimateLevel(vstorage, mutable_cf_options,
ioptions_, input_level,
output_level))) {
// This compaction output could potentially conflict with the output
// of a currently running compaction, we cannot run it.
*manual_conflict = true;
@@ -874,8 +872,9 @@ Compaction* CompactionPicker::CompactRange(
mutable_cf_options.default_write_temperature,
compact_range_options.max_subcompactions, std::move(grandparents),
/* earliest_snapshot */ std::nullopt, /* snapshot_checker */ nullptr,
CompactionReason::kManualCompaction, trim_ts, /* score */ -1,
/* l0_files_might_overlap */ true,
/* is manual */ true, trim_ts, /* score */ -1,
/* deletion_compaction */ false, /* l0_files_might_overlap */ true,
CompactionReason::kUnknown,
compact_range_options.blob_garbage_collection_policy,
compact_range_options.blob_garbage_collection_age_cutoff);
@@ -1137,7 +1136,7 @@ Status CompactionPicker::SanitizeAndConvertCompactionInputFiles(
if (output_level != 0 &&
FilesRangeOverlapWithCompaction(
*converted_input_files, output_level,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
version->storage_info(), version->GetMutableCFOptions(),
ioptions_, (*converted_input_files)[0].level, output_level))) {
return Status::Aborted(
@@ -1154,7 +1153,7 @@ void CompactionPicker::RegisterCompaction(Compaction* c) {
assert(ioptions_.compaction_style != kCompactionStyleLevel ||
c->output_level() == 0 ||
!FilesRangeOverlapWithCompaction(*c->inputs(), c->output_level(),
c->GetProximalLevel()));
c->GetPenultimateLevel()));
// CompactionReason::kExternalSstIngestion's start level is just a placeholder
// number without actual meaning as file ingestion technically does not have
// an input level like other compactions
+9 -23
View File
@@ -65,7 +65,7 @@ class CompactionPicker {
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, bool require_max_output_level) = 0;
LogBuffer* log_buffer) = 0;
// The returned Compaction might not include the whole requested range.
// In that case, compaction_end will be set to the next key that needs
@@ -73,8 +73,6 @@ class CompactionPicker {
// compaction_end will be set to nullptr.
// Client is responsible for compaction_end storage -- when called,
// *compaction_end should point to valid InternalKey!
// REQUIRES: If not compacting all levels (input_level == kCompactAllLevels),
// then levels between input_level and output_level should be empty.
virtual Compaction* CompactRange(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
@@ -117,17 +115,12 @@ class CompactionPicker {
// Caller must provide a set of input files that has been passed through
// `SanitizeAndConvertCompactionInputFiles` earlier. The lock should not be
// released between that call and this one.
//
// TODO - Remove default values for earliest_snapshot and snapshot_checker
// and require all callers to pass them in so that DB::CompactFiles() can
// also benefit from Standalone Range Tombstone Optimization
Compaction* CompactFiles(
const CompactionOptions& compact_options,
const std::vector<CompactionInputFiles>& input_files, int output_level,
VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options, uint32_t output_path_id,
std::optional<SequenceNumber> earliest_snapshot = std::nullopt,
const SnapshotChecker* snapshot_checker = nullptr);
Compaction* CompactFiles(const CompactionOptions& compact_options,
const std::vector<CompactionInputFiles>& input_files,
int output_level, VersionStorageInfo* vstorage,
const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options,
uint32_t output_path_id);
// Converts a set of compaction input file numbers into
// a list of CompactionInputFiles.
@@ -143,12 +136,6 @@ class CompactionPicker {
return !level0_compactions_in_progress_.empty();
}
// Is any compaction in progress
bool IsCompactionInProgress() const {
return !(level0_compactions_in_progress_.empty() &&
compactions_in_progress_.empty());
}
// Return true if the passed key range overlap with a compaction output
// that is currently running.
bool RangeOverlapWithCompaction(const Slice& smallest_user_key,
@@ -201,7 +188,7 @@ class CompactionPicker {
// key range of a currently running compaction.
bool FilesRangeOverlapWithCompaction(
const std::vector<CompactionInputFiles>& inputs, int level,
int proximal_level) const;
int penultimate_level) const;
bool SetupOtherInputs(const std::string& cf_name,
const MutableCFOptions& mutable_cf_options,
@@ -277,8 +264,7 @@ class NullCompactionPicker : public CompactionPicker {
const MutableDBOptions& /*mutable_db_options*/,
const std::vector<SequenceNumber>& /*existing_snapshots*/,
const SnapshotChecker* /*snapshot_checker*/,
VersionStorageInfo* /*vstorage*/, LogBuffer* /* log_buffer */,
bool /*require_max_output_level*/ = false) override {
VersionStorageInfo* /*vstorage*/, LogBuffer* /* log_buffer */) override {
return nullptr;
}
+17 -11
View File
@@ -127,9 +127,11 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
mutable_cf_options.compression_opts,
mutable_cf_options.default_write_temperature,
/* max_subcompactions */ 0, {}, /* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, CompactionReason::kFIFOTtl,
/* snapshot_checker */ nullptr,
/* is manual */ false,
/* trim_ts */ "", vstorage->CompactionScore(0),
/* l0_files_might_overlap */ true);
/* is deletion compaction */ true, /* l0_files_might_overlap */ true,
CompactionReason::kFIFOTtl);
return c;
}
@@ -198,10 +200,11 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
mutable_cf_options.default_write_temperature,
0 /* max_subcompactions */, {},
/* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr,
CompactionReason::kFIFOReduceNumFiles,
/* snapshot_checker */ nullptr, /* is manual */ false,
/* trim_ts */ "", vstorage->CompactionScore(0),
/* l0_files_might_overlap */ true);
/* is deletion compaction */ false,
/* l0_files_might_overlap */ true,
CompactionReason::kFIFOReduceNumFiles);
return c;
}
}
@@ -294,9 +297,11 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
mutable_cf_options.compression_opts,
mutable_cf_options.default_write_temperature,
/* max_subcompactions */ 0, {}, /* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, CompactionReason::kFIFOMaxSize,
/* snapshot_checker */ nullptr,
/* is manual */ false,
/* trim_ts */ "", vstorage->CompactionScore(0),
/* l0_files_might_overlap */ true);
/* is deletion compaction */ true,
/* l0_files_might_overlap */ true, CompactionReason::kFIFOMaxSize);
return c;
}
@@ -411,9 +416,10 @@ Compaction* FIFOCompactionPicker::PickTemperatureChangeCompaction(
mutable_cf_options.compression, mutable_cf_options.compression_opts,
compaction_target_temp,
/* max_subcompactions */ 0, {}, /* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, CompactionReason::kChangeTemperature,
/* trim_ts */ "", vstorage->CompactionScore(0),
/* l0_files_might_overlap */ true);
/* snapshot_checker */ nullptr,
/* is manual */ false, /* trim_ts */ "", vstorage->CompactionScore(0),
/* is deletion compaction */ false, /* l0_files_might_overlap */ true,
CompactionReason::kChangeTemperature);
return c;
}
@@ -422,7 +428,7 @@ Compaction* FIFOCompactionPicker::PickCompaction(
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& /* existing_snapshots */,
const SnapshotChecker* /* snapshot_checker */, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, bool /* require_max_output_level*/) {
LogBuffer* log_buffer) {
Compaction* c = nullptr;
if (mutable_cf_options.ttl > 0) {
c = PickTTLCompaction(cf_name, mutable_cf_options, mutable_db_options,
+1 -2
View File
@@ -23,8 +23,7 @@ class FIFOCompactionPicker : public CompactionPicker {
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& /* existing_snapshots */,
const SnapshotChecker* /* snapshot_checker */,
VersionStorageInfo* version, LogBuffer* log_buffer,
bool /* require_max_output_level*/ = false) override;
VersionStorageInfo* version, LogBuffer* log_buffer) override;
Compaction* CompactRange(const std::string& cf_name,
const MutableCFOptions& mutable_cf_options,
+14 -12
View File
@@ -145,6 +145,7 @@ class LevelCompactionBuilder {
int parent_index_ = -1;
int base_index_ = -1;
double start_level_score_ = 0;
bool is_manual_ = false;
bool is_l0_trivial_move_ = false;
CompactionInputFiles start_level_inputs_;
std::vector<CompactionInputFiles> compaction_inputs_;
@@ -413,9 +414,9 @@ void LevelCompactionBuilder::SetupOtherFilesWithRoundRobinExpansion() {
&tmp_start_level_inputs) ||
compaction_picker_->FilesRangeOverlapWithCompaction(
{tmp_start_level_inputs}, output_level_,
Compaction::EvaluateProximalLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
Compaction::EvaluatePenultimateLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
// Constraint 1a
tmp_start_level_inputs.clear();
return;
@@ -489,9 +490,9 @@ bool LevelCompactionBuilder::SetupOtherInputsIfNeeded() {
// We need to disallow this from happening.
if (compaction_picker_->FilesRangeOverlapWithCompaction(
compaction_inputs_, output_level_,
Compaction::EvaluateProximalLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
Compaction::EvaluatePenultimateLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
// This compaction output could potentially conflict with the output
// of a currently running compaction, we cannot run it.
return false;
@@ -560,8 +561,9 @@ Compaction* LevelCompactionBuilder::GetCompaction() {
mutable_cf_options_.default_write_temperature,
/* max_subcompactions */ 0, std::move(grandparents_),
/* earliest_snapshot */ std::nullopt, /* snapshot_checker */ nullptr,
compaction_reason_,
/* trim_ts */ "", start_level_score_, l0_files_might_overlap);
is_manual_,
/* trim_ts */ "", start_level_score_, false /* deletion_compaction */,
l0_files_might_overlap, compaction_reason_);
// If it's level 0 compaction, make sure we don't execute any other level 0
// compactions in parallel
@@ -844,9 +846,9 @@ bool LevelCompactionBuilder::PickFileToCompact() {
&start_level_inputs_) ||
compaction_picker_->FilesRangeOverlapWithCompaction(
{start_level_inputs_}, output_level_,
Compaction::EvaluateProximalLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
Compaction::EvaluatePenultimateLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level_,
output_level_))) {
// A locked (pending compaction) input-level file was pulled in due to
// user-key overlap.
start_level_inputs_.clear();
@@ -976,7 +978,7 @@ Compaction* LevelCompactionPicker::PickCompaction(
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& /*existing_snapshots */,
const SnapshotChecker* /*snapshot_checker*/, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, bool /* require_max_output_level*/) {
LogBuffer* log_buffer) {
LevelCompactionBuilder builder(cf_name, vstorage, this, log_buffer,
mutable_cf_options, ioptions_,
mutable_db_options);
+1 -2
View File
@@ -25,8 +25,7 @@ class LevelCompactionPicker : public CompactionPicker {
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& /* existing_snapshots */,
const SnapshotChecker* /* snapshot_checker */,
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
bool /*require_max_output_level*/ = false) override;
VersionStorageInfo* vstorage, LogBuffer* log_buffer) override;
bool NeedsCompaction(const VersionStorageInfo* vstorage) const override;
};
+34 -82
View File
@@ -1134,15 +1134,10 @@ TEST_F(CompactionPickerTest, FIFOToCold1) {
fifo_options_.max_table_files_size = kMaxSize;
fifo_options_.file_temperature_age_thresholds = {
{Temperature::kCold, kColdThreshold}};
fifo_options_.allow_trivial_copy_when_change_temperature = true;
fifo_options_.trivial_copy_buffer_size = 16 * 1024 * 1024;
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1191,10 +1186,7 @@ TEST_F(CompactionPickerTest, FIFOToColdMaxCompactionSize) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 9;
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1261,10 +1253,7 @@ TEST_F(CompactionPickerTest, FIFOToColdWithExistingCold) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1329,10 +1318,7 @@ TEST_F(CompactionPickerTest, FIFOToColdWithHotBetweenCold) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -1399,10 +1385,7 @@ TEST_F(CompactionPickerTest, FIFOToHotAndWarm) {
mutable_cf_options_.compaction_options_fifo = fifo_options_;
mutable_cf_options_.level0_file_num_compaction_trigger = 100;
mutable_cf_options_.max_compaction_bytes = kFileSize * 100;
auto copiedIOptions = ioptions_;
copiedIOptions.compaction_style = kCompactionStyleFIFO;
FIFOCompactionPicker fifo_compaction_picker(copiedIOptions, &icmp_);
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
int64_t current_time = 0;
ASSERT_OK(Env::Default()->GetCurrentTime(&current_time));
@@ -2673,37 +2656,6 @@ TEST_F(CompactionPickerTest, HitCompactionLimitWhenAddFileFromInputLevel) {
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
}
TEST_F(CompactionPickerTest, CompactRangeMaxCompactionBytes) {
mutable_cf_options_.max_compaction_bytes = 800000U;
NewVersionStorage(6, kCompactionStyleLevel);
// We will first pick file 1 and 2 and then stop before file 3.
// Since picking file 3 will pull in file 4 and 5 from L2 and
// exceed max_compaction_bytes.
Add(1, 1U, "100", "110", 10000U);
Add(1, 2U, "200", "210", 10000U, 0, 0);
Add(1, 3U, "400", "410", 10000U, 0, 0);
Add(2, 4U, "300", "310", 400000U);
Add(2, 5U, "320", "330", 400000U);
UpdateVersionStorageInfo();
bool manual_conflict = false;
InternalKey manual_end;
InternalKey* manual_end_ptr = &manual_end;
std::unique_ptr<Compaction> compaction(level_compaction_picker.CompactRange(
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
/*input_level=*/1, /*output_level=*/2,
/*compact_range_options*/ {}, /*begin=*/nullptr, /*end=*/nullptr,
&manual_end_ptr, &manual_conflict,
/*max_file_num_to_ignore=*/std::numeric_limits<uint64_t>::max(),
/*trim_ts=*/""));
ASSERT_TRUE(compaction.get() != nullptr);
ASSERT_EQ(1U, compaction->num_input_levels());
ASSERT_EQ(2, compaction->output_level());
ASSERT_EQ(2U, compaction->num_input_files(0));
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
}
TEST_F(CompactionPickerTest, IsTrivialMoveOn) {
mutable_cf_options_.max_bytes_for_level_base = 10000u;
mutable_cf_options_.max_compaction_bytes = 10001u;
@@ -3694,7 +3646,7 @@ TEST_F(CompactionPickerTest, UniversalSizeRatioTierCompactionLastLevel) {
const uint64_t kFileSize = 100000;
const int kNumLevels = 7;
const int kLastLevel = kNumLevels - 1;
const int kProximalLevel = kLastLevel - 1;
const int kPenultimateLevel = kLastLevel - 1;
ioptions_.compaction_style = kCompactionStyleUniversal;
mutable_cf_options_.preclude_last_level_data_seconds = 1000;
@@ -3719,14 +3671,14 @@ TEST_F(CompactionPickerTest, UniversalSizeRatioTierCompactionLastLevel) {
// Here to make sure it's size ratio compaction instead of size amp
ASSERT_EQ(compaction->compaction_reason(),
CompactionReason::kUniversalSizeRatio);
ASSERT_EQ(compaction->output_level(), kProximalLevel - 1);
ASSERT_EQ(compaction->output_level(), kPenultimateLevel - 1);
ASSERT_EQ(compaction->input_levels(0)->num_files, 2);
ASSERT_EQ(compaction->input_levels(5)->num_files, 0);
ASSERT_EQ(compaction->input_levels(6)->num_files, 0);
}
TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionNotSuport) {
// Tiered compaction only support level_num > 2 (otherwise the proximal
// Tiered compaction only support level_num > 2 (otherwise the penultimate
// level is going to be level 0, which may make thing more complicated), so
// when there's only 2 level, still treating level 1 as the last level for
// size amp compaction
@@ -3770,7 +3722,7 @@ TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionLastLevel) {
const uint64_t kFileSize = 100000;
const int kNumLevels = 7;
const int kLastLevel = kNumLevels - 1;
const int kProximalLevel = kLastLevel - 1;
const int kPenultimateLevel = kLastLevel - 1;
ioptions_.compaction_style = kCompactionStyleUniversal;
mutable_cf_options_.preclude_last_level_data_seconds = 1000;
@@ -3792,10 +3744,10 @@ TEST_F(CompactionPickerTest, UniversalSizeAmpTierCompactionLastLevel) {
vstorage_.get(), &log_buffer_));
// It's a Size Amp compaction, but doesn't include the last level file and
// output to the proximal level.
// output to the penultimate level.
ASSERT_EQ(compaction->compaction_reason(),
CompactionReason::kUniversalSizeAmplification);
ASSERT_EQ(compaction->output_level(), kProximalLevel);
ASSERT_EQ(compaction->output_level(), kPenultimateLevel);
ASSERT_EQ(compaction->input_levels(0)->num_files, 2);
ASSERT_EQ(compaction->input_levels(5)->num_files, 1);
ASSERT_EQ(compaction->input_levels(6)->num_files, 0);
@@ -3957,7 +3909,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest, OverlapWithNormalCompaction) {
ASSERT_EQ(enable_per_key_placement_,
level_compaction_picker.FilesRangeOverlapWithCompaction(
input_files, 6,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_.get(), mutable_cf_options_, ioptions_, 0, 6)));
}
@@ -4045,7 +3997,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
ASSERT_EQ(enable_per_key_placement_,
universal_compaction_picker.FilesRangeOverlapWithCompaction(
input_files, 6,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_.get(), mutable_cf_options_, ioptions_, 0, 6)));
}
@@ -4093,9 +4045,9 @@ TEST_P(PerKeyPlacementCompactionPickerTest, NormalCompactionOverlapUniversal) {
input_files, 5, Compaction::kInvalidLevel));
}
TEST_P(PerKeyPlacementCompactionPickerTest, ProximalOverlapUniversal) {
TEST_P(PerKeyPlacementCompactionPickerTest, PenultimateOverlapUniversal) {
// This test is make sure the Tiered compaction would lock whole range of
// both output level and proximal level
// both output level and penultimate level
if (enable_per_key_placement_) {
mutable_cf_options_.preclude_last_level_data_seconds = 10000;
}
@@ -4115,7 +4067,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest, ProximalOverlapUniversal) {
UpdateVersionStorageInfo();
// the existing compaction is the 1st L4 file + L6 file
// then compaction of the 2nd L4 file to L5 (proximal level) is overlapped
// then compaction of the 2nd L4 file to L5 (penultimate level) is overlapped
// when the tiered compaction feature is on.
CompactionOptions comp_options;
std::unordered_set<uint64_t> input_set;
@@ -4204,9 +4156,9 @@ TEST_P(PerKeyPlacementCompactionPickerTest, LastLevelOnlyOverlapUniversal) {
}
TEST_P(PerKeyPlacementCompactionPickerTest,
LastLevelOnlyFailProximalUniversal) {
LastLevelOnlyFailPenultimateUniversal) {
// This is to test last_level only compaction still unable to do the
// proximal level compaction if there's already a file in the proximal
// penultimate level compaction if there's already a file in the penultimate
// level.
// This should rarely happen in universal compaction, as the non-empty L5
// should be included in the compaction.
@@ -4239,9 +4191,9 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
mutable_db_options_, 0));
ASSERT_TRUE(comp1);
ASSERT_EQ(comp1->GetProximalLevel(), Compaction::kInvalidLevel);
ASSERT_EQ(comp1->GetPenultimateLevel(), Compaction::kInvalidLevel);
// As comp1 cannot be output to the proximal level, compacting file 40 to
// As comp1 cannot be output to the penultimate level, compacting file 40 to
// L5 is always safe.
input_set.clear();
input_files.clear();
@@ -4256,14 +4208,14 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
comp_options, input_files, 5, vstorage_.get(), mutable_cf_options_,
mutable_db_options_, 0));
ASSERT_TRUE(comp2);
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetProximalLevel());
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetPenultimateLevel());
}
TEST_P(PerKeyPlacementCompactionPickerTest,
LastLevelOnlyConflictWithOngoingUniversal) {
// This is to test last_level only compaction still unable to do the
// proximal level compaction if there's already an ongoing compaction to
// the proximal level
// penultimate level compaction if there's already an ongoing compaction to
// the penultimate level
if (enable_per_key_placement_) {
mutable_cf_options_.preclude_last_level_data_seconds = 10000;
}
@@ -4282,7 +4234,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
Add(6, 60U, "101", "351", 60000000U);
UpdateVersionStorageInfo();
// create an ongoing compaction to L5 (proximal level)
// create an ongoing compaction to L5 (penultimate level)
CompactionOptions comp_options;
std::unordered_set<uint64_t> input_set;
input_set.insert(40);
@@ -4295,7 +4247,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
mutable_db_options_, 0));
ASSERT_TRUE(comp1);
ASSERT_EQ(comp1->GetProximalLevel(), Compaction::kInvalidLevel);
ASSERT_EQ(comp1->GetPenultimateLevel(), Compaction::kInvalidLevel);
input_set.clear();
input_files.clear();
@@ -4306,7 +4258,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
ASSERT_EQ(enable_per_key_placement_,
universal_compaction_picker.FilesRangeOverlapWithCompaction(
input_files, 6,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_.get(), mutable_cf_options_, ioptions_, 6, 6)));
if (!enable_per_key_placement_) {
@@ -4314,7 +4266,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
comp_options, input_files, 6, vstorage_.get(), mutable_cf_options_,
mutable_db_options_, 0));
ASSERT_TRUE(comp2);
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetProximalLevel());
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetPenultimateLevel());
}
}
@@ -4323,7 +4275,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
// This is similar to `LastLevelOnlyConflictWithOngoingUniversal`, the only
// change is the ongoing compaction to L5 has no overlap with the last level
// compaction, so it's safe to move data from the last level to the
// proximal level.
// penultimate level.
if (enable_per_key_placement_) {
mutable_cf_options_.preclude_last_level_data_seconds = 10000;
}
@@ -4342,7 +4294,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
Add(6, 60U, "101", "351", 60000000U);
UpdateVersionStorageInfo();
// create an ongoing compaction to L5 (proximal level)
// create an ongoing compaction to L5 (penultimate level)
CompactionOptions comp_options;
std::unordered_set<uint64_t> input_set;
input_set.insert(42);
@@ -4355,7 +4307,7 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
mutable_db_options_, 0));
ASSERT_TRUE(comp1);
ASSERT_EQ(comp1->GetProximalLevel(), Compaction::kInvalidLevel);
ASSERT_EQ(comp1->GetPenultimateLevel(), Compaction::kInvalidLevel);
input_set.clear();
input_files.clear();
@@ -4366,8 +4318,8 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
// always safe to move data up
ASSERT_FALSE(universal_compaction_picker.FilesRangeOverlapWithCompaction(
input_files, 6,
Compaction::EvaluateProximalLevel(vstorage_.get(), mutable_cf_options_,
ioptions_, 6, 6)));
Compaction::EvaluatePenultimateLevel(vstorage_.get(), mutable_cf_options_,
ioptions_, 6, 6)));
// 2 compactions can be run in parallel
std::unique_ptr<Compaction> comp2(universal_compaction_picker.CompactFiles(
@@ -4375,9 +4327,9 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
mutable_db_options_, 0));
ASSERT_TRUE(comp2);
if (enable_per_key_placement_) {
ASSERT_NE(Compaction::kInvalidLevel, comp2->GetProximalLevel());
ASSERT_NE(Compaction::kInvalidLevel, comp2->GetPenultimateLevel());
} else {
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetProximalLevel());
ASSERT_EQ(Compaction::kInvalidLevel, comp2->GetPenultimateLevel());
}
}
+196 -279
View File
@@ -38,8 +38,7 @@ class UniversalCompactionBuilder {
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, VersionStorageInfo* vstorage,
UniversalCompactionPicker* picker, LogBuffer* log_buffer,
bool require_max_output_level)
UniversalCompactionPicker* picker, LogBuffer* log_buffer)
: ioptions_(ioptions),
icmp_(icmp),
cf_name_(cf_name),
@@ -47,8 +46,7 @@ class UniversalCompactionBuilder {
mutable_db_options_(mutable_db_options),
vstorage_(vstorage),
picker_(picker),
log_buffer_(log_buffer),
require_max_output_level_(require_max_output_level) {
log_buffer_(log_buffer) {
assert(icmp_);
const auto* ucmp = icmp_->user_comparator();
assert(ucmp);
@@ -104,174 +102,6 @@ class UniversalCompactionBuilder {
bool level_has_marked_standalone_rangedel;
};
unsigned int GetMaxNumFilesToCompactBasedOnMaxReadAmp(
const int file_num_compaction_trigger, const unsigned int ratio,
int* num_sr_not_compacted_output, int* max_num_runs_output) const {
assert(num_sr_not_compacted_output);
assert(max_num_runs_output);
int max_num_runs =
mutable_cf_options_.compaction_options_universal.max_read_amp;
if (max_num_runs < 0) {
// any value < -1 is not valid
assert(max_num_runs == -1);
// By default, fall back to `level0_file_num_compaction_trigger`
max_num_runs = file_num_compaction_trigger;
} else if (max_num_runs == 0) {
if (mutable_cf_options_.compaction_options_universal.stop_style ==
kCompactionStopStyleTotalSize) {
// 0 means auto-tuning by RocksDB. We estimate max num run based on
// max_run_size, size_ratio and write buffer size:
// Assume the size of the lowest level size is equal to
// write_buffer_size. Each subsequent level is the max size without
// triggering size_ratio compaction. `max_num_runs` is the minimum
// number of levels required such that the target size of the
// largest level is at least `max_run_size_`.
max_num_runs = 1;
double cur_level_max_size =
static_cast<double>(mutable_cf_options_.write_buffer_size);
double total_run_size = 0;
while (cur_level_max_size < static_cast<double>(max_run_size_)) {
// This loop should not take too many iterations since
// cur_level_max_size at least doubles each iteration.
total_run_size += cur_level_max_size;
cur_level_max_size = (100.0 + ratio) / 100.0 * total_run_size;
++max_num_runs;
}
} else {
// TODO: implement the auto-tune logic for this stop style
max_num_runs = file_num_compaction_trigger;
}
} else {
// max_num_runs > 0, it's the limit on the number of sorted run
}
// Get the total number of sorted runs that are not being compacted
int num_sr_not_compacted = 0;
for (size_t i = 0; i < sorted_runs_.size(); i++) {
if (sorted_runs_[i].being_compacted == false &&
!sorted_runs_[i].level_has_marked_standalone_rangedel) {
num_sr_not_compacted++;
}
}
*num_sr_not_compacted_output = num_sr_not_compacted;
*max_num_runs_output = max_num_runs;
if (num_sr_not_compacted > max_num_runs) {
return num_sr_not_compacted - max_num_runs + 1;
} else {
return 0;
}
}
Compaction* MaybePickPeriodicCompaction(Compaction* const prev_picked_c) {
if (prev_picked_c != nullptr ||
vstorage_->FilesMarkedForPeriodicCompaction().empty()) {
return prev_picked_c;
}
// Always need to do a full compaction for periodic compaction.
Compaction* c = PickPeriodicCompaction();
TEST_SYNC_POINT_CALLBACK("PostPickPeriodicCompaction", c);
if (c != nullptr) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: picked for periodic compaction\n",
cf_name_.c_str());
}
return c;
}
Compaction* MaybePickSizeAmpCompaction(Compaction* const prev_picked_c,
int file_num_compaction_trigger) {
if (prev_picked_c != nullptr ||
sorted_runs_.size() <
static_cast<size_t>(file_num_compaction_trigger)) {
return prev_picked_c;
}
Compaction* c = PickCompactionToReduceSizeAmp();
if (c != nullptr) {
TEST_SYNC_POINT("PickCompactionToReduceSizeAmpReturnNonnullptr");
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: picked for size amp compaction \n",
cf_name_.c_str());
}
return c;
}
Compaction* MaybePickCompactionToReduceSortedRunsBasedFileRatio(
Compaction* const prev_picked_c, int file_num_compaction_trigger,
unsigned int ratio) {
if (prev_picked_c != nullptr ||
sorted_runs_.size() <
static_cast<size_t>(file_num_compaction_trigger)) {
return prev_picked_c;
}
Compaction* c = PickCompactionToReduceSortedRuns(ratio, UINT_MAX);
if (c != nullptr) {
TEST_SYNC_POINT("PickCompactionToReduceSortedRunsReturnNonnullptr");
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: picked for size ratio compaction to "
"reduce sorted run\n",
cf_name_.c_str());
}
return c;
}
Compaction* MaybePickCompactionToReduceSortedRuns(
Compaction* const prev_picked_c, int file_num_compaction_trigger,
unsigned int ratio) {
if (prev_picked_c != nullptr ||
sorted_runs_.size() <
static_cast<size_t>(file_num_compaction_trigger)) {
return prev_picked_c;
}
int num_sr_not_compacted = 0;
int max_num_runs = 0;
const unsigned int max_num_files_to_compact =
GetMaxNumFilesToCompactBasedOnMaxReadAmp(file_num_compaction_trigger,
ratio, &num_sr_not_compacted,
&max_num_runs);
if (max_num_files_to_compact == 0) {
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: skipping compaction to reduce sorted run, num "
"sorted runs not "
"being compacted -- %u, max num runs allowed -- %d, max_run_size "
"-- %" PRIu64 "\n",
cf_name_.c_str(), num_sr_not_compacted, max_num_runs, max_run_size_);
return nullptr;
}
Compaction* c =
PickCompactionToReduceSortedRuns(UINT_MAX, max_num_files_to_compact);
if (c != nullptr) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: picked for sorted run num compaction "
"to reduce sorted run, to "
"compact file num -- %u, max num runs allowed"
"-- %d, max_run_size -- %" PRIu64 "\n",
cf_name_.c_str(), max_num_files_to_compact, max_num_runs,
max_run_size_);
}
return c;
}
Compaction* MaybePickDeleteTriggeredCompaction(
Compaction* const prev_picked_c) {
if (prev_picked_c != nullptr) {
return prev_picked_c;
}
Compaction* c = PickDeleteTriggeredCompaction();
if (c != nullptr) {
TEST_SYNC_POINT("PickDeleteTriggeredCompactionReturnNonnullptr");
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: picked for delete triggered compaction\n",
cf_name_.c_str());
}
return c;
}
// Pick Universal compaction to limit read amplification
Compaction* PickCompactionToReduceSortedRuns(
unsigned int ratio, unsigned int max_number_of_files_to_compact);
@@ -419,13 +249,6 @@ class UniversalCompactionBuilder {
return num_l0_to_exclude;
}
bool MeetsOutputLevelRequirements(int output_level) const {
return !require_max_output_level_ ||
Compaction::OutputToNonZeroMaxOutputLevel(
output_level,
vstorage_->MaxOutputLevel(ioptions_.allow_ingest_behind));
}
const ImmutableOptions& ioptions_;
const InternalKeyComparator* icmp_;
double score_;
@@ -437,7 +260,6 @@ class UniversalCompactionBuilder {
VersionStorageInfo* vstorage_;
UniversalCompactionPicker* picker_;
LogBuffer* log_buffer_;
bool require_max_output_level_;
// Optional earliest snapshot at time of compaction picking. This is only
// provided if the column family doesn't enable user-defined timestamps.
// And this information is only passed to `Compaction` picked by deletion
@@ -466,9 +288,7 @@ class UniversalCompactionBuilder {
// and the index of the file in that level
struct InputFileInfo {
InputFileInfo() : InputFileInfo(nullptr, 0, 0) {}
InputFileInfo(FileMetaData* file_meta, size_t l, size_t i)
: f(file_meta), level(l), index(i) {}
InputFileInfo() : f(nullptr), level(0), index(0) {}
FileMetaData* f;
size_t level;
@@ -501,14 +321,22 @@ SmallestKeyHeap create_level_heap(Compaction* c, const Comparator* ucmp) {
SmallestKeyHeap smallest_key_priority_q =
SmallestKeyHeap(SmallestKeyHeapComparator(ucmp));
InputFileInfo input_file;
for (size_t l = 0; l < c->num_input_levels(); l++) {
if (c->num_input_files(l) != 0) {
if (l == 0 && c->start_level() == 0) {
for (size_t i = 0; i < c->num_input_files(0); i++) {
smallest_key_priority_q.emplace(c->input(0, i), 0, i);
input_file.f = c->input(0, i);
input_file.level = 0;
input_file.index = i;
smallest_key_priority_q.push(std::move(input_file));
}
} else {
smallest_key_priority_q.emplace(c->input(l, 0), l, 0);
input_file.f = c->input(l, 0);
input_file.level = l;
input_file.index = 0;
smallest_key_priority_q.push(std::move(input_file));
}
}
}
@@ -546,7 +374,7 @@ bool UniversalCompactionBuilder::IsInputFilesNonOverlapping(Compaction* c) {
auto comparator = icmp_->user_comparator();
int first_iter = 1;
InputFileInfo prev, curr;
InputFileInfo prev, curr, next;
SmallestKeyHeap smallest_key_priority_q =
create_level_heap(c, icmp_->user_comparator());
@@ -569,10 +397,17 @@ bool UniversalCompactionBuilder::IsInputFilesNonOverlapping(Compaction* c) {
prev = curr;
}
next.f = nullptr;
if (c->level(curr.level) != 0 &&
curr.index < c->num_input_files(curr.level) - 1) {
smallest_key_priority_q.emplace(c->input(curr.level, curr.index + 1),
curr.level, curr.index + 1);
next.f = c->input(curr.level, curr.index + 1);
next.level = curr.level;
next.index = curr.index + 1;
}
if (next.f) {
smallest_key_priority_q.push(std::move(next));
}
}
return true;
@@ -598,11 +433,10 @@ Compaction* UniversalCompactionPicker::PickCompaction(
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, bool require_max_output_level) {
LogBuffer* log_buffer) {
UniversalCompactionBuilder builder(
ioptions_, icmp_, cf_name, mutable_cf_options, mutable_db_options,
existing_snapshots, snapshot_checker, vstorage, this, log_buffer,
require_max_output_level);
existing_snapshots, snapshot_checker, vstorage, this, log_buffer);
return builder.PickCompaction();
}
@@ -733,21 +567,13 @@ bool UniversalCompactionBuilder::ShouldSkipMarkedFile(
Compaction* UniversalCompactionBuilder::PickCompaction() {
const int kLevel0 = 0;
score_ = vstorage_->CompactionScore(kLevel0);
const int max_output_level =
int max_output_level =
vstorage_->MaxOutputLevel(ioptions_.allow_ingest_behind);
const int file_num_compaction_trigger =
mutable_cf_options_.level0_file_num_compaction_trigger;
const unsigned int ratio =
mutable_cf_options_.compaction_options_universal.size_ratio;
if (max_output_level == 0 &&
!MeetsOutputLevelRequirements(0 /* output_level */)) {
return nullptr;
}
max_run_size_ = 0;
sorted_runs_ =
CalculateSortedRuns(*vstorage_, max_output_level, &max_run_size_);
int file_num_compaction_trigger =
mutable_cf_options_.level0_file_num_compaction_trigger;
if (sorted_runs_.size() == 0 ||
(vstorage_->FilesMarkedForPeriodicCompaction().empty() &&
@@ -759,7 +585,6 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
"UniversalCompactionBuilder::PickCompaction:Return", nullptr);
return nullptr;
}
VersionStorageInfo::LevelSummaryStorage tmp;
ROCKS_LOG_BUFFER_MAX_SZ(
log_buffer_, 3072,
@@ -767,14 +592,119 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
cf_name_.c_str(), sorted_runs_.size(), vstorage_->LevelSummary(&tmp));
Compaction* c = nullptr;
// Periodic compaction has higher priority than other type of compaction
// because it's a hard requirement.
if (!vstorage_->FilesMarkedForPeriodicCompaction().empty()) {
// Always need to do a full compaction for periodic compaction.
c = PickPeriodicCompaction();
TEST_SYNC_POINT_CALLBACK("PostPickPeriodicCompaction", c);
}
c = MaybePickPeriodicCompaction(c);
c = MaybePickSizeAmpCompaction(c, file_num_compaction_trigger);
c = MaybePickCompactionToReduceSortedRunsBasedFileRatio(
c, file_num_compaction_trigger, ratio);
c = MaybePickCompactionToReduceSortedRuns(c, file_num_compaction_trigger,
ratio);
c = MaybePickDeleteTriggeredCompaction(c);
if (c == nullptr &&
sorted_runs_.size() >= static_cast<size_t>(file_num_compaction_trigger)) {
// Check for size amplification.
if ((c = PickCompactionToReduceSizeAmp()) != nullptr) {
TEST_SYNC_POINT("PickCompactionToReduceSizeAmpReturnNonnullptr");
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: compacting for size amp\n",
cf_name_.c_str());
} 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;
if ((c = PickCompactionToReduceSortedRuns(ratio, UINT_MAX)) != nullptr) {
TEST_SYNC_POINT("PickCompactionToReduceSortedRunsReturnNonnullptr");
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: compacting for size ratio\n",
cf_name_.c_str());
} else {
// Size amplification and file size ratios are within configured limits.
// If max read amplification exceeds configured limits, then force
// compaction to reduce the number sorted runs without looking at file
// size ratios.
// This is guaranteed by NeedsCompaction()
assert(sorted_runs_.size() >=
static_cast<size_t>(file_num_compaction_trigger));
int max_num_runs =
mutable_cf_options_.compaction_options_universal.max_read_amp;
if (max_num_runs < 0) {
// any value < -1 is not valid
assert(max_num_runs == -1);
// By default, fall back to `level0_file_num_compaction_trigger`
max_num_runs = file_num_compaction_trigger;
} else if (max_num_runs == 0) {
if (mutable_cf_options_.compaction_options_universal.stop_style ==
kCompactionStopStyleTotalSize) {
// 0 means auto-tuning by RocksDB. We estimate max num run based on
// max_run_size, size_ratio and write buffer size:
// Assume the size of the lowest level size is equal to
// write_buffer_size. Each subsequent level is the max size without
// triggering size_ratio compaction. `max_num_runs` is the minimum
// number of levels required such that the target size of the
// largest level is at least `max_run_size_`.
max_num_runs = 1;
double cur_level_max_size =
static_cast<double>(mutable_cf_options_.write_buffer_size);
double total_run_size = 0;
while (cur_level_max_size < static_cast<double>(max_run_size_)) {
// This loop should not take too many iterations since
// cur_level_max_size at least doubles each iteration.
total_run_size += cur_level_max_size;
cur_level_max_size = (100.0 + ratio) / 100.0 * total_run_size;
++max_num_runs;
}
} else {
// TODO: implement the auto-tune logic for this stop style
max_num_runs = file_num_compaction_trigger;
}
} else {
// max_num_runs > 0, it's the limit on the number of sorted run
}
// Get the total number of sorted runs that are not being compacted
int num_sr_not_compacted = 0;
for (size_t i = 0; i < sorted_runs_.size(); i++) {
if (sorted_runs_[i].being_compacted == false &&
!sorted_runs_[i].level_has_marked_standalone_rangedel) {
num_sr_not_compacted++;
}
}
// The number of sorted runs that are not being compacted is greater
// than the maximum allowed number of sorted runs
if (num_sr_not_compacted > max_num_runs) {
unsigned int num_files = num_sr_not_compacted - max_num_runs + 1;
if ((c = PickCompactionToReduceSortedRuns(UINT_MAX, num_files)) !=
nullptr) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: compacting for file num, to "
"compact file num -- %u, max num runs allowed"
"-- %d, max_run_size -- %" PRIu64 "\n",
cf_name_.c_str(), num_files, max_num_runs,
max_run_size_);
}
} else {
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: skipping compaction for file num, num runs not "
"being compacted -- %u, max num runs allowed -- %d, max_run_size "
"-- %" PRIu64 "\n",
cf_name_.c_str(), num_sr_not_compacted, max_num_runs,
max_run_size_);
}
}
}
}
if (c == nullptr) {
if ((c = PickDeleteTriggeredCompaction()) != nullptr) {
TEST_SYNC_POINT("PickDeleteTriggeredCompactionReturnNonnullptr");
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: delete triggered compaction\n",
cf_name_.c_str());
}
}
if (c == nullptr) {
TEST_SYNC_POINT_CALLBACK(
@@ -783,7 +713,6 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
}
assert(c->output_level() <=
vstorage_->MaxOutputLevel(ioptions_.allow_ingest_behind));
assert(MeetsOutputLevelRequirements(c->output_level()));
if (mutable_cf_options_.compaction_options_universal.allow_trivial_move ==
true &&
@@ -909,16 +838,14 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
if (sr->being_compacted) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: %s"
"[%d] being compacted, skipping for compaction to "
"reduce sorted runs",
"[%d] being compacted, skipping",
cf_name_.c_str(), file_num_buf, loop);
} else if (sr->level_has_marked_standalone_rangedel) {
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: %s"
"[%d] has standalone range tombstone files marked for "
"compaction, skipping for compaction to reduce sorted runs",
cf_name_.c_str(), file_num_buf, loop);
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: %s"
"[%d] has standalone range tombstone files marked for "
"compaction, skipping",
cf_name_.c_str(), file_num_buf, loop);
}
sr = nullptr;
@@ -931,8 +858,7 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
char file_num_buf[kFormatFileNumberBufSize];
sr->Dump(file_num_buf, sizeof(file_num_buf), true);
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: Possible candidate for compaction to "
"reduce sorted runs %s[%d].",
"[%s] Universal: Possible candidate %s[%d].",
cf_name_.c_str(), file_num_buf, loop);
}
@@ -1034,10 +960,6 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
output_level = sorted_runs_[first_index_after].level - 1;
}
if (!MeetsOutputLevelRequirements(output_level)) {
return nullptr;
}
std::vector<CompactionInputFiles> inputs(max_output_level + 1);
for (size_t i = 0; i < inputs.size(); ++i) {
inputs[i].level = start_level + static_cast<int>(i);
@@ -1074,7 +996,7 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
if (output_level != 0 && picker_->FilesRangeOverlapWithCompaction(
inputs, output_level,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_, mutable_cf_options_, ioptions_,
start_level, output_level))) {
return nullptr;
@@ -1097,9 +1019,10 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
mutable_cf_options_.default_write_temperature,
/* max_subcompactions */ 0, grandparents,
/* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, compaction_reason,
/* trim_ts */ "", score_,
/* l0_files_might_overlap */ true);
/* snapshot_checker */ nullptr,
/* is manual */ false, /* trim_ts */ "", score_,
false /* deletion_compaction */,
/* l0_files_might_overlap */ true, compaction_reason);
}
// Look at overall size amplification. If size amplification
@@ -1129,19 +1052,18 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSizeAmp() {
char file_num_buf[kFormatFileNumberBufSize];
sr->Dump(file_num_buf, sizeof(file_num_buf), true);
if (sr->being_compacted) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: stopping for size amp compaction at "
"sorted run undergoing compaction: "
"%s[%" ROCKSDB_PRIszt "]",
cf_name_.c_str(), file_num_buf, start_index - 1);
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: stopping at sorted run undergoing compaction: "
"%s[%" ROCKSDB_PRIszt "]",
cf_name_.c_str(), file_num_buf, start_index - 1);
} else if (sr->level_has_marked_standalone_rangedel) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: stopping for size amp compaction at "
"sorted run that has "
"standalone range "
"tombstone files marked for compaction: "
"%s[%" ROCKSDB_PRIszt "]",
cf_name_.c_str(), file_num_buf, start_index - 1);
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: stopping at sorted run that has standalone range "
"tombstone files marked for compaction: "
"%s[%" ROCKSDB_PRIszt "]",
cf_name_.c_str(), file_num_buf, start_index - 1);
}
break;
}
@@ -1157,12 +1079,11 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSizeAmp() {
{
const size_t num_l0_to_exclude = MightExcludeNewL0sToReduceWriteStop(
num_l0_files, end_index, start_index, candidate_size);
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: Excluding for size amp compaction %" ROCKSDB_PRIszt
" latest L0 files to reduce potential write stop "
"triggered by `level0_stop_writes_trigger`",
cf_name_.c_str(), num_l0_to_exclude);
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: Excluding %" ROCKSDB_PRIszt
" latest L0 files to reduce potential write stop "
"triggered by `level0_stop_writes_trigger`",
cf_name_.c_str(), num_l0_to_exclude);
}
{
@@ -1180,18 +1101,18 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSizeAmp() {
// size amplification = percentage of additional size
if (candidate_size * 100 < ratio * base_sr_size) {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: size amp compction not needed. "
"newer-files-total-size %" PRIu64
" earliest-file-size %" PRIu64,
cf_name_.c_str(), candidate_size, base_sr_size);
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: size amp not needed. newer-files-total-size %" PRIu64
" earliest-file-size %" PRIu64,
cf_name_.c_str(), candidate_size, base_sr_size);
return nullptr;
} else {
ROCKS_LOG_BUFFER(log_buffer_,
"[%s] Universal: size amp compaction needed. "
"newer-files-total-size %" PRIu64
" earliest-file-size %" PRIu64,
cf_name_.c_str(), candidate_size, base_sr_size);
ROCKS_LOG_BUFFER(
log_buffer_,
"[%s] Universal: size amp needed. newer-files-total-size %" PRIu64
" earliest-file-size %" PRIu64,
cf_name_.c_str(), candidate_size, base_sr_size);
}
// Since incremental compaction can't include more than second last
// level, it can introduce penalty, compared to full compaction. We
@@ -1424,7 +1345,7 @@ Compaction* UniversalCompactionBuilder::PickIncrementalForReduceSizeAmp(
// intra L0 compactions outputs could have overlap
if (output_level != 0 && picker_->FilesRangeOverlapWithCompaction(
inputs, output_level,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_, mutable_cf_options_, ioptions_,
start_level, output_level))) {
return nullptr;
@@ -1446,9 +1367,10 @@ Compaction* UniversalCompactionBuilder::PickIncrementalForReduceSizeAmp(
/* max_subcompactions */ 0, /* grandparents */ {},
/* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr,
CompactionReason::kUniversalSizeAmplification,
/* trim_ts */ "", score_,
/* l0_files_might_overlap */ true);
/* is manual */ false,
/* trim_ts */ "", score_, false /* deletion_compaction */,
/* l0_files_might_overlap */ true,
CompactionReason::kUniversalSizeAmplification);
}
// Pick files marked for compaction. Typically, files are marked by
@@ -1541,10 +1463,6 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() {
}
assert(output_level <= max_output_level);
if (!MeetsOutputLevelRequirements(output_level)) {
return nullptr;
}
if (output_level != 0) {
if (start_level == 0) {
if (!picker_->GetOverlappingL0Files(vstorage_, &start_level_inputs,
@@ -1568,9 +1486,9 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() {
}
if (picker_->FilesRangeOverlapWithCompaction(
inputs, output_level,
Compaction::EvaluateProximalLevel(vstorage_, mutable_cf_options_,
ioptions_, start_level,
output_level))) {
Compaction::EvaluatePenultimateLevel(
vstorage_, mutable_cf_options_, ioptions_, start_level,
output_level))) {
return nullptr;
}
@@ -1598,9 +1516,11 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() {
GetCompressionOptions(mutable_cf_options_, vstorage_, output_level),
mutable_cf_options_.default_write_temperature,
/* max_subcompactions */ 0, grandparents, earliest_snapshot_,
snapshot_checker_, CompactionReason::kFilesMarkedForCompaction,
/* trim_ts */ "", score_,
/* l0_files_might_overlap */ true);
snapshot_checker_,
/* is manual */ false,
/* trim_ts */ "", score_, false /* deletion_compaction */,
/* l0_files_might_overlap */ true,
CompactionReason::kFilesMarkedForCompaction);
}
Compaction* UniversalCompactionBuilder::PickCompactionToOldest(
@@ -1667,14 +1587,10 @@ Compaction* UniversalCompactionBuilder::PickCompactionWithSortedRunRange(
output_level = sorted_runs_[end_index + 1].level - 1;
}
if (!MeetsOutputLevelRequirements(output_level)) {
return nullptr;
}
// intra L0 compactions outputs could have overlap
if (output_level != 0 && picker_->FilesRangeOverlapWithCompaction(
inputs, output_level,
Compaction::EvaluateProximalLevel(
Compaction::EvaluatePenultimateLevel(
vstorage_, mutable_cf_options_, ioptions_,
start_level, output_level))) {
return nullptr;
@@ -1696,9 +1612,10 @@ Compaction* UniversalCompactionBuilder::PickCompactionWithSortedRunRange(
mutable_cf_options_.default_write_temperature,
/* max_subcompactions */ 0, /* grandparents */ {},
/* earliest_snapshot */ std::nullopt,
/* snapshot_checker */ nullptr, compaction_reason,
/* trim_ts */ "", score_,
/* l0_files_might_overlap */ true);
/* snapshot_checker */ nullptr,
/* is manual */ false,
/* trim_ts */ "", score_, false /* deletion_compaction */,
/* l0_files_might_overlap */ true, compaction_reason);
}
Compaction* UniversalCompactionBuilder::PickPeriodicCompaction() {
+1 -4
View File
@@ -18,15 +18,12 @@ class UniversalCompactionPicker : public CompactionPicker {
UniversalCompactionPicker(const ImmutableOptions& ioptions,
const InternalKeyComparator* icmp)
: CompactionPicker(ioptions, icmp) {}
// If `require_max_output_level` is true, only pick compaction
// with max output level or return nullptr if no such compaction exists.
Compaction* PickCompaction(
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
const MutableDBOptions& mutable_db_options,
const std::vector<SequenceNumber>& existing_snapshots,
const SnapshotChecker* snapshot_checker, VersionStorageInfo* vstorage,
LogBuffer* log_buffer, bool require_max_output_level = false) override;
LogBuffer* log_buffer) override;
int MaxOutputLevel() const override { return NumberLevels() - 1; }
bool NeedsCompaction(const VersionStorageInfo* vstorage) const override;
+88 -272
View File
@@ -41,14 +41,17 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
}
compaction_input.cf_name = compaction->column_family_data()->GetName();
compaction_input.snapshots = job_context_->snapshot_seqs;
compaction_input.snapshots = existing_snapshots_;
compaction_input.has_begin = sub_compact->start.has_value();
compaction_input.begin =
compaction_input.has_begin ? sub_compact->start->ToString() : "";
compaction_input.has_end = sub_compact->end.has_value();
compaction_input.end =
compaction_input.has_end ? sub_compact->end->ToString() : "";
compaction_input.options_file_number = options_file_number_;
compaction_input.options_file_number =
sub_compact->compaction->input_version()
->version_set()
->options_file_number();
TEST_SYNC_POINT_CALLBACK(
"CompactionServiceJob::ProcessKeyValueCompactionWithCompactionService",
@@ -74,27 +77,15 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
compaction->column_family_data()->GetName().c_str(), job_id_,
compaction_input.output_level, input_files_oss.str().c_str());
CompactionServiceJobInfo info(
dbname_, db_id_, db_session_id_,
compaction->column_family_data()->GetID(),
compaction->column_family_data()->GetName(), GetCompactionId(sub_compact),
dbname_, db_id_, db_session_id_, GetCompactionId(sub_compact),
thread_pri_, compaction->compaction_reason(),
compaction->is_full_compaction(), compaction->is_manual_compaction(),
compaction->bottommost_level(), compaction->start_level(),
compaction->output_level());
compaction->bottommost_level());
CompactionServiceScheduleResponse response =
db_options_.compaction_service->Schedule(info, compaction_input_binary);
switch (response.status) {
case CompactionServiceJobStatus::kSuccess:
break;
case CompactionServiceJobStatus::kAborted:
sub_compact->status =
Status::Aborted("Scheduling a remote compaction job was aborted");
ROCKS_LOG_WARN(
db_options_.info_log,
"[%s] [JOB %d] Remote compaction was aborted at Schedule()",
compaction->column_family_data()->GetName().c_str(), job_id_);
return response.status;
case CompactionServiceJobStatus::kFailure:
sub_compact->status = Status::Incomplete(
"CompactionService failed to schedule a remote compaction job.");
@@ -114,9 +105,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
break;
}
std::string debug_str_before_wait =
compaction->input_version()->DebugString(/*hex=*/true);
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Waiting for remote compaction...",
compaction->column_family_data()->GetName().c_str(), job_id_);
@@ -125,17 +113,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
db_options_.compaction_service->Wait(response.scheduled_job_id,
&compaction_result_binary);
if (compaction_status != CompactionServiceJobStatus::kSuccess) {
ROCKS_LOG_ERROR(
db_options_.info_log,
"[%s] [JOB %d] Wait() status is not kSuccess. "
"\nDebugString Before Wait():\n%s"
"\nDebugString After Wait():\n%s",
compaction->column_family_data()->GetName().c_str(), job_id_,
debug_str_before_wait.c_str(),
compaction->input_version()->DebugString(/*hex=*/true).c_str());
}
if (compaction_status == CompactionServiceJobStatus::kUseLocal) {
ROCKS_LOG_INFO(
db_options_.info_log,
@@ -144,16 +121,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
return compaction_status;
}
if (compaction_status == CompactionServiceJobStatus::kAborted) {
sub_compact->status =
Status::Aborted("Waiting a remote compaction job was aborted");
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Remote compaction was aborted during Wait()",
compaction->column_family_data()->GetName().c_str(),
job_id_);
return compaction_status;
}
CompactionServiceResult compaction_result;
s = CompactionServiceResult::Read(compaction_result_binary,
&compaction_result);
@@ -210,7 +177,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
for (const auto& file : compaction_result.output_files) {
uint64_t file_num = versions_->NewFileNumber();
auto src_file = compaction_result.output_path + "/" + file.file_name;
auto tgt_file = TableFileName(compaction->immutable_options().cf_paths,
auto tgt_file = TableFileName(compaction->immutable_options()->cf_paths,
file_num, compaction->output_path_id());
s = fs_->RenameFile(src_file, tgt_file, IOOptions(), nullptr);
if (!s.ok()) {
@@ -221,24 +188,14 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
}
FileMetaData meta;
uint64_t file_size = file.file_size;
// TODO - Clean this up in the next release.
// For backward compatibility - in case the remote worker does not populate
// the file_size yet. If missing, continue to populate this from the file
// system.
if (file_size == 0) {
s = fs_->GetFileSize(tgt_file, IOOptions(), &file_size, nullptr);
}
uint64_t file_size;
s = fs_->GetFileSize(tgt_file, IOOptions(), &file_size, nullptr);
if (!s.ok()) {
sub_compact->status = s;
db_options_.compaction_service->OnInstallation(
response.scheduled_job_id, CompactionServiceJobStatus::kFailure);
return CompactionServiceJobStatus::kFailure;
}
assert(file_size > 0);
meta.fd = FileDescriptor(file_num, compaction->output_path_id(), file_size,
file.smallest_seqno, file.largest_seqno);
meta.smallest.DecodeFrom(file.smallest_internal_key);
@@ -250,35 +207,19 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
meta.file_checksum_func_name = file.file_checksum_func_name;
meta.marked_for_compaction = file.marked_for_compaction;
meta.unique_id = file.unique_id;
meta.temperature = file.file_temperature;
meta.tail_size =
FileMetaData::CalculateTailSize(file_size, file.table_properties);
auto cfd = compaction->column_family_data();
CompactionOutputs* compaction_outputs =
sub_compact->Outputs(file.is_proximal_level_output);
assert(compaction_outputs);
compaction_outputs->AddOutput(std::move(meta), cfd->internal_comparator(),
false, true, file.paranoid_hash);
compaction_outputs->UpdateTableProperties(file.table_properties);
sub_compact->Current().AddOutput(std::move(meta),
cfd->internal_comparator(), false, true,
file.paranoid_hash);
sub_compact->Current().UpdateTableProperties(file.table_properties);
}
// Set per-level stats
auto compaction_output_stats =
sub_compact->OutputStats(false /* is_proximal_level */);
assert(compaction_output_stats);
compaction_output_stats->Add(
compaction_result.internal_stats.output_level_stats);
if (compaction->SupportsPerKeyPlacement()) {
compaction_output_stats =
sub_compact->OutputStats(true /* is_proximal_level */);
assert(compaction_output_stats);
compaction_output_stats->Add(
compaction_result.internal_stats.proximal_level_stats);
}
// Set job stats
sub_compact->compaction_job_stats = compaction_result.stats;
sub_compact->Current().SetNumOutputRecords(
compaction_result.stats.num_output_records);
sub_compact->Current().SetNumOutputFiles(
compaction_result.stats.num_output_files);
sub_compact->Current().AddBytesWritten(compaction_result.bytes_written);
RecordTick(stats_, REMOTE_COMPACT_READ_BYTES, compaction_result.bytes_read);
RecordTick(stats_, REMOTE_COMPACT_WRITE_BYTES,
compaction_result.bytes_written);
@@ -298,51 +239,69 @@ void CompactionServiceCompactionJob::RecordCompactionIOStats() {
CompactionJob::RecordCompactionIOStats();
}
void CompactionServiceCompactionJob::UpdateCompactionJobStats(
const InternalStats::CompactionStats& stats) const {
compaction_job_stats_->elapsed_micros = stats.micros;
// output information only in remote compaction
compaction_job_stats_->total_output_bytes = stats.bytes_written;
compaction_job_stats_->total_output_bytes_blob = stats.bytes_written_blob;
compaction_job_stats_->num_output_records = stats.num_output_records;
compaction_job_stats_->num_output_files = stats.num_output_files;
compaction_job_stats_->num_output_files_blob = stats.num_output_files_blob;
}
CompactionServiceCompactionJob::CompactionServiceCompactionJob(
int job_id, Compaction* compaction, const ImmutableDBOptions& db_options,
const MutableDBOptions& mutable_db_options, const FileOptions& file_options,
VersionSet* versions, const std::atomic<bool>* shutting_down,
LogBuffer* log_buffer, FSDirectory* output_directory, Statistics* stats,
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
JobContext* job_context, std::shared_ptr<Cache> table_cache,
EventLogger* event_logger, const std::string& dbname,
const std::shared_ptr<IOTracer>& io_tracer,
std::vector<SequenceNumber> existing_snapshots,
std::shared_ptr<Cache> table_cache, EventLogger* event_logger,
const std::string& dbname, const std::shared_ptr<IOTracer>& io_tracer,
const std::atomic<bool>& manual_compaction_canceled,
const std::string& db_id, const std::string& db_session_id,
std::string output_path,
const CompactionServiceInput& compaction_service_input,
CompactionServiceResult* compaction_service_result)
: CompactionJob(job_id, compaction, db_options, mutable_db_options,
file_options, versions, shutting_down, log_buffer, nullptr,
output_directory, nullptr, stats, db_mutex,
db_error_handler, job_context, std::move(table_cache),
event_logger,
compaction->mutable_cf_options().paranoid_file_checks,
compaction->mutable_cf_options().report_bg_io_stats, dbname,
&(compaction_service_result->stats), Env::Priority::USER,
io_tracer, manual_compaction_canceled, db_id, db_session_id,
compaction->column_family_data()->GetFullHistoryTsLow()),
: CompactionJob(
job_id, compaction, db_options, mutable_db_options, file_options,
versions, shutting_down, log_buffer, nullptr, output_directory,
nullptr, stats, db_mutex, db_error_handler,
std::move(existing_snapshots), kMaxSequenceNumber, nullptr, nullptr,
std::move(table_cache), event_logger,
compaction->mutable_cf_options()->paranoid_file_checks,
compaction->mutable_cf_options()->report_bg_io_stats, dbname,
&(compaction_service_result->stats), Env::Priority::USER, io_tracer,
manual_compaction_canceled, db_id, db_session_id,
compaction->column_family_data()->GetFullHistoryTsLow()),
output_path_(std::move(output_path)),
compaction_input_(compaction_service_input),
compaction_result_(compaction_service_result) {}
void CompactionServiceCompactionJob::Prepare() {
std::optional<Slice> begin;
if (compaction_input_.has_begin) {
begin = compaction_input_.begin;
}
std::optional<Slice> end;
if (compaction_input_.has_end) {
end = compaction_input_.end;
}
CompactionJob::Prepare(std::make_pair(begin, end));
}
Status CompactionServiceCompactionJob::Run() {
AutoThreadOperationStageUpdater stage_updater(
ThreadStatus::STAGE_COMPACTION_RUN);
auto* c = compact_->compaction;
assert(c->column_family_data() != nullptr);
const VersionStorageInfo* storage_info = c->input_version()->storage_info();
assert(storage_info);
assert(storage_info->NumLevelFiles(compact_->compaction->level()) > 0);
write_hint_ = storage_info->CalculateSSTWriteHint(c->output_level());
bottommost_level_ = c->bottommost_level();
Slice begin = compaction_input_.begin;
Slice end = compaction_input_.end;
compact_->sub_compact_states.emplace_back(
c,
compaction_input_.has_begin ? std::optional<Slice>(begin)
: std::optional<Slice>(),
compaction_input_.has_end ? std::optional<Slice>(end)
: std::optional<Slice>(),
/*sub_job_id*/ 0);
log_buffer_->FlushBufferToLog();
LogCompaction();
@@ -358,14 +317,15 @@ Status CompactionServiceCompactionJob::Run() {
ProcessKeyValueCompaction(sub_compact);
uint64_t elapsed_micros = db_options_.clock->NowMicros() - start_micros;
internal_stats_.SetMicros(elapsed_micros);
internal_stats_.AddCpuMicros(elapsed_micros);
compaction_stats_.stats.micros =
db_options_.clock->NowMicros() - start_micros;
compaction_stats_.stats.cpu_micros =
sub_compact->compaction_job_stats.cpu_micros;
RecordTimeToHistogram(stats_, COMPACTION_TIME,
internal_stats_.output_level_stats.micros);
compaction_stats_.stats.micros);
RecordTimeToHistogram(stats_, COMPACTION_CPU_TIME,
internal_stats_.output_level_stats.cpu_micros);
compaction_stats_.stats.cpu_micros);
Status status = sub_compact->status;
IOStatus io_s = sub_compact->io_status;
@@ -395,45 +355,38 @@ Status CompactionServiceCompactionJob::Run() {
// Build Compaction Job Stats
// 1. Aggregate internal stats and job stats for all subcompactions
// internal stats: sub_compact.proximal_level_outputs_.stats and
// sub_compact.compaction_outputs_.stats into
// internal_stats_.output_level_stats and
// internal_stats_.proximal_level_stats
// job-level stats: sub_compact.compaction_job_stats into compact.job_stats_
//
// For remote compaction, there's only one subcompaction.
compact_->AggregateCompactionStats(internal_stats_, *job_stats_);
// 1. Aggregate CompactionOutputStats into Internal Compaction Stats
// (compaction_stats_) and aggregate Compaction Job Stats
// (compaction_job_stats_) from the sub compactions
compact_->AggregateCompactionStats(compaction_stats_, *compaction_job_stats_);
// 2. Update job-level output stats with the aggregated internal_stats_
// Please note that input stats will be updated by primary host when all
// subcompactions are finished
UpdateCompactionJobOutputStats(internal_stats_);
// and set fields that are not propagated as part of the update
// 2. Update the Output information in the Compaction Job Stats with
// aggregated Internal Compaction Stats.
UpdateCompactionJobStats(compaction_stats_.stats);
// 3. Set fields that are not propagated as part of aggregations above
compaction_result_->stats.is_manual_compaction = c->is_manual_compaction();
compaction_result_->stats.is_full_compaction = c->is_full_compaction();
compaction_result_->stats.is_remote_compaction = true;
// 3. Update IO Stats that are not part of the the update above
// (bytes_read, bytes_written)
// 4. Update IO Stats that are not part of the aggregations above (bytes_read,
// bytes_written)
RecordCompactionIOStats();
// Build Output
compaction_result_->internal_stats = internal_stats_;
compaction_result_->output_level = compact_->compaction->output_level();
compaction_result_->output_path = output_path_;
if (status.ok()) {
for (const auto& output_file : sub_compact->GetOutputs()) {
auto& meta = output_file.meta;
compaction_result_->output_files.emplace_back(
MakeTableFileName(meta.fd.GetNumber()), meta.fd.GetFileSize(),
meta.fd.smallest_seqno, meta.fd.largest_seqno,
meta.smallest.Encode().ToString(), meta.largest.Encode().ToString(),
meta.oldest_ancester_time, meta.file_creation_time, meta.epoch_number,
meta.file_checksum, meta.file_checksum_func_name,
output_file.validator.GetHash(), meta.marked_for_compaction,
meta.unique_id, *output_file.table_properties,
output_file.is_proximal_level, meta.temperature);
MakeTableFileName(meta.fd.GetNumber()), meta.fd.smallest_seqno,
meta.fd.largest_seqno, meta.smallest.Encode().ToString(),
meta.largest.Encode().ToString(), meta.oldest_ancester_time,
meta.file_creation_time, meta.epoch_number, meta.file_checksum,
meta.file_checksum_func_name, output_file.validator.GetHash(),
meta.marked_for_compaction, meta.unique_id,
*output_file.table_properties);
}
}
@@ -533,10 +486,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
{offsetof(struct CompactionServiceOutputFile, file_name),
OptionType::kEncodedString, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"file_size",
{offsetof(struct CompactionServiceOutputFile, file_size),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"smallest_seqno",
{offsetof(struct CompactionServiceOutputFile, smallest_seqno),
OptionType::kUInt64T, OptionVerificationType::kNormal,
@@ -609,16 +558,7 @@ static std::unordered_map<std::string, OptionTypeInfo>
const auto this_one = static_cast<const TableProperties*>(addr1);
const auto that_one = static_cast<const TableProperties*>(addr2);
return this_one->AreEqual(opts, that_one, mismatch);
}}},
{"is_proximal_level_output",
{offsetof(struct CompactionServiceOutputFile,
is_proximal_level_output),
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"file_temperature",
{offsetof(struct CompactionServiceOutputFile, file_temperature),
OptionType::kTemperature, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}}};
}}}};
static std::unordered_map<std::string, OptionTypeInfo>
compaction_job_stats_type_info = {
@@ -743,125 +683,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
OptionTypeFlags::kNone}},
};
static std::unordered_map<std::string, OptionTypeInfo>
compaction_stats_type_info = {
{"micros",
{offsetof(struct InternalStats::CompactionStats, micros),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"cpu_micros",
{offsetof(struct InternalStats::CompactionStats, cpu_micros),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_read_non_output_levels",
{offsetof(struct InternalStats::CompactionStats,
bytes_read_non_output_levels),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_read_output_level",
{offsetof(struct InternalStats::CompactionStats,
bytes_read_output_level),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_skipped_non_output_levels",
{offsetof(struct InternalStats::CompactionStats,
bytes_skipped_non_output_levels),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_skipped_output_level",
{offsetof(struct InternalStats::CompactionStats,
bytes_skipped_output_level),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_read_blob",
{offsetof(struct InternalStats::CompactionStats, bytes_read_blob),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_written",
{offsetof(struct InternalStats::CompactionStats, bytes_written),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_written_blob",
{offsetof(struct InternalStats::CompactionStats, bytes_written_blob),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"bytes_moved",
{offsetof(struct InternalStats::CompactionStats, bytes_moved),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_input_files_in_non_output_levels",
{offsetof(struct InternalStats::CompactionStats,
num_input_files_in_non_output_levels),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_input_files_in_output_level",
{offsetof(struct InternalStats::CompactionStats,
num_input_files_in_output_level),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_filtered_input_files_in_non_output_levels",
{offsetof(struct InternalStats::CompactionStats,
num_filtered_input_files_in_non_output_levels),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_filtered_input_files_in_output_level",
{offsetof(struct InternalStats::CompactionStats,
num_filtered_input_files_in_output_level),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_output_files",
{offsetof(struct InternalStats::CompactionStats, num_output_files),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_output_files_blob",
{offsetof(struct InternalStats::CompactionStats,
num_output_files_blob),
OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_input_records",
{offsetof(struct InternalStats::CompactionStats, num_input_records),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_dropped_records",
{offsetof(struct InternalStats::CompactionStats, num_dropped_records),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"num_output_records",
{offsetof(struct InternalStats::CompactionStats, num_output_records),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"count",
{offsetof(struct InternalStats::CompactionStats, count),
OptionType::kUInt64T, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"counts", OptionTypeInfo::Array<
int, static_cast<int>(CompactionReason::kNumOfReasons)>(
offsetof(struct InternalStats::CompactionStats, counts),
OptionVerificationType::kNormal, OptionTypeFlags::kNone,
{0, OptionType::kInt})},
};
static std::unordered_map<std::string, OptionTypeInfo>
compaction_internal_stats_type_info = {
{"output_level_stats",
OptionTypeInfo::Struct(
"output_level_stats", &compaction_stats_type_info,
offsetof(struct InternalStats::CompactionStatsFull,
output_level_stats),
OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
{"has_proximal_level_output",
{offsetof(struct InternalStats::CompactionStatsFull,
has_proximal_level_output),
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
{"proximal_level_stats",
OptionTypeInfo::Struct(
"proximal_level_stats", &compaction_stats_type_info,
offsetof(struct InternalStats::CompactionStatsFull,
proximal_level_stats),
OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
};
namespace {
// this is a helper struct to serialize and deserialize class Status, because
// Status's members are not public.
@@ -968,11 +789,6 @@ static std::unordered_map<std::string, OptionTypeInfo> cs_result_type_info = {
"stats", &compaction_job_stats_type_info,
offsetof(struct CompactionServiceResult, stats),
OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
{"internal_stats",
OptionTypeInfo::Struct(
"internal_stats", &compaction_internal_stats_type_info,
offsetof(struct CompactionServiceResult, internal_stats),
OptionVerificationType::kNormal, OptionTypeFlags::kNone)},
};
Status CompactionServiceInput::Read(const std::string& data_str,
+14 -464
View File
@@ -7,7 +7,6 @@
#include "port/stack_trace.h"
#include "rocksdb/utilities/options_util.h"
#include "table/unique_id_impl.h"
#include "utilities/merge_operators/string_append/stringappend.h"
namespace ROCKSDB_NAMESPACE {
@@ -22,10 +21,10 @@ class MyTestCompactionService : public CompactionService {
: db_path_(std::move(db_path)),
options_(options),
statistics_(statistics),
start_info_("na", "na", "na", 0, "na", 0, Env::TOTAL,
CompactionReason::kUnknown, false, false, false, -1, -1),
wait_info_("na", "na", "na", 0, "na", 0, Env::TOTAL,
CompactionReason::kUnknown, false, false, false, -1, -1),
start_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false),
wait_info_("na", "na", "na", 0, Env::TOTAL, CompactionReason::kUnknown,
false, false, false),
listeners_(listeners),
table_properties_collector_factories_(
std::move(table_properties_collector_factories)) {}
@@ -85,7 +84,6 @@ class MyTestCompactionService : public CompactionService {
options_override.table_factory = options_.table_factory;
options_override.sst_partitioner_factory = options_.sst_partitioner_factory;
options_override.statistics = statistics_;
options_override.info_log = options_.info_log;
if (!listeners_.empty()) {
options_override.listeners = listeners_;
}
@@ -116,8 +114,6 @@ class MyTestCompactionService : public CompactionService {
}
}
void CancelAwaitingJobs() override { canceled_ = true; }
void OnInstallation(const std::string& /*scheduled_job_id*/,
CompactionServiceJobStatus status) override {
final_updated_status_ = status;
@@ -150,7 +146,6 @@ class MyTestCompactionService : public CompactionService {
}
void SetCanceled(bool canceled) { canceled_ = canceled; }
bool GetCanceled() { return canceled_; }
void GetResult(CompactionServiceResult* deserialized) {
CompactionServiceResult::Read(result_, deserialized).PermitUncheckedError();
@@ -199,15 +194,12 @@ class CompactionServiceTest : public DBTestBase {
options->statistics = primary_statistics_;
compactor_statistics_ = CreateDBStatistics();
auto my_cs = std::make_shared<MyTestCompactionService>(
compaction_service_ = std::make_shared<MyTestCompactionService>(
dbname_, *options, compactor_statistics_, remote_listeners,
remote_table_properties_collector_factories);
compaction_service_ = my_cs;
options->compaction_service = compaction_service_;
DestroyAndReopen(*options);
CreateAndReopenWithCF({"cf_1", "cf_2", "cf_3"}, *options);
my_cs->SetCanceled(false);
}
Statistics* GetCompactorStatistics() { return compactor_statistics_.get(); }
@@ -279,17 +271,8 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
Statistics* primary_statistics = GetPrimaryStatistics();
Statistics* compactor_statistics = GetCompactorStatistics();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"BlockBasedTable::PrefetchTail::TaiSizeNotRecorded",
[&](void* /* arg */) {
// Trigger assertion to verify precise tail prefetch size calculation
assert(false);
});
SyncPoint::GetInstance()->EnableProcessing();
GenerateTestData();
ASSERT_OK(dbfull()->TEST_WaitForCompact());
SyncPoint::GetInstance()->DisableProcessing();
VerifyTestData();
auto my_cs = GetCompactionService();
@@ -356,8 +339,6 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
assert(*id != kNullUniqueId64x2);
verify_passed++;
});
Close();
my_cs->SetCanceled(false);
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "cf_1", "cf_2", "cf_3"},
options);
ASSERT_GT(verify_passed, 0);
@@ -368,12 +349,11 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
} else {
ASSERT_OK(result.status);
}
ASSERT_GE(result.internal_stats.output_level_stats.micros, 1);
ASSERT_GE(result.internal_stats.output_level_stats.cpu_micros, 1);
ASSERT_GE(result.stats.elapsed_micros, 1);
ASSERT_GE(result.stats.cpu_micros, 1);
ASSERT_EQ(20, result.internal_stats.output_level_stats.num_output_records);
ASSERT_EQ(result.output_files.size(),
result.internal_stats.output_level_stats.num_output_files);
ASSERT_EQ(20, result.stats.num_output_records);
ASSERT_EQ(result.output_files.size(), result.stats.num_output_files);
uint64_t total_size = 0;
for (auto output_file : result.output_files) {
@@ -384,14 +364,13 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
ASSERT_GT(file_size, 0);
total_size += file_size;
}
ASSERT_EQ(total_size, result.internal_stats.TotalBytesWritten());
ASSERT_EQ(total_size, result.stats.total_output_bytes);
ASSERT_TRUE(result.stats.is_remote_compaction);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_FALSE(result.stats.is_full_compaction);
Close();
SyncPoint::GetInstance()->DisableProcessing();
}
TEST_F(CompactionServiceTest, ManualCompaction) {
@@ -435,121 +414,6 @@ TEST_F(CompactionServiceTest, ManualCompaction) {
ASSERT_OK(result.status);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_TRUE(result.stats.is_remote_compaction);
auto info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(0, info.cf_id);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(0, info.cf_id);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
// Test non-default CF
ASSERT_OK(
db_->CompactRange(CompactRangeOptions(), handles_[1], nullptr, nullptr));
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_TRUE(result.stats.is_remote_compaction);
info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(handles_[1]->GetID(), info.cf_id);
ASSERT_EQ(handles_[1]->GetName(), info.cf_name);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(handles_[1]->GetID(), info.cf_id);
ASSERT_EQ(handles_[1]->GetName(), info.cf_name);
}
TEST_F(CompactionServiceTest, StandaloneDeleteRangeTombstoneOptimization) {
Options options = CurrentOptions();
options.compaction_style = CompactionStyle::kCompactionStyleUniversal;
ReopenWithCompactionService(&options);
size_t num_files_after_filtered = 0;
SyncPoint::GetInstance()->SetCallBack(
"VersionSet::MakeInputIterator:NewCompactionMergingIterator",
[&](void* arg) {
num_files_after_filtered = *static_cast<size_t*>(arg);
});
SyncPoint::GetInstance()->EnableProcessing();
std::vector<std::string> files;
{
// Writes first version of data in range partitioned files.
SstFileWriter sst_file_writer(EnvOptions(), options);
std::string file1 = dbname_ + "file1.sst";
ASSERT_OK(sst_file_writer.Open(file1));
ASSERT_OK(sst_file_writer.Put("a", "a1"));
ASSERT_OK(sst_file_writer.Put("b", "b1"));
ExternalSstFileInfo file1_info;
ASSERT_OK(sst_file_writer.Finish(&file1_info));
files.push_back(std::move(file1));
std::string file2 = dbname_ + "file2.sst";
ASSERT_OK(sst_file_writer.Open(file2));
ASSERT_OK(sst_file_writer.Put("x", "x1"));
ASSERT_OK(sst_file_writer.Put("y", "y1"));
ExternalSstFileInfo file2_info;
ASSERT_OK(sst_file_writer.Finish(&file2_info));
files.push_back(std::move(file2));
}
IngestExternalFileOptions ifo;
ASSERT_OK(db_->IngestExternalFile(files, ifo));
ASSERT_EQ(Get("a"), "a1");
ASSERT_EQ(Get("b"), "b1");
ASSERT_EQ(Get("x"), "x1");
ASSERT_EQ(Get("y"), "y1");
ASSERT_EQ(2, NumTableFilesAtLevel(6));
auto my_cs = GetCompactionService();
uint64_t comp_num = my_cs->GetCompactionNum();
{
// Atomically delete old version of data with one range delete file.
// And a new batch of range partitioned files with new version of data.
files.clear();
SstFileWriter sst_file_writer(EnvOptions(), options);
std::string file2 = dbname_ + "file2.sst";
ASSERT_OK(sst_file_writer.Open(file2));
ASSERT_OK(sst_file_writer.DeleteRange("a", "z"));
ExternalSstFileInfo file2_info;
ASSERT_OK(sst_file_writer.Finish(&file2_info));
files.push_back(std::move(file2));
std::string file3 = dbname_ + "file3.sst";
ASSERT_OK(sst_file_writer.Open(file3));
ASSERT_OK(sst_file_writer.Put("a", "a2"));
ASSERT_OK(sst_file_writer.Put("b", "b2"));
ExternalSstFileInfo file3_info;
ASSERT_OK(sst_file_writer.Finish(&file3_info));
files.push_back(std::move(file3));
std::string file4 = dbname_ + "file4.sst";
ASSERT_OK(sst_file_writer.Open(file4));
ASSERT_OK(sst_file_writer.Put("x", "x2"));
ASSERT_OK(sst_file_writer.Put("y", "y2"));
ExternalSstFileInfo file4_info;
ASSERT_OK(sst_file_writer.Finish(&file4_info));
files.push_back(std::move(file4));
}
ASSERT_OK(db_->IngestExternalFile(files, ifo));
ASSERT_OK(db_->WaitForCompact(WaitForCompactOptions()));
ASSERT_GE(my_cs->GetCompactionNum(), comp_num + 1);
CompactionServiceResult result;
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_TRUE(result.stats.is_manual_compaction);
ASSERT_TRUE(result.stats.is_remote_compaction);
ASSERT_EQ(num_files_after_filtered, 1);
Close();
SyncPoint::GetInstance()->DisableProcessing();
}
TEST_F(CompactionServiceTest, CompactionOutputFileIOError) {
@@ -623,7 +487,7 @@ TEST_F(CompactionServiceTest, PreservedOptionsLocalCompaction) {
ASSERT_TRUE(s.IsNotFound());
// Should be old value
ASSERT_EQ(2, compaction->mutable_cf_options()
.level0_file_num_compaction_trigger);
->level0_file_num_compaction_trigger);
ASSERT_TRUE(dbfull()->min_options_file_numbers_.empty());
});
@@ -709,7 +573,7 @@ TEST_F(CompactionServiceTest, PreservedOptionsRemoteCompaction) {
"CompactionJob::ProcessKeyValueCompaction()::Processing", [&](void* arg) {
auto compaction = static_cast<Compaction*>(arg);
ASSERT_EQ(2, compaction->mutable_cf_options()
.level0_file_num_compaction_trigger);
->level0_file_num_compaction_trigger);
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
@@ -844,119 +708,6 @@ TEST_F(CompactionServiceTest, VerifyStatsLocalFallback) {
VerifyTestData();
}
TEST_F(CompactionServiceTest, VerifyInputRecordCount) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
ReopenWithCompactionService(&options);
GenerateTestData();
auto my_cs = GetCompactionService();
std::string start_str = Key(15);
std::string end_str = Key(45);
Slice start(start_str);
Slice end(end_str);
uint64_t comp_num = my_cs->GetCompactionNum();
// Only iterator through 10 keys and force compaction to finish.
int num_iter = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"CompactionJob::ProcessKeyValueCompaction()::stop", [&](void* stop_ptr) {
num_iter++;
if (num_iter == 10) {
*(bool*)stop_ptr = true;
}
});
SyncPoint::GetInstance()->EnableProcessing();
// CompactRange() should fail
Status s = db_->CompactRange(CompactRangeOptions(), &start, &end);
ASSERT_NOK(s);
ASSERT_TRUE(s.IsCorruption());
const char* expected_message =
"Compaction number of input keys does not match number of keys "
"processed.";
ASSERT_TRUE(std::strstr(s.getState(), expected_message));
ASSERT_GE(my_cs->GetCompactionNum(), comp_num + 1);
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_F(CompactionServiceTest, EmptyResult) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
ReopenWithCompactionService(&options);
GenerateTestData();
auto my_cs = GetCompactionService();
uint64_t comp_num = my_cs->GetCompactionNum();
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
ASSERT_GE(my_cs->GetCompactionNum(), comp_num + 1);
// Delete range to cover entire range
ASSERT_OK(db_->DeleteRange(WriteOptions(), "key", "keyz"));
ASSERT_OK(Flush());
// In this unit test, both remote compaction and primary db instance are
// running in the same process, so NewFileNumber will never have a collision.
// In the real-world remote compactions, when the compaction is indeed running
// in another process, this is not going to be the case.
// To simulate the SST file with the same name created in the tmp directory,
// override the file number in remote compaction to re-use old SST file
// number.
bool need_to_override_file_number = false;
SyncPoint::GetInstance()->SetCallBack(
"DBImplSecondary::OpenAndCompact::BeforeLoadingOptions:0",
[&](void*) { need_to_override_file_number = true; });
SyncPoint::GetInstance()->SetCallBack(
"CompactionJob::OpenCompactionOutputFile::NewFileNumber",
[&](void* file_number) {
if (need_to_override_file_number) {
auto n = static_cast<uint64_t*>(file_number);
ColumnFamilyMetaData cf_meta;
db_->GetColumnFamilyMetaData(&cf_meta);
for (const auto& level : cf_meta.levels) {
for (const auto& file : level.files) {
// Use one of the existing file name
*n = test::GetFileNumber(file.name);
need_to_override_file_number = false;
return;
}
}
}
});
// Inject failure, so that the remote compaction fails after
// ProcessKeyValueCompaction()
SyncPoint::GetInstance()->SetCallBack(
"DBImplSecondary::CompactWithoutInstallation::End", [&](void* status) {
// override job status
auto s = static_cast<Status*>(status);
*s = Status::Aborted("MyTestCompactionService failed to compact!");
});
SyncPoint::GetInstance()->EnableProcessing();
// Compaction should fail and SST files in the primary db should exist
{
ASSERT_NOK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
ColumnFamilyMetaData meta;
db_->GetColumnFamilyMetaData(&meta);
for (const auto& level : meta.levels) {
for (const auto& file : level.files) {
std::string fname = file.db_path + "/" + file.name;
ASSERT_OK(db_->GetEnv()->FileExists(fname));
}
}
}
Close();
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_F(CompactionServiceTest, CorruptedOutput) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
@@ -1090,12 +841,6 @@ TEST_F(CompactionServiceTest, TruncatedOutput) {
Slice end(end_str);
uint64_t comp_num = my_cs->GetCompactionNum();
// Skip calculating tail size to avoid crashing due to truncated file size
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"FileMetaData::CalculateTailSize", [&](void* arg) {
bool* skip = static_cast<bool*>(arg);
*skip = true;
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"CompactionServiceCompactionJob::Run:0", [&](void* arg) {
CompactionServiceResult* compaction_result =
@@ -1112,7 +857,7 @@ TEST_F(CompactionServiceTest, TruncatedOutput) {
ASSERT_OK(s);
ASSERT_GT(file_size, 0);
ASSERT_OK(test::TruncateFile(env_, file_name, file_size / 4));
ASSERT_OK(test::TruncateFile(env_, file_name, file_size / 2));
}
});
SyncPoint::GetInstance()->EnableProcessing();
@@ -1251,41 +996,6 @@ TEST_F(CompactionServiceTest, CancelCompactionOnRemoteSide) {
VerifyTestData();
}
TEST_F(CompactionServiceTest, CancelCompactionOnPrimarySide) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
ReopenWithCompactionService(&options);
GenerateTestData();
auto my_cs = GetCompactionService();
std::string start_str = Key(15);
std::string end_str = Key(45);
Slice start(start_str);
Slice end(end_str);
uint64_t comp_num = my_cs->GetCompactionNum();
ReopenWithCompactionService(&options);
GenerateTestData();
my_cs = GetCompactionService();
// Primary DB calls CancelAllBackgroundWork() while the compaction is running
SyncPoint::GetInstance()->SetCallBack(
"CompactionJob::Run():Inprogress",
[&](void* /*arg*/) { CancelAllBackgroundWork(db_, false /*wait*/); });
SyncPoint::GetInstance()->EnableProcessing();
Status s = db_->CompactRange(CompactRangeOptions(), &start, &end);
ASSERT_TRUE(s.IsIncomplete());
// Check canceled_ was set to true by CancelAwaitingJobs()
ASSERT_TRUE(my_cs->GetCanceled());
// compaction number is not increased
ASSERT_GE(my_cs->GetCompactionNum(), comp_num);
}
TEST_F(CompactionServiceTest, FailedToStart) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
@@ -1387,32 +1097,6 @@ TEST_F(CompactionServiceTest, CompactionFilter) {
ASSERT_GE(my_cs->GetCompactionNum(), 1);
}
TEST_F(CompactionServiceTest, MergeOperator) {
Options options = CurrentOptions();
options.merge_operator.reset(new StringAppendOperator(','));
ReopenWithCompactionService(&options);
GenerateTestData();
ASSERT_OK(dbfull()->TEST_WaitForCompact());
for (int i = 0; i < 200; i++) {
ASSERT_OK(db_->Merge(WriteOptions(), Key(i),
"merge_op_append_" + std::to_string(i)));
}
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
// verify result
for (int i = 0; i < 200; i++) {
auto result = Get(Key(i));
if (i % 2) {
ASSERT_EQ(result, "value" + std::to_string(i) + ",merge_op_append_" +
std::to_string(i));
} else {
ASSERT_EQ(result, "value_new" + std::to_string(i) + ",merge_op_append_" +
std::to_string(i));
}
}
auto my_cs = GetCompactionService();
ASSERT_GE(my_cs->GetCompactionNum(), 1);
}
TEST_F(CompactionServiceTest, Snapshot) {
Options options = CurrentOptions();
ReopenWithCompactionService(&options);
@@ -1434,81 +1118,6 @@ TEST_F(CompactionServiceTest, Snapshot) {
db_->ReleaseSnapshot(s1);
}
TEST_F(CompactionServiceTest, PrecludeLastLevel) {
const int kNumTrigger = 4;
const int kNumLevels = 7;
const int kNumKeys = 100;
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleUniversal;
options.last_level_temperature = Temperature::kCold;
options.level0_file_num_compaction_trigger = 4;
options.max_subcompactions = 10;
options.num_levels = kNumLevels;
ReopenWithCompactionService(&options);
// Alternate for comparison: DestroyAndReopen(options);
// This is simpler than setting up mock time to make the user option work,
// but is not as direct as testing with preclude option itself.
SyncPoint::GetInstance()->SetCallBack(
"Compaction::SupportsPerKeyPlacement:Enabled",
[&](void* arg) { *static_cast<bool*>(arg) = true; });
SyncPoint::GetInstance()->SetCallBack(
"CompactionJob::PrepareTimes():preclude_last_level_min_seqno",
[&](void* arg) { *static_cast<SequenceNumber*>(arg) = 100; });
SyncPoint::GetInstance()->EnableProcessing();
for (int i = 0; i < kNumTrigger; i++) {
for (int j = 0; j < kNumKeys; j++) {
ASSERT_OK(Put(Key(j * kNumTrigger + i), "v" + std::to_string(i)));
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// Data split between proximal (kUnknown) and last (kCold) levels
ASSERT_EQ("0,0,0,0,0,1,1", FilesPerLevel());
ASSERT_GT(GetSstSizeHelper(Temperature::kUnknown), 0);
ASSERT_GT(GetSstSizeHelper(Temperature::kCold), 0);
// TODO: Check FileSystem temperatures with FileTemperatureTestFS
for (int i = 0; i < kNumTrigger; i++) {
for (int j = 0; j < kNumKeys; j++) {
ASSERT_EQ(Get(Key(j * kNumTrigger + i)), "v" + std::to_string(i));
}
}
// Verify Output Stats
auto my_cs = GetCompactionService();
{
CompactionServiceResult result;
my_cs->GetResult(&result);
ASSERT_OK(result.status);
ASSERT_GT(result.internal_stats.output_level_stats.cpu_micros, 0);
ASSERT_GT(result.internal_stats.output_level_stats.micros, 0);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_records +
result.internal_stats.proximal_level_stats.num_output_records,
kNumTrigger * kNumKeys);
ASSERT_EQ(result.internal_stats.output_level_stats.num_output_files +
result.internal_stats.proximal_level_stats.num_output_files,
2);
CompactionServiceJobInfo info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(kNumLevels - 1, info.output_level);
}
SyncPoint::GetInstance()->DisableProcessing();
// Disable Preclude feature and run full compaction to the bottommost level
{
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
CompactionServiceJobInfo info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(kNumLevels - 2, info.base_input_level);
ASSERT_EQ(kNumLevels - 1, info.output_level);
}
}
TEST_F(CompactionServiceTest, ConcurrentCompaction) {
Options options = CurrentOptions();
options.level0_file_num_compaction_trigger = 100;
@@ -1576,17 +1185,12 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(1, info.base_input_level);
ASSERT_EQ(2, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(Env::USER, info.priority);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(1, info.base_input_level);
ASSERT_EQ(2, info.output_level);
ASSERT_EQ(kDefaultColumnFamilyName, info.cf_name);
// Test priority BOTTOM
env_->SetBackgroundThreads(1, Env::BOTTOM);
@@ -1618,24 +1222,18 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(Env::BOTTOM, info.priority);
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(db_->NumberLevels() - 1, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(Env::BOTTOM, info.priority);
ASSERT_EQ(CompactionReason::kLevelL0FilesNum, info.compaction_reason);
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(0, info.base_input_level);
ASSERT_EQ(db_->NumberLevels() - 1, info.output_level);
// Test Non-Bottommost Level
options.num_levels = 4;
ReopenWithCompactionService(&options);
my_cs =
static_cast_with_check<MyTestCompactionService>(GetCompactionService());
int compaction_num = my_cs->GetCompactionNum();
ASSERT_EQ(0, compaction_num);
for (int i = 0; i < options.level0_file_num_compaction_trigger; i++) {
for (int j = 0; j < 10; j++) {
@@ -1644,22 +1242,16 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// This is trivial move. Done locally.
ASSERT_EQ(0, my_cs->GetCompactionNum());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
info = my_cs->GetCompactionInfoForStart();
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(false, info.bottommost_level);
ASSERT_EQ(-1, info.base_input_level);
ASSERT_EQ(-1, info.output_level);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(false, info.is_manual_compaction);
ASSERT_EQ(false, info.is_full_compaction);
ASSERT_EQ(false, info.bottommost_level);
ASSERT_EQ(-1, info.base_input_level);
ASSERT_EQ(-1, info.output_level);
// Test Full Compaction + Bottommost Level
options.num_levels = 6;
@@ -1674,10 +1266,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
}
ASSERT_OK(Flush());
}
MoveFilesToLevel(options.num_levels - 1);
// Force final level compaction
// base_input_level == output_level == last_level
CompactRangeOptions cro;
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
@@ -1689,15 +1278,10 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
info = my_cs->GetCompactionInfoForWait();
ASSERT_EQ(options.num_levels - 1, info.base_input_level);
ASSERT_EQ(options.num_levels - 1, info.output_level);
ASSERT_EQ(true, info.is_manual_compaction);
ASSERT_EQ(true, info.is_full_compaction);
ASSERT_EQ(true, info.bottommost_level);
ASSERT_EQ(CompactionReason::kManualCompaction, info.compaction_reason);
ASSERT_EQ(options.num_levels - 1, info.base_input_level);
ASSERT_EQ(options.num_levels - 1, info.output_level);
ASSERT_EQ("0,0,0,0,0,1", FilesPerLevel());
}
TEST_F(CompactionServiceTest, FallbackLocalAuto) {
@@ -1787,40 +1371,6 @@ TEST_F(CompactionServiceTest, FallbackLocalManual) {
VerifyTestData();
}
TEST_F(CompactionServiceTest, AbortedWhileWait) {
Options options = CurrentOptions();
options.disable_auto_compactions = true;
ReopenWithCompactionService(&options);
GenerateTestData();
VerifyTestData();
auto my_cs = GetCompactionService();
Statistics* compactor_statistics = GetCompactorStatistics();
Statistics* primary_statistics = GetPrimaryStatistics();
my_cs->ResetOverride();
std::string start_str = Key(15);
std::string end_str = Key(45);
Slice start(start_str);
Slice end(end_str);
// Override Wait() result with kAborted
my_cs->OverrideWaitStatus(CompactionServiceJobStatus::kAborted);
start_str = Key(120);
start = start_str;
Status s = db_->CompactRange(CompactRangeOptions(), &start, nullptr);
ASSERT_NOK(s);
ASSERT_TRUE(s.IsAborted());
// no remote compaction is run
ASSERT_EQ(my_cs->GetCompactionNum(), 0);
// make sure the compaction statistics is not recorded any side
ASSERT_EQ(primary_statistics->getTickerCount(COMPACT_WRITE_BYTES), 0);
ASSERT_EQ(primary_statistics->getTickerCount(REMOTE_COMPACT_WRITE_BYTES), 0);
ASSERT_EQ(compactor_statistics->getTickerCount(COMPACT_WRITE_BYTES), 0);
}
TEST_F(CompactionServiceTest, RemoteEventListener) {
class RemoteEventListenerTest : public EventListener {
public:
+4 -4
View File
@@ -36,11 +36,11 @@ Slice CompactionState::LargestUserKey() {
}
void CompactionState::AggregateCompactionStats(
InternalStats::CompactionStatsFull& internal_stats,
CompactionJobStats& job_stats) {
InternalStats::CompactionStatsFull& compaction_stats,
CompactionJobStats& compaction_job_stats) {
for (const auto& sc : sub_compact_states) {
sc.AggregateCompactionOutputStats(internal_stats);
job_stats.Add(sc.compaction_job_stats);
sc.AggregateCompactionOutputStats(compaction_stats);
compaction_job_stats.Add(sc.compaction_job_stats);
}
}
} // namespace ROCKSDB_NAMESPACE
+2 -2
View File
@@ -29,8 +29,8 @@ class CompactionState {
Status status;
void AggregateCompactionStats(
InternalStats::CompactionStatsFull& internal_stats,
CompactionJobStats& job_stats);
InternalStats::CompactionStatsFull& compaction_stats,
CompactionJobStats& compaction_job_stats);
explicit CompactionState(Compaction* c) : compaction(c) {}
+23 -28
View File
@@ -14,32 +14,22 @@
namespace ROCKSDB_NAMESPACE {
void SubcompactionState::AggregateCompactionOutputStats(
InternalStats::CompactionStatsFull& internal_stats) const {
// Outputs should be closed. By extension, any files created just for
// range deletes have already been written also.
assert(compaction_outputs_.HasBuilder() == false);
assert(proximal_level_outputs_.HasBuilder() == false);
// FIXME: These stats currently include abandonned output files
// assert(compaction_outputs_.stats_.num_output_files ==
// compaction_outputs_.outputs_.size());
// assert(proximal_level_outputs_.stats_.num_output_files ==
// proximal_level_outputs_.outputs_.size());
internal_stats.output_level_stats.Add(compaction_outputs_.stats_);
if (proximal_level_outputs_.HasOutput()) {
internal_stats.has_proximal_level_output = true;
internal_stats.proximal_level_stats.Add(proximal_level_outputs_.stats_);
InternalStats::CompactionStatsFull& compaction_stats) const {
compaction_stats.stats.Add(compaction_outputs_.stats_);
if (HasPenultimateLevelOutputs()) {
compaction_stats.has_penultimate_level_output = true;
compaction_stats.penultimate_level_stats.Add(
penultimate_level_outputs_.stats_);
}
}
OutputIterator SubcompactionState::GetOutputs() const {
return OutputIterator(proximal_level_outputs_.outputs_,
return OutputIterator(penultimate_level_outputs_.outputs_,
compaction_outputs_.outputs_);
}
void SubcompactionState::Cleanup(Cache* cache) {
proximal_level_outputs_.Cleanup();
penultimate_level_outputs_.Cleanup();
compaction_outputs_.Cleanup();
if (!status.ok()) {
@@ -53,7 +43,7 @@ void SubcompactionState::Cleanup(Cache* cache) {
// be picked up by scanning the DB directory.
TableCache::ReleaseObsolete(
cache, out.meta.fd.GetNumber(), nullptr /*handle*/,
compaction->mutable_cf_options().uncache_aggressiveness);
compaction->mutable_cf_options()->uncache_aggressiveness);
}
}
// TODO: sub_compact.io_status is not checked like status. Not sure if thats
@@ -62,9 +52,9 @@ void SubcompactionState::Cleanup(Cache* cache) {
}
Slice SubcompactionState::SmallestUserKey() const {
if (proximal_level_outputs_.HasOutput()) {
if (has_penultimate_level_outputs_) {
Slice a = compaction_outputs_.SmallestUserKey();
Slice b = proximal_level_outputs_.SmallestUserKey();
Slice b = penultimate_level_outputs_.SmallestUserKey();
if (a.empty()) {
return b;
}
@@ -84,9 +74,9 @@ Slice SubcompactionState::SmallestUserKey() const {
}
Slice SubcompactionState::LargestUserKey() const {
if (proximal_level_outputs_.HasOutput()) {
if (has_penultimate_level_outputs_) {
Slice a = compaction_outputs_.LargestUserKey();
Slice b = proximal_level_outputs_.LargestUserKey();
Slice b = penultimate_level_outputs_.LargestUserKey();
if (a.empty()) {
return b;
}
@@ -106,13 +96,18 @@ Slice SubcompactionState::LargestUserKey() const {
}
Status SubcompactionState::AddToOutput(
const CompactionIterator& iter, bool use_proximal_output,
const CompactionIterator& iter,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func) {
// update target output
current_outputs_ =
use_proximal_output ? &proximal_level_outputs_ : &compaction_outputs_;
return current_outputs_->AddToOutput(iter, open_file_func, close_file_func);
// update target output first
is_current_penultimate_level_ = iter.output_to_penultimate_level();
current_outputs_ = is_current_penultimate_level_ ? &penultimate_level_outputs_
: &compaction_outputs_;
if (is_current_penultimate_level_) {
has_penultimate_level_outputs_ = true;
}
return Current().AddToOutput(iter, open_file_func, close_file_func);
}
} // namespace ROCKSDB_NAMESPACE
+51 -69
View File
@@ -26,13 +26,13 @@ namespace ROCKSDB_NAMESPACE {
// Maintains state and outputs for each sub-compaction
// It contains 2 `CompactionOutputs`:
// 1. one for the normal output files
// 2. another for the proximal level outputs
// 2. another for the penultimate level outputs
// a `current` pointer maintains the current output group, when calling
// `AddToOutput()`, it checks the output of the current compaction_iterator key
// and point `current` to the target output group. By default, it just points to
// normal compaction_outputs, if the compaction_iterator key should be placed on
// the proximal level, `current` is changed to point to
// `proximal_level_outputs`.
// the penultimate level, `current` is changed to point to
// `penultimate_level_outputs`.
// The later operations uses `Current()` to get the target group.
//
// +----------+ +-----------------------------+ +---------+
@@ -43,7 +43,7 @@ namespace ROCKSDB_NAMESPACE {
// | | ... |
// |
// | +-----------------------------+ +---------+
// +-------------> | proximal_level_outputs |----->| output |
// +-------------> | penultimate_level_outputs |----->| output |
// +-----------------------------+ +---------+
// | ... |
@@ -78,21 +78,30 @@ class SubcompactionState {
Slice LargestUserKey() const;
// Get all outputs from the subcompaction. For per_key_placement compaction,
// it returns both the last level outputs and proximal level outputs.
// it returns both the last level outputs and penultimate level outputs.
OutputIterator GetOutputs() const;
// Assign range dels aggregator. The various tombstones will potentially
// be filtered to different outputs.
// Assign range dels aggregator, for each range_del, it can only be assigned
// to one output level, for per_key_placement, it's going to be the
// penultimate level.
// TODO: This does not work for per_key_placement + user-defined timestamp +
// DeleteRange() combo. If user-defined timestamp is enabled,
// it is possible for a range tombstone to belong to bottommost level (
// seqno < earliest snapshot) without being dropped (garbage collection
// for user-defined timestamp).
void AssignRangeDelAggregator(
std::unique_ptr<CompactionRangeDelAggregator>&& range_del_agg) {
assert(range_del_agg_ == nullptr);
assert(range_del_agg);
range_del_agg_ = std::move(range_del_agg);
if (compaction->SupportsPerKeyPlacement()) {
penultimate_level_outputs_.AssignRangeDelAggregator(
std::move(range_del_agg));
} else {
compaction_outputs_.AssignRangeDelAggregator(std::move(range_del_agg));
}
}
void RemoveLastEmptyOutput() {
compaction_outputs_.RemoveLastEmptyOutput();
proximal_level_outputs_.RemoveLastEmptyOutput();
penultimate_level_outputs_.RemoveLastEmptyOutput();
}
void BuildSubcompactionJobInfo(
@@ -106,11 +115,7 @@ class SubcompactionState {
subcompaction_job_info.subcompaction_job_id = static_cast<int>(sub_job_id);
subcompaction_job_info.base_input_level = c->start_level();
subcompaction_job_info.output_level = c->output_level();
subcompaction_job_info.compaction_reason = c->compaction_reason();
subcompaction_job_info.compression = c->output_compression();
subcompaction_job_info.stats = compaction_job_stats;
subcompaction_job_info.blob_compression_type =
c->mutable_cf_options().blob_compression_type;
}
SubcompactionState() = delete;
@@ -123,14 +128,14 @@ class SubcompactionState {
start(_start),
end(_end),
sub_job_id(_sub_job_id),
compaction_outputs_(c, /*is_proximal_level=*/false),
proximal_level_outputs_(c, /*is_proximal_level=*/true) {
compaction_outputs_(c, /*is_penultimate_level=*/false),
penultimate_level_outputs_(c, /*is_penultimate_level=*/true) {
assert(compaction != nullptr);
// Set output split key (used for RoundRobin feature) only for normal
// compaction_outputs, output to proximal_level feature doesn't support
// compaction_outputs, output to penultimate_level feature doesn't support
// RoundRobin feature (and may never going to be supported, because for
// RoundRobin, the data time is mostly naturally sorted, no need to have
// per-key placement with output_to_proximal_level).
// per-key placement with output_to_penultimate_level).
compaction_outputs_.SetOutputSlitKey(start, end);
}
@@ -145,17 +150,27 @@ class SubcompactionState {
compaction_job_stats(std::move(state.compaction_job_stats)),
sub_job_id(state.sub_job_id),
compaction_outputs_(std::move(state.compaction_outputs_)),
proximal_level_outputs_(std::move(state.proximal_level_outputs_)),
range_del_agg_(std::move(state.range_del_agg_)) {
current_outputs_ = state.current_outputs_ == &state.proximal_level_outputs_
? &proximal_level_outputs_
penultimate_level_outputs_(std::move(state.penultimate_level_outputs_)),
is_current_penultimate_level_(state.is_current_penultimate_level_),
has_penultimate_level_outputs_(state.has_penultimate_level_outputs_) {
current_outputs_ = is_current_penultimate_level_
? &penultimate_level_outputs_
: &compaction_outputs_;
}
bool HasPenultimateLevelOutputs() const {
return has_penultimate_level_outputs_ ||
penultimate_level_outputs_.HasRangeDel();
}
bool IsCurrentPenultimateLevel() const {
return is_current_penultimate_level_;
}
// Add all the new files from this compaction to version_edit
void AddOutputsEdit(VersionEdit* out_edit) const {
for (const auto& file : proximal_level_outputs_.outputs_) {
out_edit->AddFile(compaction->GetProximalLevel(), file.meta);
for (const auto& file : penultimate_level_outputs_.outputs_) {
out_edit->AddFile(compaction->GetPenultimateLevel(), file.meta);
}
for (const auto& file : compaction_outputs_.outputs_) {
out_edit->AddFile(compaction->output_level(), file.meta);
@@ -165,74 +180,41 @@ class SubcompactionState {
void Cleanup(Cache* cache);
void AggregateCompactionOutputStats(
InternalStats::CompactionStatsFull& internal_stats) const;
InternalStats::CompactionStatsFull& compaction_stats) const;
CompactionOutputs& Current() const {
assert(current_outputs_);
return *current_outputs_;
}
CompactionOutputs* Outputs(bool is_proximal_level) {
assert(compaction);
if (is_proximal_level) {
assert(compaction->SupportsPerKeyPlacement());
return &proximal_level_outputs_;
}
return &compaction_outputs_;
}
// Per-level stats for the output
InternalStats::CompactionStats* OutputStats(bool is_proximal_level) {
assert(compaction);
if (is_proximal_level) {
assert(compaction->SupportsPerKeyPlacement());
return &proximal_level_outputs_.stats_;
}
return &compaction_outputs_.stats_;
}
CompactionRangeDelAggregator* RangeDelAgg() const {
return range_del_agg_.get();
}
// if the outputs have range delete, range delete is also data
bool HasRangeDel() const {
return range_del_agg_ && !range_del_agg_->IsEmpty();
}
// Add compaction_iterator key/value to the `Current` output group.
Status AddToOutput(const CompactionIterator& iter, bool use_proximal_output,
Status AddToOutput(const CompactionIterator& iter,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func);
// Close all compaction output files, both output_to_proximal_level outputs
// Close all compaction output files, both output_to_penultimate_level outputs
// and normal outputs.
Status CloseCompactionFiles(const Status& curr_status,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func) {
auto per_key = compaction->SupportsPerKeyPlacement();
// Call FinishCompactionOutputFile() even if status is not ok: it needs to
// close the output file.
// CloseOutput() may open new compaction output files.
Status s = curr_status;
if (per_key) {
s = proximal_level_outputs_.CloseOutput(s, range_del_agg_.get(),
open_file_func, close_file_func);
} else {
assert(proximal_level_outputs_.HasBuilder() == false);
assert(proximal_level_outputs_.HasOutput() == false);
}
s = compaction_outputs_.CloseOutput(s, range_del_agg_.get(), open_file_func,
close_file_func);
is_current_penultimate_level_ = true;
Status s = penultimate_level_outputs_.CloseOutput(
curr_status, open_file_func, close_file_func);
is_current_penultimate_level_ = false;
s = compaction_outputs_.CloseOutput(s, open_file_func, close_file_func);
return s;
}
private:
// State kept for output being generated
CompactionOutputs compaction_outputs_;
CompactionOutputs proximal_level_outputs_;
CompactionOutputs penultimate_level_outputs_;
CompactionOutputs* current_outputs_ = &compaction_outputs_;
std::unique_ptr<CompactionRangeDelAggregator> range_del_agg_;
bool is_current_penultimate_level_ = false;
bool has_penultimate_level_outputs_ = false;
};
} // namespace ROCKSDB_NAMESPACE
File diff suppressed because it is too large. Load diff
+4 -15
View File
@@ -4,6 +4,7 @@
// (found in the LICENSE.Apache file in the root directory).
//
#include "rocksdb/convenience.h"
#include "db/convenience_impl.h"
@@ -26,17 +27,6 @@ Status DeleteFilesInRange(DB* db, ColumnFamilyHandle* column_family,
Status DeleteFilesInRanges(DB* db, ColumnFamilyHandle* column_family,
const RangePtr* ranges, size_t n, bool include_end) {
std::vector<RangeOpt> range_opts(n);
for (size_t i = 0; i < n; ++i) {
range_opts[i] = {OptSlice::CopyFromPtr(ranges[i].start),
OptSlice::CopyFromPtr(ranges[i].limit)};
}
return DeleteFilesInRanges(db, column_family, range_opts.data(), n,
include_end);
}
Status DeleteFilesInRanges(DB* db, ColumnFamilyHandle* column_family,
const RangeOpt* ranges, size_t n, bool include_end) {
return (static_cast_with_check<DBImpl>(db->GetRootDB()))
->DeleteFilesInRanges(column_family, ranges, n, include_end);
}
@@ -93,10 +83,9 @@ Status VerifySstFileChecksumInternal(const Options& options,
nullptr /* file_read_hist */, ioptions.rate_limiter.get()));
const bool kImmortal = true;
auto reader_options = TableReaderOptions(
ioptions, options.prefix_extractor, options.compression_manager.get(),
env_options, internal_comparator, options.block_protection_bytes_per_key,
false /* skip_filters */, !kImmortal, false /* force_direct_prefetch */,
-1 /* level */);
ioptions, options.prefix_extractor, env_options, internal_comparator,
options.block_protection_bytes_per_key, false /* skip_filters */,
!kImmortal, false /* force_direct_prefetch */, -1 /* level */);
reader_options.largest_seqno = largest_seqno;
s = options.table_factory->NewTableReader(
read_options, reader_options, std::move(file_reader), file_size,
+6 -75
View File
@@ -7,6 +7,8 @@
// 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 "rocksdb/options.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -23,7 +25,6 @@
#include "rocksdb/convenience.h"
#include "rocksdb/db.h"
#include "rocksdb/env.h"
#include "rocksdb/options.h"
#include "rocksdb/table.h"
#include "rocksdb/utilities/transaction_db.h"
#include "rocksdb/write_batch.h"
@@ -556,74 +557,6 @@ TEST_F(CorruptionTest, TableFileFooterNotMagic) {
ASSERT_TRUE(s.ToString().find(".sst") != std::string::npos);
}
TEST_F(CorruptionTest, DBOpenWithWrongFileSize) {
// Validate that when paranoid flag is true, DB::Open() fails if one of the
// file corrupted. Validate that when paranoid flag is false, DB::Open()
// succeed if one of the file corrupted, and the healthy file is readable.
CloseDb();
const std::string test_cf_name = "test_cf";
std::vector<ColumnFamilyDescriptor> cf_descs;
cf_descs.emplace_back(kDefaultColumnFamilyName, ColumnFamilyOptions());
cf_descs.emplace_back(test_cf_name, ColumnFamilyOptions());
{
options_.create_missing_column_families = true;
std::vector<ColumnFamilyHandle*> cfhs;
ASSERT_OK(DB::Open(options_, dbname_, cf_descs, &cfhs, &db_));
assert(db_ != nullptr); // suppress false clang-analyze report
ASSERT_OK(db_->Put(WriteOptions(), cfhs[0], "k", "v"));
ASSERT_OK(db_->Put(WriteOptions(), cfhs[1], "k1", "v1"));
ASSERT_OK(db_->Put(WriteOptions(), cfhs[0], "k2", "v2"));
for (auto* cfh : cfhs) {
delete cfh;
}
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
ASSERT_OK(dbi->TEST_FlushMemTable());
// ********************************************
// Corrupt the file by making the file bigger
std::vector<LiveFileMetaData> metadata;
db_->GetLiveFilesMetaData(&metadata);
std::string filename = dbname_ + metadata[0].name;
const auto& fs = options_.env->GetFileSystem();
{
std::unique_ptr<FSWritableFile> f;
ASSERT_OK(fs->ReopenWritableFile(filename, FileOptions(), &f, nullptr));
ASSERT_OK(f->Append("blahblah", IOOptions(), nullptr));
ASSERT_OK(f->Close(IOOptions(), nullptr));
}
CloseDb();
}
// DB failed to open due to one of the file is corrupted, as paranoid flag is
// true
options_.paranoid_checks = true;
std::vector<ColumnFamilyHandle*> cfhs;
auto s = DB::Open(options_, dbname_, cf_descs, &cfhs, &db_);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(s.ToString().find("file size mismatch") != std::string::npos);
// DB opened successfully, as paranoid flag is false, validate the one that is
// healthy is still accessible
options_.paranoid_checks = false;
ASSERT_OK(DB::Open(options_, dbname_, cf_descs, &cfhs, &db_));
assert(db_ != nullptr); // suppress false clang-analyze report
std::string v;
ASSERT_OK(db_->Get(ReadOptions(), cfhs[1], "k1", &v));
ASSERT_EQ(v, "v1");
// Validate the default column family is corrupted
Check(0, 0);
s = db_->Get(ReadOptions(), cfhs[0], "k1", &v);
ASSERT_TRUE(s.IsCorruption());
delete cfhs[1];
delete cfhs[0];
}
TEST_F(CorruptionTest, TableFileWrongSize) {
Build(100);
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
@@ -647,16 +580,13 @@ TEST_F(CorruptionTest, TableFileWrongSize) {
// DB actually accepts this without paranoid checks, relying on size
// recorded in manifest to locate the SST footer.
options_.paranoid_checks = false;
options_.skip_checking_sst_file_sizes_on_db_open = false;
Reopen();
// As footer could not be extraced, file is completely unreadable
Check(0, 0);
std::string v;
auto s = db_->Get(ReadOptions(), "k1", &v);
ASSERT_TRUE(s.IsCorruption());
Check(100, 100);
// But reports the issue with paranoid checks
options_.paranoid_checks = true;
s = TryReopen();
Status s = TryReopen();
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(s.ToString().find("file size mismatch") != std::string::npos);
@@ -934,6 +864,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksOnCompact) {
ASSERT_OK(DB::Open(options, dbname_, &db_));
assert(db_ != nullptr); // suppress false clang-analyze report
Build(100, 2);
// ASSERT_OK(db_->Flush(FlushOptions()));
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
ASSERT_OK(dbi->TEST_FlushMemTable());
mock->SetCorruptionMode(mode);
+2
View File
@@ -3,6 +3,7 @@
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include "db/db_impl/db_impl.h"
#include "db/db_test_util.h"
#include "rocksdb/db.h"
@@ -348,3 +349,4 @@ int main(int argc, char** argv) {
return 0;
}
}
+17 -196
View File
@@ -161,7 +161,6 @@ TEST_F(DBBasicTest, UniqueSession) {
ASSERT_EQ(sid2, sid3);
DestroyAndReopen(options);
CreateAndReopenWithCF({"goku"}, options);
ASSERT_OK(db_->GetDbSessionId(sid1));
ASSERT_OK(Put("bar", "e1"));
@@ -180,7 +179,6 @@ TEST_F(DBBasicTest, UniqueSession) {
TEST_F(DBBasicTest, ReadOnlyDB) {
ASSERT_OK(Put("foo", "v1"));
ASSERT_OK(Put("bar", "v2"));
ASSERT_OK(Flush());
ASSERT_OK(Put("foo", "v3"));
Close();
@@ -210,11 +208,10 @@ TEST_F(DBBasicTest, ReadOnlyDB) {
auto options = CurrentOptions();
assert(options.env == env_);
ASSERT_OK(EnforcedReadOnlyReopen(options));
ASSERT_OK(ReadOnlyReopen(options));
ASSERT_EQ("v3", Get("foo"));
ASSERT_EQ("v2", Get("bar"));
verify_all_iters();
ASSERT_EQ(Flush().code(), Status::Code::kNotSupported);
Close();
// Reopen and flush memtable.
@@ -222,38 +219,26 @@ TEST_F(DBBasicTest, ReadOnlyDB) {
ASSERT_OK(Flush());
Close();
// Now check keys in read only mode.
ASSERT_OK(EnforcedReadOnlyReopen(options));
ASSERT_OK(ReadOnlyReopen(options));
ASSERT_EQ("v3", Get("foo"));
ASSERT_EQ("v2", Get("bar"));
verify_all_iters();
ASSERT_EQ(db_->SyncWAL().code(), Status::Code::kNotSupported);
// More ops that should fail
std::vector<ColumnFamilyHandle*> cfhs{{}};
ASSERT_EQ(db_->CreateColumnFamily(options, "blah", &cfhs[0]).code(),
Status::Code::kNotSupported);
ASSERT_EQ(db_->CreateColumnFamilies(options, {"blah"}, &cfhs).code(),
Status::Code::kNotSupported);
std::vector<ColumnFamilyDescriptor> cfds;
cfds.push_back({"blah", options});
ASSERT_EQ(db_->CreateColumnFamilies(cfds, &cfhs).code(),
Status::Code::kNotSupported);
ASSERT_TRUE(db_->SyncWAL().IsNotSupported());
}
TEST_F(DBBasicTest, ReadOnlyDBWithWriteDBIdToManifestSet) {
auto options = CurrentOptions();
options.write_dbid_to_manifest = false;
DestroyAndReopen(options);
// TODO akanksha: Update the test to check that combination
// does not actually write to FS (use open read-only with
// CompositeEnvWrapper+ReadOnlyFileSystem).
TEST_F(DBBasicTest, DISABLED_ReadOnlyDBWithWriteDBIdToManifestSet) {
ASSERT_OK(Put("foo", "v1"));
ASSERT_OK(Put("bar", "v2"));
ASSERT_OK(Put("foo", "v3"));
Close();
auto options = CurrentOptions();
options.write_dbid_to_manifest = true;
assert(options.env == env_);
ASSERT_OK(EnforcedReadOnlyReopen(options));
ASSERT_OK(ReadOnlyReopen(options));
std::string db_id1;
ASSERT_OK(db_->GetDbIdentity(db_id1));
ASSERT_EQ("v3", Get("foo"));
@@ -273,7 +258,7 @@ TEST_F(DBBasicTest, ReadOnlyDBWithWriteDBIdToManifestSet) {
ASSERT_OK(Flush());
Close();
// Now check keys in read only mode.
ASSERT_OK(EnforcedReadOnlyReopen(options));
ASSERT_OK(ReadOnlyReopen(options));
ASSERT_EQ("v3", Get("foo"));
ASSERT_EQ("v2", Get("bar"));
ASSERT_TRUE(db_->SyncWAL().IsNotSupported());
@@ -893,6 +878,7 @@ TEST_F(DBBasicTest, Snapshot) {
} while (ChangeOptions());
}
class DBBasicMultiConfigs : public DBBasicTest,
public ::testing::WithParamInterface<int> {
public:
@@ -2618,7 +2604,8 @@ class DBMultiGetAsyncIOTest : public DBBasicTest,
// Warm up the block cache so we don't need to use the IO uring
Iterator* iter = dbfull()->NewIterator(ReadOptions());
for (iter->SeekToFirst(); iter->Valid() && iter->status().ok();
iter->Next());
iter->Next())
;
EXPECT_OK(iter->status());
delete iter;
#endif // ROCKSDB_IOURING_PRESENT
@@ -3288,7 +3275,8 @@ TEST_F(DBBasicTest, GetAllKeyVersions) {
ASSERT_OK(Delete(std::to_string(i)));
}
std::vector<KeyVersion> key_versions;
ASSERT_OK(GetAllKeyVersions(db_, {}, {}, std::numeric_limits<size_t>::max(),
ASSERT_OK(GetAllKeyVersions(db_, Slice(), Slice(),
std::numeric_limits<size_t>::max(),
&key_versions));
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates, key_versions.size());
for (size_t i = 0; i < kNumInserts + kNumDeletes + kNumUpdates; i++) {
@@ -3298,7 +3286,7 @@ TEST_F(DBBasicTest, GetAllKeyVersions) {
ASSERT_EQ(key_versions[i].GetTypeName(), "TypeValue");
}
}
ASSERT_OK(GetAllKeyVersions(db_, handles_[0], {}, {},
ASSERT_OK(GetAllKeyVersions(db_, handles_[0], Slice(), Slice(),
std::numeric_limits<size_t>::max(),
&key_versions));
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates, key_versions.size());
@@ -3313,17 +3301,10 @@ TEST_F(DBBasicTest, GetAllKeyVersions) {
for (size_t i = 0; i + 1 != kNumDeletes; ++i) {
ASSERT_OK(Delete(1, std::to_string(i)));
}
ASSERT_OK(GetAllKeyVersions(db_, handles_[1], {}, {},
std::numeric_limits<size_t>::max(),
&key_versions));
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates - 3, key_versions.size());
// Change from historical behavior: empty key is now interpreted literally as
// a legal key (rather than as a "not present" key)
ASSERT_OK(GetAllKeyVersions(db_, handles_[1], Slice(), Slice(),
std::numeric_limits<size_t>::max(),
&key_versions));
ASSERT_EQ(key_versions.size(), 0);
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates - 3, key_versions.size());
}
TEST_F(DBBasicTest, ValueTypeString) {
@@ -3375,69 +3356,6 @@ TEST_F(DBBasicTest, MultiGetIOBufferOverrun) {
keys.data(), values.data(), statuses.data(), true);
}
TEST_F(DBBasicTest, MultiGetWithSnapshotsAndPersistedTier) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.atomic_flush = true;
DestroyAndReopen(options);
CreateAndReopenWithCF({"cf1", "cf2"}, options);
// Insert initial data
ASSERT_OK(Put(0, "key1", "value1_cf0"));
ASSERT_OK(Put(1, "key1", "value1_cf1"));
ASSERT_OK(Put(2, "key1", "value1_cf2"));
ASSERT_OK(Flush({0, 1, 2}));
for (auto cf : {0, 1, 2}) {
ASSERT_EQ(1, NumTableFilesAtLevel(0, cf));
}
ASSERT_OK(Put(0, "key1", "value2_cf0"));
ASSERT_OK(Put(1, "key1", "value2_cf1"));
ASSERT_OK(Put(2, "key1", "value2_cf2"));
// Prepare for concurrent atomic flush
std::atomic<bool> flush_done(false);
std::thread flush_thread([&]() {
ASSERT_OK(Flush({0, 1, 2}));
flush_done.store(true);
});
// Perform MultiGet with snapshot and read_tier = kPersistentTier
ReadOptions ro;
const Snapshot* snapshot = db_->GetSnapshot();
ro.snapshot = snapshot;
ro.read_tier = kPersistedTier;
std::string k = "key1";
std::vector<Slice> keys(3, Slice(k));
std::vector<Status> statuses(keys.size());
std::vector<ColumnFamilyHandle*> cfs(keys.size());
std::vector<Slice> new_keys(keys.size());
std::vector<PinnableSlice> pin_values(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
cfs[i] = handles_[i];
}
db_->MultiGet(ro, cfs.size(), cfs.data(), keys.data(), pin_values.data(),
statuses.data());
for (const auto& s : statuses) {
ASSERT_OK(s);
}
if (pin_values[0] == "value1_cf0") {
// Check if the first value matches expected value
ASSERT_EQ(pin_values[1], "value1_cf1");
ASSERT_EQ(pin_values[2], "value1_cf2");
} else {
// If first value doesn't match, check if we got the updated values
ASSERT_EQ(pin_values[0], "value2_cf0");
ASSERT_EQ(pin_values[1], "value2_cf1");
ASSERT_EQ(pin_values[2], "value2_cf2");
}
flush_thread.join();
db_->ReleaseSnapshot(snapshot);
}
TEST_F(DBBasicTest, IncrementalRecoveryNoCorrupt) {
Options options = CurrentOptions();
DestroyAndReopen(options);
@@ -5078,103 +4996,6 @@ TEST_F(DBBasicTest, VerifyFileChecksumsReadahead) {
(sst_size + alignment - 1) / (alignment));
}
TEST_F(DBBasicTest, DisallowMemtableWrite) {
// This test is mostly about what you can't do with memtable writes
// disallowed. For what you can do, see
// ExternalSSTFileBasicTest.FailIfNotBottommostLevelAndDisallowMemtable
Options options_allow = GetDefaultOptions();
options_allow.create_if_missing = true;
Options options_disallow = options_allow;
options_disallow.disallow_memtable_writes = true;
options_disallow.paranoid_memory_checks = true;
DestroyAndReopen(options_allow);
// CFs allowing and disallowing memtable write
CreateColumnFamilies({"cf1", "cf2"}, options_allow);
CreateColumnFamilies({"cf3"}, options_disallow);
// XXX: needed to get consistent handles_ mappings
ReopenWithColumnFamilies(
{"default", "cf1", "cf2", "cf3"},
{options_allow, options_allow, options_allow, options_disallow});
EXPECT_EQ(Put(0, "a0", "1").code(), Status::Code::kOk);
EXPECT_EQ(Put(1, "a1", "1").code(), Status::Code::kOk);
EXPECT_EQ(Put(2, "a2", "1").code(), Status::Code::kOk);
EXPECT_EQ(Put(3, "a3", "1").code(), Status::Code::kInvalidArgument);
EXPECT_EQ(Get(0, "a0"), "1");
EXPECT_EQ(Get(1, "a1"), "1");
EXPECT_EQ(Get(2, "a2"), "1");
EXPECT_EQ(Get(3, "a3"), "NOT_FOUND");
EXPECT_EQ(Delete(0, "z0").code(), Status::Code::kOk);
EXPECT_EQ(Delete(1, "z1").code(), Status::Code::kOk);
EXPECT_EQ(Delete(2, "z2").code(), Status::Code::kOk);
EXPECT_EQ(Delete(3, "z3").code(), Status::Code::kInvalidArgument);
WriteBatch wb;
EXPECT_EQ(wb.Put(handles_[0], "b0", "2").code(), Status::Code::kOk);
EXPECT_EQ(wb.Put(handles_[1], "b1", "2").code(), Status::Code::kOk);
EXPECT_EQ(wb.Put(handles_[2], "b2", "2").code(), Status::Code::kOk);
EXPECT_EQ(wb.Put(handles_[3], "b3", "2").code(),
Status::Code::kInvalidArgument);
ASSERT_OK(db_->Write({}, &wb));
wb.Clear();
EXPECT_EQ(Get(0, "b0"), "2");
EXPECT_EQ(Get(1, "b1"), "2");
EXPECT_EQ(Get(2, "b2"), "2");
EXPECT_EQ(Get(3, "b3"), "NOT_FOUND");
std::unique_ptr<Iterator> iter(
dbfull()->NewIterator(ReadOptions(), handles_[3]));
iter->Seek("a3");
ASSERT_OK(iter->status());
iter.reset();
// When the DB is re-opened with WAL entries for a CF that is newly setting
// disallow_memtable_writes, we detect that and fail the open gracefully.
ASSERT_EQ(TryReopenWithColumnFamilies(
{"default", "cf1", "cf2", "cf3"},
{options_allow, options_allow, options_disallow, options_allow})
.code(),
Status::Code::kInvalidArgument);
// Successfully opening with allow creates L0 files from the WAL
ReopenWithColumnFamilies({"default", "cf1", "cf2", "cf3"}, options_allow);
EXPECT_EQ(Get(0, "a0"), "1");
EXPECT_EQ(Get(1, "a1"), "1");
EXPECT_EQ(Get(2, "a2"), "1");
EXPECT_EQ(Get(3, "a3"), "NOT_FOUND");
// Now able to disallow on CF2 because no relevant WAL entries
ReopenWithColumnFamilies(
{"default", "cf1", "cf2", "cf3"},
{options_allow, options_allow, options_disallow, options_allow});
EXPECT_EQ(Get(0, "a0"), "1");
EXPECT_EQ(Get(1, "a1"), "1");
EXPECT_EQ(Get(2, "a2"), "1");
EXPECT_EQ(Get(3, "a3"), "NOT_FOUND");
// Now able to write to CF 3 but not CF 2
EXPECT_EQ(Put(0, "c0", "3").code(), Status::Code::kOk);
EXPECT_EQ(Put(1, "c1", "3").code(), Status::Code::kOk);
EXPECT_EQ(Put(2, "c2", "3").code(), Status::Code::kInvalidArgument);
EXPECT_EQ(Put(3, "c3", "3").code(), Status::Code::kOk);
EXPECT_EQ(Get(0, "c0"), "3");
EXPECT_EQ(Get(1, "c1"), "3");
EXPECT_EQ(Get(2, "c2"), "NOT_FOUND");
EXPECT_EQ(Get(3, "c3"), "3");
// disallow_memtable_writes not supported on default column family.
// (Would be complicated to make a WriteBatch aware of the setting in order
// to reject the write before entering the write path.)
Destroy(options_allow);
EXPECT_EQ(TryReopen(options_disallow).code(), Status::Code::kInvalidArgument);
}
// TODO: re-enable after we provide finer-grained control for WAL tracking to
// meet the needs of different use cases, durability levels and recovery modes.
TEST_F(DBBasicTest, DISABLED_ManualWalSync) {
+62 -74
View File
@@ -305,6 +305,7 @@ class ReadOnlyCacheWrapper : public CacheWrapper {
} // anonymous namespace
#endif // SNAPPY
// Make sure that when options.block_cache is set, after a new table is
// created its index/filter blocks are added to block cache.
TEST_F(DBBlockCacheTest, IndexAndFilterBlocksOfNewTableAddedToCache) {
@@ -506,8 +507,6 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
table_options.prepopulate_block_cache =
BlockBasedTableOptions::PrepopulateBlockCache::kFlushOnly;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
// Include a compression dictionary block
options.compression_opts.max_dict_bytes = 123;
DestroyAndReopen(options);
std::string value(kValueSize, 'a');
@@ -539,9 +538,6 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_HIT));
}
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_FILTER_MISS));
// Including compression dict
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_MISS));
}
// Verify compaction not counted
@@ -829,78 +825,70 @@ TEST_F(DBBlockCacheTest, CacheCompressionDict) {
const int kNumEntriesPerFile = 128;
const int kNumBytesPerEntry = 1024;
std::vector<CompressionType> dict_compressions =
GetSupportedDictCompressions();
// Try all the available libraries that support dictionary compression
std::vector<CompressionType> compression_types;
if (Zlib_Supported()) {
compression_types.push_back(kZlibCompression);
}
if (LZ4_Supported()) {
compression_types.push_back(kLZ4Compression);
compression_types.push_back(kLZ4HCCompression);
}
if (ZSTD_Supported()) {
compression_types.push_back(kZSTD);
} else if (ZSTDNotFinal_Supported()) {
compression_types.push_back(kZSTDNotFinalCompression);
}
Random rnd(301);
// Format version before and after compression handling changes
for (int format_version : {6, 7}) {
// Test all supported compression types because (at least historically)
// dictionary compression could be enabled and a dictionary block saved
// but ignored by some compression types. Ensure we at least don't crash
// or return corruption for those.
for (auto compression_type : GetSupportedCompressions()) {
// Extra handling checks only for types actually supporting dictionary
// compression.
bool dict_supported =
std::count(dict_compressions.begin(), dict_compressions.end(),
compression_type) > 0;
for (auto compression_type : compression_types) {
Options options = CurrentOptions();
options.bottommost_compression = compression_type;
options.bottommost_compression_opts.max_dict_bytes = 4096;
options.bottommost_compression_opts.enabled = true;
options.create_if_missing = true;
options.num_levels = 2;
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
options.target_file_size_base = kNumEntriesPerFile * kNumBytesPerEntry;
BlockBasedTableOptions table_options;
table_options.cache_index_and_filter_blocks = true;
table_options.block_cache.reset(new MockCache());
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
Options options = CurrentOptions();
options.bottommost_compression = compression_type;
options.bottommost_compression_opts.max_dict_bytes = 4096;
options.bottommost_compression_opts.enabled = true;
options.create_if_missing = true;
options.num_levels = 2;
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
options.target_file_size_base = kNumEntriesPerFile * kNumBytesPerEntry;
BlockBasedTableOptions table_options;
table_options.cache_index_and_filter_blocks = true;
table_options.block_cache.reset(new MockCache());
table_options.format_version = format_version;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
RecordCacheCountersForCompressionDict(options);
RecordCacheCountersForCompressionDict(options);
for (int i = 0; i < kNumFiles; ++i) {
ASSERT_EQ(i, NumTableFilesAtLevel(0, 0));
for (int j = 0; j < kNumEntriesPerFile; ++j) {
std::string value = rnd.RandomString(kNumBytesPerEntry);
ASSERT_OK(Put(Key(j * kNumFiles + i), value.c_str()));
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
ASSERT_EQ(0, NumTableFilesAtLevel(0));
ASSERT_EQ(kNumFiles, NumTableFilesAtLevel(1));
if (dict_supported) {
// Compression dictionary blocks are preloaded.
CheckCacheCountersForCompressionDict(
options, kNumFiles /* expected_compression_dict_misses */,
0 /* expected_compression_dict_hits */,
kNumFiles /* expected_compression_dict_inserts */);
}
// Seek to a key in a file. It should cause the SST's dictionary
// meta-block to be read.
RecordCacheCounters(options);
RecordCacheCountersForCompressionDict(options);
ReadOptions read_options;
ASSERT_NE("NOT_FOUND", Get(Key(kNumFiles * kNumEntriesPerFile - 1)));
if (dict_supported) {
// Two block hits: index and dictionary since they are prefetched
// One block missed/added: data block
CheckCacheCounters(options, 1 /* expected_misses */,
2 /* expected_hits */, 1 /* expected_inserts */,
0 /* expected_failures */);
CheckCacheCountersForCompressionDict(
options, 0 /* expected_compression_dict_misses */,
1 /* expected_compression_dict_hits */,
0 /* expected_compression_dict_inserts */);
for (int i = 0; i < kNumFiles; ++i) {
ASSERT_EQ(i, NumTableFilesAtLevel(0, 0));
for (int j = 0; j < kNumEntriesPerFile; ++j) {
std::string value = rnd.RandomString(kNumBytesPerEntry);
ASSERT_OK(Put(Key(j * kNumFiles + i), value.c_str()));
}
ASSERT_OK(Flush());
}
ASSERT_OK(dbfull()->TEST_WaitForCompact());
ASSERT_EQ(0, NumTableFilesAtLevel(0));
ASSERT_EQ(kNumFiles, NumTableFilesAtLevel(1));
// Compression dictionary blocks are preloaded.
CheckCacheCountersForCompressionDict(
options, kNumFiles /* expected_compression_dict_misses */,
0 /* expected_compression_dict_hits */,
kNumFiles /* expected_compression_dict_inserts */);
// Seek to a key in a file. It should cause the SST's dictionary meta-block
// to be read.
RecordCacheCounters(options);
RecordCacheCountersForCompressionDict(options);
ReadOptions read_options;
ASSERT_NE("NOT_FOUND", Get(Key(kNumFiles * kNumEntriesPerFile - 1)));
// Two block hits: index and dictionary since they are prefetched
// One block missed/added: data block
CheckCacheCounters(options, 1 /* expected_misses */, 2 /* expected_hits */,
1 /* expected_inserts */, 0 /* expected_failures */);
CheckCacheCountersForCompressionDict(
options, 0 /* expected_compression_dict_misses */,
1 /* expected_compression_dict_hits */,
0 /* expected_compression_dict_inserts */);
}
}
@@ -1770,8 +1758,8 @@ class CacheKeyTest : public testing::Test {
tp_.db_id = std::to_string(db_id_);
tp_.orig_file_number = file_number;
bool is_stable;
std::string cur_session_id; // ignored
uint64_t cur_file_number = 42; // ignored
std::string cur_session_id; // ignored
uint64_t cur_file_number = 42; // ignored
OffsetableCacheKey rv;
BlockBasedTable::SetupBaseCacheKey(&tp_, cur_session_id, cur_file_number,
&rv, &is_stable);
-48
View File
@@ -2244,54 +2244,6 @@ TEST_F(DBBloomFilterTest, MemtableWholeKeyBloomFilterMultiGet) {
db_->ReleaseSnapshot(snapshot);
}
TEST_F(DBBloomFilterTest, TestMemtableBloomAndWBM) {
Options options = CurrentOptions();
options.arena_block_size = 4096;
options.write_buffer_size = 4000000;
std::shared_ptr<Cache> cache = NewLRUCache(LRUCacheOptions(
options.write_buffer_size * 3 /* capacity */, 1 /* num_shard_bits */,
false /* strict_capacity_limit */, 0.0 /* high_pri_pool_ratio */,
nullptr /* memory_allocator */, kDefaultToAdaptiveMutex,
kDontChargeCacheMetadata));
options.write_buffer_manager.reset(
new WriteBufferManager(options.write_buffer_size, cache));
Reopen(options);
ASSERT_OK(Put("foo", "bar"));
const auto kDummyEntrySize =
CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
// Just the start of a memtable, no Bloom
ASSERT_GE(cache->GetUsage(), options.arena_block_size);
ASSERT_LE(cache->GetUsage(), kDummyEntrySize);
// Now enable memtable bloom filter
const double kRatio = 0.25;
options.memtable_prefix_bloom_size_ratio = kRatio;
options.memtable_whole_key_filtering = true;
Reopen(options);
ASSERT_OK(Put("foo2", "bar2"));
// Expecting a memtable Bloom of ratio times write_buffer_size, memory tracked
auto bloom_size = static_cast<size_t>(kRatio * options.write_buffer_size);
ASSERT_GE(cache->GetUsage(), bloom_size);
ASSERT_LE(cache->GetUsage(), bloom_size + 2U * kDummyEntrySize);
// Now get another memtable and test
// Pin this memtable with an iterator
std::unique_ptr<Iterator> iter{db_->NewIterator({})};
iter->Seek("foo2");
ASSERT_TRUE(iter->Valid());
ASSERT_OK(Flush());
ASSERT_OK(Put("foo2", "bar2"));
// Expecting twice as much
ASSERT_GE(cache->GetUsage(), 2U * bloom_size);
ASSERT_LE(cache->GetUsage(), 2U * bloom_size + 2U * kDummyEntrySize);
}
namespace {
std::pair<uint64_t, uint64_t> GetBloomStat(const Options& options, bool sst) {
if (sst) {
+264 -696
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -491,6 +491,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
::testing::InitGoogleTest(&argc, argv);
+7 -41
View File
@@ -3,13 +3,12 @@
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
//
#include <iostream>
#include <string>
#include "db/db_test_util.h"
#include "port/stack_trace.h"
#include "rocksdb/perf_context.h"
#include "test_util/sync_point.h"
#include <iostream>
#include <string>
namespace ROCKSDB_NAMESPACE {
@@ -17,16 +16,16 @@ class DBEncryptionTest : public DBTestBase {
public:
DBEncryptionTest()
: DBTestBase("db_encryption_test", /*env_do_fsync=*/true) {}
Env* GetNonEncryptedEnv() {
Env* GetTargetEnv() {
if (encrypted_env_ != nullptr) {
return (static_cast_with_check<CompositeEnvWrapper>(encrypted_env_))
->env_target();
return (static_cast<EnvWrapper*>(encrypted_env_))->target();
} else {
return env_;
}
}
};
TEST_F(DBEncryptionTest, CheckEncrypted) {
ASSERT_OK(Put("foo567", "v1.fetdq"));
ASSERT_OK(Put("bar123", "v2.dfgkjdfghsd"));
@@ -39,7 +38,7 @@ TEST_F(DBEncryptionTest, CheckEncrypted) {
auto status = env_->GetChildren(dbname_, &fileNames);
ASSERT_OK(status);
Env* target = GetNonEncryptedEnv();
Env* target = GetTargetEnv();
int hits = 0;
for (auto it = fileNames.begin(); it != fileNames.end(); ++it) {
if (*it == "LOCK") {
@@ -90,7 +89,7 @@ TEST_F(DBEncryptionTest, CheckEncrypted) {
}
TEST_F(DBEncryptionTest, ReadEmptyFile) {
auto defaultEnv = GetNonEncryptedEnv();
auto defaultEnv = GetTargetEnv();
// create empty file for reading it back in later
auto envOptions = EnvOptions(CurrentOptions());
@@ -117,39 +116,6 @@ TEST_F(DBEncryptionTest, ReadEmptyFile) {
ASSERT_TRUE(data.empty());
}
TEST_F(DBEncryptionTest, NotSupportedGetFileSize) {
// Validate envrypted env does not support GetFileSize.
// The goal of the test is to validate the encrypted env/fs does not support
// GetFileSize API on FSRandomAccessFile interface.
// This test combined with the rest of the integration tests validate that
// the new API GetFileSize on FSRandomAccessFile interface is not required to
// be supported for database to work properly.
// The GetFileSize API is used in ReadFooterFromFile() API to get the file
// size. When GetFileSize API is not supported, the ReadFooterFromFile() API
// will use FileSystem GetFileSize API as fallback. Refer to the
// EncryptedRandomAccessFile class definition for more details.
if (!encrypted_env_) {
return;
}
auto fs = encrypted_env_->GetFileSystem();
// create empty file for reading it back in later
auto filePath = dbname_ + "/empty.empty";
// Create empty file
CreateFile(fs.get(), filePath, "", false);
// Open it for reading footer
std::unique_ptr<FSRandomAccessFile> randomAccessFile;
auto status = fs->NewRandomAccessFile(filePath, FileOptions(),
&randomAccessFile, nullptr);
ASSERT_OK(status);
uint64_t fileSize;
status = randomAccessFile->GetFileSize(&fileSize);
ASSERT_TRUE(status.IsNotSupported());
}
} // namespace ROCKSDB_NAMESPACE
+16 -11
View File
@@ -4,6 +4,7 @@
// (found in the LICENSE.Apache file in the root directory).
//
#include <algorithm>
#include <cstdint>
#include <memory>
@@ -75,9 +76,11 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
ret.emplace_back(CurrentFileName(""));
ret.emplace_back(DescriptorFileName("", versions_->manifest_file_number()));
// In read-only mode the OPTIONS file number is zero when no OPTIONS file
// exist at all. In this cases we do not record any OPTIONS file in the live
// file list.
// The OPTIONS file number is zero in read-write mode when OPTIONS file
// writing failed and the DB was configured with
// `fail_if_options_file_error == false`. In read-only mode the OPTIONS file
// number is zero when no OPTIONS file exist at all. In those cases we do not
// record any OPTIONS file in the live file list.
if (versions_->options_file_number() != 0) {
ret.emplace_back(OptionsFileName("", versions_->options_file_number()));
}
@@ -183,14 +186,14 @@ Status DBImpl::GetSortedWalFilesImpl(VectorWalPtr& files, bool need_seqnos) {
return s;
}
Status DBImpl::GetCurrentWalFile(std::unique_ptr<WalFile>* current_wal_file) {
Status DBImpl::GetCurrentWalFile(std::unique_ptr<WalFile>* current_log_file) {
uint64_t current_logfile_number;
{
InstrumentedMutexLock l(&mutex_);
current_logfile_number = cur_wal_number_;
current_logfile_number = logfile_number_;
}
return wal_manager_.GetLiveWalFile(current_logfile_number, current_wal_file);
return wal_manager_.GetLiveWalFile(current_logfile_number, current_log_file);
}
Status DBImpl::GetLiveFilesStorageInfo(
@@ -263,7 +266,7 @@ Status DBImpl::GetLiveFilesStorageInfo(
continue;
}
VersionStorageInfo& vsi = *cfd->current()->storage_info();
auto& cf_paths = cfd->ioptions().cf_paths;
auto& cf_paths = cfd->ioptions()->cf_paths;
auto GetDir = [&](size_t path_id) {
// Matching TableFileName() behavior
@@ -330,7 +333,7 @@ Status DBImpl::GetLiveFilesStorageInfo(
const uint64_t options_size = versions_->options_file_size_;
const uint64_t min_log_num = MinLogNumberToKeep();
// Ensure consistency with manifest for track_and_verify_wals_in_manifest
const uint64_t max_log_num = cur_wal_number_;
const uint64_t max_log_num = logfile_number_;
mutex_.Unlock();
@@ -367,9 +370,11 @@ Status DBImpl::GetLiveFilesStorageInfo(
}
}
// In read-only mode the OPTIONS file number is zero when no OPTIONS file
// exist at all. In this cases we do not record any OPTIONS file in the live
// file list.
// The OPTIONS file number is zero in read-write mode when OPTIONS file
// writing failed and the DB was configured with
// `fail_if_options_file_error == false`. In read-only mode the OPTIONS file
// number is zero when no OPTIONS file exist at all. In those cases we do not
// record any OPTIONS file in the live file list.
if (options_number != 0) {
results.emplace_back();
LiveFileStorageInfo& info = results.back();
-57
View File
@@ -3504,63 +3504,6 @@ TEST_F(DBFlushTest, DBStuckAfterAtomicFlushError) {
ASSERT_OK(dbfull()->TEST_WaitForBackgroundWork());
ASSERT_EQ(1, NumTableFilesAtLevel(0));
}
TEST_F(DBFlushTest, VerifyOutputRecordCount) {
for (bool use_plain_table : {false, true}) {
Options options = CurrentOptions();
options.flush_verify_memtable_count = true;
options.merge_operator = MergeOperators::CreateStringAppendOperator();
DestroyAndReopen(options);
// Verify flush output record count verification in different table
// formats
if (use_plain_table) {
options.table_factory.reset(NewPlainTableFactory());
}
// Verify that flush output record count verification does not produce false
// positives.
ASSERT_OK(Merge("k0", "v1"));
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
ASSERT_OK(SingleDelete("k2"));
ASSERT_OK(Delete("k2"));
ASSERT_OK(Delete("k3"));
ASSERT_OK(db_->DeleteRange(WriteOptions(), "k1", "k3"));
ASSERT_OK(Flush());
// Verify that flush output record count verification catch corruption
DestroyAndReopen(options);
if (use_plain_table) {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"PlainTableBuilder::Add::skip",
[&](void* skip) { *(bool*)skip = true; });
} else {
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"BlockBasedTableBuilder::Add::skip",
[&](void* skip) { *(bool*)skip = true; });
}
SyncPoint::GetInstance()->EnableProcessing();
const char* expect =
"Number of keys in flush output SST files does not match";
// 1. During DB open flush
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
Status s = TryReopen(options);
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), expect));
// 2. During regular flush
DestroyAndReopen(options);
ASSERT_OK(Put("k1", "v1"));
ASSERT_OK(Put("k2", "v1"));
s = Flush();
ASSERT_TRUE(s.IsCorruption());
ASSERT_TRUE(std::strstr(s.getState(), expect));
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
}
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
+2 -2
View File
@@ -248,7 +248,7 @@ Status CompactedDBImpl::Init(const Options& options) {
}
Status CompactedDBImpl::Open(const Options& options, const std::string& dbname,
std::unique_ptr<DB>* dbptr) {
DB** dbptr) {
*dbptr = nullptr;
if (options.max_open_files != -1) {
@@ -267,7 +267,7 @@ Status CompactedDBImpl::Open(const Options& options, const std::string& dbname,
ROCKS_LOG_INFO(db->immutable_db_options_.info_log,
"Opened the db as fully compacted mode");
LogFlush(db->immutable_db_options_.info_log);
*dbptr = std::move(db);
*dbptr = db.release();
}
return s;
}
+1 -1
View File
@@ -22,7 +22,7 @@ class CompactedDBImpl : public DBImpl {
~CompactedDBImpl() override;
static Status Open(const Options& options, const std::string& dbname,
std::unique_ptr<DB>* dbptr);
DB** dbptr);
// Implementations of the DB interface
using DB::Get;
+569 -538
View File
File diff suppressed because it is too large. Load diff
+191 -346
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+9 -13
View File
@@ -84,7 +84,6 @@ void DBImpl::TEST_GetFilesMetaData(
}
uint64_t DBImpl::TEST_Current_Manifest_FileNo() {
InstrumentedMutexLock l(&mutex_);
return versions_->manifest_file_number();
}
@@ -104,8 +103,8 @@ Status DBImpl::TEST_CompactRange(int level, const Slice* begin,
cfd = cfh->cfd();
}
int output_level =
(cfd->ioptions().compaction_style == kCompactionStyleUniversal ||
cfd->ioptions().compaction_style == kCompactionStyleFIFO)
(cfd->ioptions()->compaction_style == kCompactionStyleUniversal ||
cfd->ioptions()->compaction_style == kCompactionStyleFIFO)
? level
: level + 1;
return RunManualCompaction(
@@ -225,13 +224,13 @@ void DBImpl::TEST_EndWrite(void* w) {
}
size_t DBImpl::TEST_LogsToFreeSize() {
InstrumentedMutexLock l(&wal_write_mutex_);
return wals_to_free_.size();
InstrumentedMutexLock l(&log_write_mutex_);
return logs_to_free_.size();
}
uint64_t DBImpl::TEST_LogfileNumber() {
InstrumentedMutexLock l(&mutex_);
return cur_wal_number_;
return logfile_number_;
}
void DBImpl::TEST_GetAllBlockCaches(
@@ -240,7 +239,7 @@ void DBImpl::TEST_GetAllBlockCaches(
for (auto cfd : *versions_->GetColumnFamilySet()) {
if (const auto bbto =
cfd->GetCurrentMutableCFOptions()
.table_factory->GetOptions<BlockBasedTableOptions>()) {
->table_factory->GetOptions<BlockBasedTableOptions>()) {
cache_set->insert(bbto->block_cache.get());
}
}
@@ -268,7 +267,7 @@ Status DBImpl::TEST_GetLatestMutableCFOptions(
InstrumentedMutexLock l(&mutex_);
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
*mutable_cf_options = cfh->cfd()->GetLatestMutableCFOptions();
*mutable_cf_options = *cfh->cfd()->GetLatestMutableCFOptions();
return Status::OK();
}
@@ -380,13 +379,10 @@ void DBImpl::TEST_VerifyNoObsoleteFilesCached(
uint64_t file_number;
GetUnaligned(reinterpret_cast<const uint64_t*>(key.data()), &file_number);
// Assert file is in live/quarantined set
bool cached_file_is_live_or_quar =
live_and_quar_files.find(file_number) != live_and_quar_files.end();
if (!cached_file_is_live_or_quar) {
// Fail with useful info
if (live_and_quar_files.find(file_number) == live_and_quar_files.end()) {
std::cerr << "File " << file_number << " is not live nor quarantined"
<< std::endl;
assert(cached_file_is_live_or_quar);
assert(false);
}
};
table_cache_->ApplyToAllEntries(fn, {});
+7 -5
View File
@@ -45,8 +45,8 @@ Status DBImpl::SuggestCompactRange(ColumnFamilyHandle* column_family,
}
// Since we have some more files to compact, we should also recompute
// compaction score
vstorage->ComputeCompactionScore(cfd->ioptions(),
cfd->GetLatestMutableCFOptions());
vstorage->ComputeCompactionScore(*cfd->ioptions(),
*cfd->GetLatestMutableCFOptions());
EnqueuePendingCompaction(cfd);
MaybeScheduleFlushOrCompaction();
}
@@ -146,11 +146,13 @@ Status DBImpl::PromoteL0(ColumnFamilyHandle* column_family, int target_level) {
f->user_defined_timestamps_persisted);
}
status = versions_->LogAndApply(cfd, read_options, write_options, &edit,
&mutex_, directories_.GetDbDir());
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
read_options, write_options, &edit, &mutex_,
directories_.GetDbDir());
if (status.ok()) {
InstallSuperVersionAndScheduleWork(
cfd, job_context.superversion_contexts.data());
cfd, job_context.superversion_contexts.data(),
*cfd->GetLatestMutableCFOptions());
}
} // lock released here
LogFlush(immutable_db_options_.info_log);
+36 -40
View File
@@ -28,7 +28,7 @@ uint64_t DBImpl::MinLogNumberToKeep() {
return versions_->min_log_number_to_keep();
}
uint64_t DBImpl::MinLogNumberToRecycle() { return min_wal_number_to_recycle_; }
uint64_t DBImpl::MinLogNumberToRecycle() { return min_log_number_to_recycle_; }
uint64_t DBImpl::MinObsoleteSstNumberToKeep() {
mutex_.AssertHeld();
@@ -159,7 +159,6 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
// Get obsolete files. This function will also update the list of
// pending files in VersionSet().
assert(versions_);
versions_->GetObsoleteFiles(
&job_context->sst_delete_files, &job_context->blob_delete_files,
&job_context->manifest_delete_files, job_context->min_pending_output);
@@ -272,77 +271,77 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
// logs_ is empty when called during recovery, in which case there can't yet
// be any tracked obsolete logs
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
if (alive_wal_files_.empty() || logs_.empty()) {
if (alive_log_files_.empty() || logs_.empty()) {
mutex_.AssertHeld();
// We may reach here if the db is DBImplSecondary
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
return;
}
bool mutex_unlocked = false;
if (!alive_wal_files_.empty() && !logs_.empty()) {
if (!alive_log_files_.empty() && !logs_.empty()) {
uint64_t min_log_number = job_context->log_number;
size_t num_alive_wal_files = alive_wal_files_.size();
size_t num_alive_log_files = alive_log_files_.size();
// find newly obsoleted log files
while (alive_wal_files_.begin()->number < min_log_number) {
auto& earliest = *alive_wal_files_.begin();
while (alive_log_files_.begin()->number < min_log_number) {
auto& earliest = *alive_log_files_.begin();
if (immutable_db_options_.recycle_log_file_num >
wal_recycle_files_.size() &&
log_recycle_files_.size() &&
earliest.number >= MinLogNumberToRecycle()) {
ROCKS_LOG_INFO(immutable_db_options_.info_log,
"adding log %" PRIu64 " to recycle list\n",
earliest.number);
wal_recycle_files_.push_back(earliest.number);
log_recycle_files_.push_back(earliest.number);
} else {
job_context->log_delete_files.push_back(earliest.number);
}
if (job_context->size_log_to_delete == 0) {
job_context->prev_wals_total_size = wals_total_size_.LoadRelaxed();
job_context->num_alive_wal_files = num_alive_wal_files;
job_context->prev_total_log_size = total_log_size_;
job_context->num_alive_log_files = num_alive_log_files;
}
job_context->size_log_to_delete += earliest.size;
wals_total_size_.FetchSubRelaxed(earliest.size);
alive_wal_files_.pop_front();
total_log_size_ -= earliest.size;
alive_log_files_.pop_front();
// Current log should always stay alive since it can't have
// number < MinLogNumber().
assert(alive_wal_files_.size());
assert(alive_log_files_.size());
}
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
mutex_.Unlock();
mutex_unlocked = true;
TEST_SYNC_POINT_CALLBACK("FindObsoleteFiles::PostMutexUnlock", nullptr);
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
while (!logs_.empty() && logs_.front().number < min_log_number) {
auto& log = logs_.front();
if (log.IsSyncing()) {
wal_sync_cv_.Wait();
log_sync_cv_.Wait();
// logs_ could have changed while we were waiting.
continue;
}
// This WAL file is not live, so it's OK if we never sync the rest of it.
// If it's already closed, then it's been fully synced. If
// !background_close_inactive_wals then we need to Close it before
// removing from logs_ but not blocking while holding wal_write_mutex_.
// removing from logs_ but not blocking while holding log_write_mutex_.
if (!immutable_db_options_.background_close_inactive_wals &&
log.writer->file()) {
// We are taking ownership of and pinning the front entry, so we can
// expect it to be the same after releasing and re-acquiring the lock
log.PrepareForSync();
wal_write_mutex_.Unlock();
log_write_mutex_.Unlock();
// TODO: maybe check the return value of Close.
// TODO: plumb Env::IOActivity, Env::IOPriority
auto s = log.writer->file()->Close({});
s.PermitUncheckedError();
wal_write_mutex_.Lock();
log_write_mutex_.Lock();
log.writer->PublishIfClosed();
assert(&log == &logs_.front());
log.FinishSync();
wal_sync_cv_.SignalAll();
log_sync_cv_.SignalAll();
}
wals_to_free_.push_back(log.ReleaseWriter());
logs_to_free_.push_back(log.ReleaseWriter());
logs_.pop_front();
}
// Current log cannot be obsolete.
@@ -350,16 +349,16 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
}
// We're just cleaning up for DB::Write().
assert(job_context->wals_to_free.empty());
job_context->wals_to_free = wals_to_free_;
assert(job_context->logs_to_free.empty());
job_context->logs_to_free = logs_to_free_;
wals_to_free_.clear();
wal_write_mutex_.Unlock();
logs_to_free_.clear();
log_write_mutex_.Unlock();
if (mutex_unlocked) {
mutex_.Lock();
}
job_context->log_recycle_files.assign(wal_recycle_files_.begin(),
wal_recycle_files_.end());
job_context->log_recycle_files.assign(log_recycle_files_.begin(),
log_recycle_files_.end());
}
// Delete obsolete files and log status and information of file deletion
@@ -368,7 +367,6 @@ void DBImpl::DeleteObsoleteFileImpl(int job_id, const std::string& fname,
FileType type, uint64_t number) {
TEST_SYNC_POINT_CALLBACK("DBImpl::DeleteObsoleteFileImpl::BeforeDeletion",
const_cast<std::string*>(&fname));
IGNORE_STATUS_IF_ERROR(Status::IOError());
Status file_deletion_status;
if (type == kTableFile || type == kBlobFile || type == kWalFile) {
@@ -424,14 +422,12 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
// FindObsoleteFiles() should've populated this so nonzero
assert(state.manifest_file_number != 0);
IGNORE_STATUS_IF_ERROR(Status::IOError());
// Now, convert lists to unordered sets, WITHOUT mutex held; set is slow.
std::unordered_set<uint64_t> sst_live_set(state.sst_live.begin(),
state.sst_live.end());
std::unordered_set<uint64_t> blob_live_set(state.blob_live.begin(),
state.blob_live.end());
std::unordered_set<uint64_t> wal_recycle_files_set(
std::unordered_set<uint64_t> log_recycle_files_set(
state.log_recycle_files.begin(), state.log_recycle_files.end());
std::unordered_set<uint64_t> quarantine_files_set(
state.files_to_quarantine.begin(), state.files_to_quarantine.end());
@@ -491,13 +487,13 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
std::unique(candidate_files.begin(), candidate_files.end()),
candidate_files.end());
if (state.prev_wals_total_size > 0) {
if (state.prev_total_log_size > 0) {
ROCKS_LOG_INFO(immutable_db_options_.info_log,
"[JOB %d] Try to delete WAL files size %" PRIu64
", prev total WAL file size %" PRIu64
", number of live WAL files %" ROCKSDB_PRIszt ".\n",
state.job_id, state.size_log_to_delete,
state.prev_wals_total_size, state.num_alive_wal_files);
state.prev_total_log_size, state.num_alive_log_files);
}
std::vector<std::string> old_info_log_files;
@@ -532,7 +528,7 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
optsfile_num2 = std::min(optsfile_num2, state.min_options_file_number);
// Close WALs before trying to delete them.
for (const auto w : state.wals_to_free) {
for (const auto w : state.logs_to_free) {
// TODO: maybe check the return value of Close.
// TODO: plumb Env::IOActivity, Env::IOPriority
auto s = w->Close({});
@@ -559,8 +555,8 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
case kWalFile:
keep = ((number >= state.log_number) ||
(number == state.prev_log_number) ||
(wal_recycle_files_set.find(number) !=
wal_recycle_files_set.end()));
(log_recycle_files_set.find(number) !=
log_recycle_files_set.end()));
break;
case kDescriptorFile:
// Keep my manifest file, and any newer incarnations'
@@ -1043,7 +1039,7 @@ std::set<std::string> DBImpl::CollectAllDBPaths() {
all_db_paths.insert(NormalizePath(db_path.path));
}
for (const auto* cfd : *versions_->GetColumnFamilySet()) {
for (const auto& cf_path : cfd->ioptions().cf_paths) {
for (const auto& cf_path : cfd->ioptions()->cf_paths) {
all_db_paths.insert(NormalizePath(cf_path.path));
}
}
+6 -1
View File
@@ -70,6 +70,9 @@ Status DBImplFollower::Recover(
}
return s;
}
if (immutable_db_options_.paranoid_checks && s.ok()) {
s = CheckConsistency();
}
if (s.ok()) {
default_cf_handle_ = new ColumnFamilyHandleImpl(
versions_->GetColumnFamilySet()->GetDefault(), this, &mutex_);
@@ -137,8 +140,10 @@ Status DBImplFollower::TryCatchUpWithLeader() {
// to super versions in a lock free manner, it checks the earliest
// sequence number to detect if there was a change in version in
// the meantime.
const MutableCFOptions mutable_cf_options =
*cfd->GetLatestMutableCFOptions();
MemTable* new_mem = cfd->ConstructNewMemtable(
cfd->GetLatestMutableCFOptions(), versions_->LastSequence());
mutable_cf_options, versions_->LastSequence());
cfd->mem()->SetNextLogNumber(cfd->GetLogNumber());
cfd->mem()->ConstructFragmentedRangeTombstones();
cfd->imm()->Add(cfd->mem(), &job_context.memtables_to_free);
+389 -759
View File
File diff suppressed because it is too large. Load diff
+32 -35
View File
@@ -16,6 +16,7 @@
namespace ROCKSDB_NAMESPACE {
DBImplReadOnly::DBImplReadOnly(const DBOptions& db_options,
const std::string& dbname)
: DBImpl(db_options, dbname, /*seq_per_batch*/ false,
@@ -32,8 +33,7 @@ Status DBImplReadOnly::GetImpl(const ReadOptions& read_options,
const Slice& key,
GetImplOptions& get_impl_options) {
assert(get_impl_options.value != nullptr ||
get_impl_options.columns != nullptr ||
get_impl_options.merge_operands != nullptr);
get_impl_options.columns != nullptr);
assert(get_impl_options.column_family);
Status s;
@@ -87,11 +87,7 @@ Status DBImplReadOnly::GetImpl(const ReadOptions& read_options,
return s;
}
}
// Prepare to store a list of merge operations if merge occurs.
MergeContext merge_context;
// TODO - Large Result Optimization for Read Only DB
// (https://github.com/facebook/rocksdb/pull/10458)
SequenceNumber max_covering_tombstone_seq = 0;
LookupKey lkey(key, snapshot, read_options.timestamp);
PERF_TIMER_STOP(get_snapshot_time);
@@ -102,8 +98,7 @@ Status DBImplReadOnly::GetImpl(const ReadOptions& read_options,
get_impl_options.value ? get_impl_options.value->GetSelf() : nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options,
false /* immutable_memtable */, &read_cb,
/*is_blob_index=*/nullptr, /*do_merge=*/get_impl_options.get_value)) {
false /* immutable_memtable */, &read_cb)) {
if (get_impl_options.value) {
get_impl_options.value->PinSelf();
}
@@ -117,7 +112,7 @@ Status DBImplReadOnly::GetImpl(const ReadOptions& read_options,
/*value_found*/ nullptr,
/*key_exists*/ nullptr, /*seq*/ nullptr, &read_cb,
/*is_blob*/ nullptr,
/*do_merge=*/get_impl_options.get_value);
/*do_merge*/ true);
RecordTick(stats_, MEMTABLE_MISS);
}
{
@@ -127,14 +122,6 @@ Status DBImplReadOnly::GetImpl(const ReadOptions& read_options,
size = get_impl_options.value->size();
} else if (get_impl_options.columns) {
size = get_impl_options.columns->serialized_size();
} else if (get_impl_options.merge_operands) {
*get_impl_options.number_of_operands =
static_cast<int>(merge_context.GetNumOperands());
for (const Slice& sl : merge_context.GetOperands()) {
size += sl.size();
get_impl_options.merge_operands->PinSelf(sl);
get_impl_options.merge_operands++;
}
}
RecordTick(stats_, BYTES_READ, size);
RecordInHistogram(stats_, BYTES_PER_READ, size);
@@ -185,10 +172,16 @@ Iterator* DBImplReadOnly::NewIterator(const ReadOptions& _read_options,
? static_cast<const SnapshotImpl*>(read_options.snapshot)->number_
: latest_snapshot;
ReadCallback* read_callback = nullptr; // No read callback provided.
return NewArenaWrappedDbIterator(
env_, read_options, cfh, super_version, read_seq, read_callback, this,
/*expose_blob_index=*/false, /*allow_refresh=*/false,
/*allow_mark_memtable_for_flush=*/false);
auto db_iter = NewArenaWrappedDbIterator(
env_, read_options, *cfd->ioptions(), super_version->mutable_cf_options,
super_version->current, read_seq,
super_version->mutable_cf_options.max_sequential_skip_in_iterations,
super_version->version_number, read_callback);
auto internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfd, super_version, db_iter->GetArena(),
read_seq, /* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
}
Status DBImplReadOnly::NewIterators(
@@ -225,32 +218,36 @@ Status DBImplReadOnly::NewIterators(
? static_cast<const SnapshotImpl*>(read_options.snapshot)->number_
: latest_snapshot;
autovector<std::tuple<ColumnFamilyHandleImpl*, SuperVersion*>> cfh_to_sv;
autovector<std::tuple<ColumnFamilyData*, SuperVersion*>> cfd_to_sv;
const bool check_read_ts =
read_options.timestamp && read_options.timestamp->size() > 0;
for (auto cfh : column_families) {
auto* cfd = static_cast_with_check<ColumnFamilyHandleImpl>(cfh)->cfd();
auto* sv = cfd->GetSuperVersion()->Ref();
cfh_to_sv.emplace_back(static_cast_with_check<ColumnFamilyHandleImpl>(cfh),
sv);
cfd_to_sv.emplace_back(cfd, sv);
if (check_read_ts) {
const Status s =
FailIfReadCollapsedHistory(cfd, sv, *(read_options.timestamp));
if (!s.ok()) {
for (auto prev_entry : cfh_to_sv) {
for (auto prev_entry : cfd_to_sv) {
std::get<1>(prev_entry)->Unref();
}
return s;
}
}
}
assert(cfh_to_sv.size() == column_families.size());
for (auto [cfh, sv] : cfh_to_sv) {
assert(cfd_to_sv.size() == column_families.size());
for (auto [cfd, sv] : cfd_to_sv) {
auto* db_iter = NewArenaWrappedDbIterator(
env_, read_options, cfh, sv, read_seq, read_callback, this,
/*expose_blob_index=*/false, /*allow_refresh=*/false,
/*allow_mark_memtable_for_flush=*/false);
env_, read_options, *cfd->ioptions(), sv->mutable_cf_options,
sv->current, read_seq,
sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback);
auto* internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfd, sv, db_iter->GetArena(), read_seq,
/* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
iterators->push_back(db_iter);
}
@@ -279,8 +276,7 @@ Status OpenForReadOnlyCheckExistence(const DBOptions& db_options,
} // namespace
Status DB::OpenForReadOnly(const Options& options, const std::string& dbname,
std::unique_ptr<DB>* dbptr,
bool /*error_if_wal_file_exists*/) {
DB** dbptr, bool /*error_if_wal_file_exists*/) {
Status s = OpenForReadOnlyCheckExistence(options, dbname);
if (!s.ok()) {
return s;
@@ -314,7 +310,7 @@ Status DB::OpenForReadOnly(const Options& options, const std::string& dbname,
Status DB::OpenForReadOnly(
const DBOptions& db_options, const std::string& dbname,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, std::unique_ptr<DB>* dbptr,
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr,
bool error_if_wal_file_exists) {
// If dbname does not exist in the file system, should not do anything
Status s = OpenForReadOnlyCheckExistence(db_options, dbname);
@@ -330,7 +326,7 @@ Status DB::OpenForReadOnly(
Status DBImplReadOnly::OpenForReadOnlyWithoutCheck(
const DBOptions& db_options, const std::string& dbname,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, std::unique_ptr<DB>* dbptr,
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr,
bool error_if_wal_file_exists) {
*dbptr = nullptr;
handles->clear();
@@ -361,7 +357,7 @@ Status DBImplReadOnly::OpenForReadOnlyWithoutCheck(
impl->mutex_.Unlock();
sv_context.Clean();
if (s.ok()) {
dbptr->reset(impl);
*dbptr = impl;
for (auto* h : *handles) {
impl->NewThreadStatusCfInfo(
static_cast_with_check<ColumnFamilyHandleImpl>(h)->cfd());
@@ -376,4 +372,5 @@ Status DBImplReadOnly::OpenForReadOnlyWithoutCheck(
return s;
}
} // namespace ROCKSDB_NAMESPACE
+2 -24
View File
@@ -5,6 +5,7 @@
#pragma once
#include <string>
#include <vector>
@@ -155,29 +156,6 @@ class DBImplReadOnly : public DBImpl {
return Status::NotSupported("Not supported operation in read only mode.");
}
using DB::CreateColumnFamily;
using DBImpl::CreateColumnFamily;
Status CreateColumnFamily(const ColumnFamilyOptions& /*cf_options*/,
const std::string& /*column_family*/,
ColumnFamilyHandle** /*handle*/) override {
return Status::NotSupported("Not supported operation in read only mode.");
}
using DB::CreateColumnFamilies;
using DBImpl::CreateColumnFamilies;
Status CreateColumnFamilies(
const ColumnFamilyOptions& /*cf_options*/,
const std::vector<std::string>& /*column_family_names*/,
std::vector<ColumnFamilyHandle*>* /*handles*/) override {
return Status::NotSupported("Not supported operation in read only mode.");
}
Status CreateColumnFamilies(
const std::vector<ColumnFamilyDescriptor>& /*column_families*/,
std::vector<ColumnFamilyHandle*>* /*handles*/) override {
return Status::NotSupported("Not supported operation in read only mode.");
}
// FIXME: some missing overrides for more "write" functions
protected:
@@ -194,7 +172,7 @@ class DBImplReadOnly : public DBImpl {
static Status OpenForReadOnlyWithoutCheck(
const DBOptions& db_options, const std::string& dbname,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, std::unique_ptr<DB>* dbptr,
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr,
bool error_if_wal_file_exists = false);
friend class DB;
};
+112 -136
View File
@@ -49,12 +49,15 @@ Status DBImplSecondary::Recover(
}
return s;
}
if (immutable_db_options_.paranoid_checks && s.ok()) {
s = CheckConsistency();
}
// Initial max_total_in_memory_state_ before recovery logs.
max_total_in_memory_state_ = 0;
for (auto cfd : *versions_->GetColumnFamilySet()) {
const auto& mutable_cf_options = cfd->GetLatestMutableCFOptions();
max_total_in_memory_state_ += mutable_cf_options.write_buffer_size *
mutable_cf_options.max_write_buffer_number;
auto* mutable_cf_options = cfd->GetLatestMutableCFOptions();
max_total_in_memory_state_ += mutable_cf_options->write_buffer_size *
mutable_cf_options->max_write_buffer_number;
}
if (s.ok()) {
default_cf_handle_ = new ColumnFamilyHandleImpl(
@@ -267,8 +270,10 @@ Status DBImplSecondary::RecoverLogFiles(
if (!cfd->mem()->IsEmpty() &&
(curr_log_num == std::numeric_limits<uint64_t>::max() ||
curr_log_num != log_number)) {
MemTable* new_mem = cfd->ConstructNewMemtable(
cfd->GetLatestMutableCFOptions(), seq_of_batch);
const MutableCFOptions mutable_cf_options =
*cfd->GetLatestMutableCFOptions();
MemTable* new_mem =
cfd->ConstructNewMemtable(mutable_cf_options, seq_of_batch);
cfd->mem()->SetNextLogNumber(log_number);
cfd->mem()->ConstructFragmentedRangeTombstones();
cfd->imm()->Add(cfd->mem(), &job_context->memtables_to_free);
@@ -339,8 +344,7 @@ Status DBImplSecondary::GetImpl(const ReadOptions& read_options,
const Slice& key,
GetImplOptions& get_impl_options) {
assert(get_impl_options.value != nullptr ||
get_impl_options.columns != nullptr ||
get_impl_options.merge_operands != nullptr);
get_impl_options.columns != nullptr);
assert(get_impl_options.column_family);
Status s;
@@ -395,64 +399,37 @@ Status DBImplSecondary::GetImpl(const ReadOptions& read_options,
}
}
MergeContext merge_context;
// TODO - Large Result Optimization for Secondary DB
// (https://github.com/facebook/rocksdb/pull/10458)
SequenceNumber max_covering_tombstone_seq = 0;
LookupKey lkey(key, snapshot, read_options.timestamp);
PERF_TIMER_STOP(get_snapshot_time);
bool done = false;
// Look up starts here
if (get_impl_options.get_value) {
if (super_version->mem->Get(
lkey,
get_impl_options.value ? get_impl_options.value->GetSelf()
: nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options,
false /* immutable_memtable */, &read_cb,
/*is_blob_index=*/nullptr, /*do_merge=*/true)) {
done = true;
if (get_impl_options.value) {
get_impl_options.value->PinSelf();
}
RecordTick(stats_, MEMTABLE_HIT);
} else if ((s.ok() || s.IsMergeInProgress()) &&
super_version->imm->Get(
lkey,
get_impl_options.value ? get_impl_options.value->GetSelf()
: nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options, &read_cb)) {
done = true;
if (get_impl_options.value) {
get_impl_options.value->PinSelf();
}
RecordTick(stats_, MEMTABLE_HIT);
if (super_version->mem->Get(
lkey,
get_impl_options.value ? get_impl_options.value->GetSelf() : nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options,
false /* immutable_memtable */, &read_cb)) {
done = true;
if (get_impl_options.value) {
get_impl_options.value->PinSelf();
}
} else {
// GetMergeOperands
if (super_version->mem->Get(
lkey,
get_impl_options.value ? get_impl_options.value->GetSelf()
: nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options,
false /* immutable_memtable */, &read_cb,
/*is_blob_index=*/nullptr, /*do_merge=*/false)) {
done = true;
RecordTick(stats_, MEMTABLE_HIT);
} else if ((s.ok() || s.IsMergeInProgress()) &&
super_version->imm->GetMergeOperands(lkey, &s, &merge_context,
&max_covering_tombstone_seq,
read_options)) {
done = true;
RecordTick(stats_, MEMTABLE_HIT);
RecordTick(stats_, MEMTABLE_HIT);
} else if ((s.ok() || s.IsMergeInProgress()) &&
super_version->imm->Get(
lkey,
get_impl_options.value ? get_impl_options.value->GetSelf()
: nullptr,
get_impl_options.columns, ts, &s, &merge_context,
&max_covering_tombstone_seq, read_options, &read_cb)) {
done = true;
if (get_impl_options.value) {
get_impl_options.value->PinSelf();
}
RecordTick(stats_, MEMTABLE_HIT);
}
if (!s.ok() && !s.IsMergeInProgress() && !s.IsNotFound()) {
assert(done);
if (!done && !s.ok() && !s.IsMergeInProgress()) {
ReturnAndCleanupSuperVersion(cfd, super_version);
return s;
}
@@ -476,14 +453,6 @@ Status DBImplSecondary::GetImpl(const ReadOptions& read_options,
size = get_impl_options.value->size();
} else if (get_impl_options.columns) {
size = get_impl_options.columns->serialized_size();
} else if (get_impl_options.merge_operands) {
*get_impl_options.number_of_operands =
static_cast<int>(merge_context.GetNumOperands());
for (const Slice& sl : merge_context.GetOperands()) {
size += sl.size();
get_impl_options.merge_operands->PinSelf(sl);
get_impl_options.merge_operands++;
}
}
RecordTick(stats_, BYTES_READ, size);
RecordTimeToHistogram(stats_, BYTES_PER_READ, size);
@@ -563,10 +532,17 @@ ArenaWrappedDBIter* DBImplSecondary::NewIteratorImpl(
assert(snapshot == kMaxSequenceNumber);
snapshot = versions_->LastSequence();
assert(snapshot != kMaxSequenceNumber);
return NewArenaWrappedDbIterator(env_, read_options, cfh, super_version,
snapshot, read_callback, this,
expose_blob_index, allow_refresh,
/*allow_mark_memtable_for_flush=*/false);
auto db_iter = NewArenaWrappedDbIterator(
env_, read_options, *cfh->cfd()->ioptions(),
super_version->mutable_cf_options, super_version->current, snapshot,
super_version->mutable_cf_options.max_sequential_skip_in_iterations,
super_version->version_number, read_callback, cfh, expose_blob_index,
allow_refresh);
auto internal_iter = NewInternalIterator(
db_iter->GetReadOptions(), cfh->cfd(), super_version, db_iter->GetArena(),
snapshot, /* allow_unprepared_value */ true, db_iter);
db_iter->SetIterUnderDBIter(internal_iter);
return db_iter;
}
Status DBImplSecondary::NewIterators(
@@ -650,15 +626,58 @@ Status DBImplSecondary::NewIterators(
return Status::OK();
}
Status DBImplSecondary::CheckConsistency() {
mutex_.AssertHeld();
Status s = DBImpl::CheckConsistency();
// If DBImpl::CheckConsistency() which is stricter returns success, then we
// do not need to give a second chance.
if (s.ok()) {
return s;
}
// It's possible that DBImpl::CheckConssitency() can fail because the primary
// may have removed certain files, causing the GetFileSize(name) call to
// fail and returning a PathNotFound. In this case, we take a best-effort
// approach and just proceed.
TEST_SYNC_POINT_CALLBACK(
"DBImplSecondary::CheckConsistency:AfterFirstAttempt", &s);
if (immutable_db_options_.skip_checking_sst_file_sizes_on_db_open) {
return Status::OK();
}
std::vector<LiveFileMetaData> metadata;
versions_->GetLiveFilesMetaData(&metadata);
std::string corruption_messages;
for (const auto& md : metadata) {
// md.name has a leading "/".
std::string file_path = md.db_path + md.name;
uint64_t fsize = 0;
s = env_->GetFileSize(file_path, &fsize);
if (!s.ok() &&
(env_->GetFileSize(Rocks2LevelTableFileName(file_path), &fsize).ok() ||
s.IsPathNotFound())) {
s = Status::OK();
}
if (!s.ok()) {
corruption_messages +=
"Can't access " + md.name + ": " + s.ToString() + "\n";
}
}
return corruption_messages.empty() ? Status::OK()
: Status::Corruption(corruption_messages);
}
Status DBImplSecondary::TryCatchUpWithPrimary() {
assert(versions_.get() != nullptr);
assert(manifest_reader_.get() != nullptr);
Status s;
// read the manifest and apply new changes to the secondary instance
std::unordered_set<ColumnFamilyData*> cfds_changed;
JobContext job_context(0, true /*create_superversion*/);
{
InstrumentedMutexLock lock_guard(&mutex_);
assert(manifest_reader_.get() != nullptr);
s = static_cast_with_check<ReactiveVersionSet>(versions_.get())
->ReadAndApply(&mutex_, &manifest_reader_,
manifest_reader_status_.get(), &cfds_changed,
@@ -682,13 +701,13 @@ Status DBImplSecondary::TryCatchUpWithPrimary() {
// instance
if (s.ok()) {
s = FindAndRecoverLogFiles(&cfds_changed, &job_context);
if (s.IsPathNotFound()) {
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
"Secondary tries to read WAL, but WAL file(s) have already "
"been purged by primary.");
s = Status::OK();
}
}
if (s.IsPathNotFound()) {
ROCKS_LOG_INFO(
immutable_db_options_.info_log,
"Secondary tries to read WAL, but WAL file(s) have already "
"been purged by primary.");
s = Status::OK();
}
if (s.ok()) {
for (auto cfd : cfds_changed) {
@@ -718,8 +737,7 @@ Status DBImplSecondary::TryCatchUpWithPrimary() {
}
Status DB::OpenAsSecondary(const Options& options, const std::string& dbname,
const std::string& secondary_path,
std::unique_ptr<DB>* dbptr) {
const std::string& secondary_path, DB** dbptr) {
*dbptr = nullptr;
DBOptions db_options(options);
@@ -741,7 +759,7 @@ Status DB::OpenAsSecondary(
const DBOptions& db_options, const std::string& dbname,
const std::string& secondary_path,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, std::unique_ptr<DB>* dbptr) {
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr) {
*dbptr = nullptr;
DBOptions tmp_opts(db_options);
@@ -808,7 +826,7 @@ Status DB::OpenAsSecondary(
impl->mutex_.Unlock();
sv_context.Clean();
if (s.ok()) {
dbptr->reset(impl);
*dbptr = impl;
for (auto h : *handles) {
impl->NewThreadStatusCfInfo(
static_cast_with_check<ColumnFamilyHandleImpl>(h)->cfd());
@@ -846,47 +864,31 @@ Status DBImplSecondary::CompactWithoutInstallation(
ColumnFamilyMetaData cf_meta;
version->GetColumnFamilyMetaData(&cf_meta);
const MutableCFOptions* mutable_cf_options = cfd->GetLatestMutableCFOptions();
ColumnFamilyOptions cf_options = cfd->GetLatestCFOptions();
VersionStorageInfo* vstorage = version->storage_info();
// Use comp_options to reuse some CompactFiles functions
CompactionOptions comp_options;
comp_options.compression = kDisableCompressionOption;
comp_options.output_file_size_limit = MaxFileSizeForLevel(
cfd->GetLatestMutableCFOptions(), input.output_level,
cfd->ioptions().compaction_style, vstorage->base_level(),
cfd->ioptions().level_compaction_dynamic_level_bytes);
*mutable_cf_options, input.output_level, cf_options.compaction_style,
vstorage->base_level(), cf_options.level_compaction_dynamic_level_bytes);
std::vector<CompactionInputFiles> input_files;
Status s = cfd->compaction_picker()->GetCompactionInputsFromFileNumbers(
&input_files, &input_set, vstorage, comp_options);
if (!s.ok()) {
ROCKS_LOG_ERROR(
immutable_db_options_.info_log,
"GetCompactionInputsFromFileNumbers() failed - %s.\n DebugString: %s",
s.ToString().c_str(), version->DebugString(/*hex=*/true).c_str());
return s;
}
const int job_id = next_job_id_.fetch_add(1);
JobContext job_context(job_id, true /*create_superversion*/);
std::vector<SequenceNumber> snapshots = input.snapshots;
// TODO - snapshot_checker support in Remote Compaction
job_context.InitSnapshotContext(/*checker=*/nullptr,
/*managed_snapshot=*/nullptr,
kMaxSequenceNumber, std::move(snapshots));
// TODO - consider serializing the entire Compaction object and using it as
// input instead of recreating it in the remote worker
std::unique_ptr<Compaction> c;
assert(cfd->compaction_picker());
c.reset(cfd->compaction_picker()->CompactFiles(
comp_options, input_files, input.output_level, vstorage,
cfd->GetLatestMutableCFOptions(), mutable_db_options_, 0,
/*earliest_snapshot=*/job_context.snapshot_seqs.empty()
? kMaxSequenceNumber
: job_context.snapshot_seqs.front(),
job_context.snapshot_checker));
*mutable_cf_options, mutable_db_options_, 0));
assert(c != nullptr);
c->FinalizeInputInfo(version);
// Create output directory if it's not existed yet
@@ -899,6 +901,8 @@ Status DBImplSecondary::CompactWithoutInstallation(
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL,
immutable_db_options_.info_log.get());
const int job_id = next_job_id_.fetch_add(1);
// use primary host's db_id for running the compaction, but db_session_id is
// using the local one, which is to make sure the unique id is unique from
// the remote compactors. Because the id is generated from db_id,
@@ -909,12 +913,10 @@ Status DBImplSecondary::CompactWithoutInstallation(
job_id, c.get(), immutable_db_options_, mutable_db_options_,
file_options_for_compaction_, versions_.get(), &shutting_down_,
&log_buffer, output_dir.get(), stats_, &mutex_, &error_handler_,
&job_context, table_cache_, &event_logger_, dbname_, io_tracer_,
input.snapshots, table_cache_, &event_logger_, dbname_, io_tracer_,
options.canceled ? *options.canceled : kManualCompactionCanceledFalse_,
input.db_id, db_session_id_, secondary_path_, input, result);
compaction_job.Prepare();
mutex_.Unlock();
s = compaction_job.Run();
mutex_.Lock();
@@ -949,10 +951,9 @@ Status DB::OpenAndCompact(
}
// 2. Load the options
DBOptions base_db_options;
DBOptions db_options;
ConfigOptions config_options;
config_options.env = override_options.env;
config_options.ignore_unknown_options = true;
std::vector<ColumnFamilyDescriptor> all_column_families;
TEST_SYNC_POINT_CALLBACK(
@@ -962,22 +963,13 @@ Status DB::OpenAndCompact(
std::string options_file_name =
OptionsFileName(name, compaction_input.options_file_number);
s = LoadOptionsFromFile(config_options, options_file_name, &base_db_options,
s = LoadOptionsFromFile(config_options, options_file_name, &db_options,
&all_column_families);
if (!s.ok()) {
return s;
}
// 3. Options to Override
// Override serializable configurations from override_options.options_map
DBOptions db_options;
s = GetDBOptionsFromMap(config_options, base_db_options,
override_options.options_map, &db_options);
if (!s.ok()) {
return s;
}
// Override options that are directly set as shared ptrs in
// 3. Override pointer configurations in DBOptions with
// CompactionServiceOptionsOverride
db_options.env = override_options.env;
db_options.file_checksum_gen_factory =
@@ -988,7 +980,6 @@ Status DB::OpenAndCompact(
// We will close the DB after the compaction anyway.
// Open as many files as needed for the compaction.
db_options.max_open_files = -1;
db_options.info_log = override_options.info_log;
// 4. Filter CFs that are needed for OpenAndCompact()
// We do not need to open all column families for the remote compaction.
@@ -998,18 +989,6 @@ Status DB::OpenAndCompact(
std::vector<ColumnFamilyDescriptor> column_families;
for (auto& cf : all_column_families) {
if (cf.name == compaction_input.cf_name) {
ColumnFamilyOptions cf_options;
// Override serializable configurations from override_options.options_map
s = GetColumnFamilyOptionsFromMap(config_options, cf.options,
override_options.options_map,
&cf_options);
if (!s.ok()) {
return s;
}
cf.options = std::move(cf_options);
// Override options that are directly set as shared ptrs in
// CompactionServiceOptionsOverride
cf.options.comparator = override_options.comparator;
cf.options.merge_operator = override_options.merge_operator;
cf.options.compaction_filter = override_options.compaction_filter;
@@ -1021,7 +1000,6 @@ Status DB::OpenAndCompact(
override_options.sst_partitioner_factory;
cf.options.table_properties_collector_factories =
override_options.table_properties_collector_factories;
column_families.emplace_back(cf);
} else if (cf.name == kDefaultColumnFamilyName) {
column_families.emplace_back(cf);
@@ -1038,9 +1016,6 @@ Status DB::OpenAndCompact(
}
assert(db);
TEST_SYNC_POINT_CALLBACK(
"DBImplSecondary::OpenAndCompact::AfterOpenAsSecondary:0", db);
// 6. Find the handle of the Column Family that this will compact
ColumnFamilyHandle* cfh = nullptr;
for (auto* handle : handles) {
@@ -1082,4 +1057,5 @@ Status DB::OpenAndCompact(
output, override_options);
}
} // namespace ROCKSDB_NAMESPACE
+8 -2
View File
@@ -5,6 +5,7 @@
#pragma once
#include <string>
#include <vector>
@@ -52,8 +53,7 @@ class LogReaderContainer {
Logger* info_log;
std::string fname;
Status* status; // nullptr if immutable_db_options_.paranoid_checks==false
void Corruption(size_t bytes, const Status& s,
uint64_t /*log_number*/ = kMaxSequenceNumber) override {
void Corruption(size_t bytes, const Status& s) override {
ROCKS_LOG_WARN(info_log, "%s%s: dropping %d bytes; %s",
(this->status == nullptr ? "(ignoring error) " : ""),
fname.c_str(), static_cast<int>(bytes),
@@ -248,6 +248,12 @@ class DBImplSecondary : public DBImpl {
Status MaybeInitLogReader(uint64_t log_number,
log::FragmentBufferedReader** log_reader);
// Check if all live files exist on file system and that their file sizes
// matche to the in-memory records. It is possible that some live files may
// have been deleted by the primary. In this case, CheckConsistency() does
// not flag the missing file as inconsistency.
Status CheckConsistency() override;
#ifndef NDEBUG
Status TEST_CompactWithoutInstallation(const OpenAndCompactOptions& options,
ColumnFamilyHandle* cfh,
File diff suppressed because it is too large. Load diff
+5 -15
View File
@@ -7,8 +7,6 @@
// 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 <iomanip>
#include "db/db_test_util.h"
#include "port/stack_trace.h"
#include "test_util/testutil.h"
@@ -99,20 +97,12 @@ class CorruptionFS : public FileSystemWrapper {
for (size_t i = 0; i < num_reqs; ++i) {
FSReadRequest& req = reqs[i];
if (fs_.fs_buffer_) {
// See https://github.com/facebook/rocksdb/pull/13195 for why we
// want to set up our test implementation for FSAllocationPtr this
// way.
char* internalData = new char[req.len];
req.status = Read(req.offset, req.len, options, &req.result,
internalData, dbg);
Slice* internalSlice = new Slice(internalData, req.len);
FSAllocationPtr internalPtr(internalSlice, [](void* ptr) {
delete[] static_cast<const char*>(
static_cast<Slice*>(ptr)->data_);
delete static_cast<Slice*>(ptr);
FSAllocationPtr buffer(new char[req.len], [](void* ptr) {
delete[] static_cast<char*>(ptr);
});
req.fs_scratch = std::move(internalPtr);
req.fs_scratch = std::move(buffer);
req.status = Read(req.offset, req.len, options, &req.result,
static_cast<char*>(req.fs_scratch.get()), dbg);
} else {
req.status = Read(req.offset, req.len, options, &req.result,
req.scratch, dbg);
+29 -42
View File
@@ -9,6 +9,7 @@
#include "db/db_iter.h"
#include <iostream>
#include <limits>
#include <string>
@@ -41,8 +42,9 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
const MutableCFOptions& mutable_cf_options,
const Comparator* cmp, InternalIterator* iter,
const Version* version, SequenceNumber s, bool arena_mode,
uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index, ReadOnlyMemTable* active_mem)
bool expose_blob_index)
: prefix_extractor_(mutable_cf_options.prefix_extractor.get()),
env_(_env),
clock_(ioptions.clock),
@@ -56,21 +58,11 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
read_callback_(read_callback),
sequence_(s),
statistics_(ioptions.stats),
max_skip_(mutable_cf_options.max_sequential_skip_in_iterations),
max_skip_(max_sequential_skip_in_iterations),
max_skippable_internal_keys_(read_options.max_skippable_internal_keys),
num_internal_keys_skipped_(0),
iterate_lower_bound_(read_options.iterate_lower_bound),
iterate_upper_bound_(read_options.iterate_upper_bound),
cfh_(cfh),
timestamp_ub_(read_options.timestamp),
timestamp_lb_(read_options.iter_start_ts),
timestamp_size_(timestamp_ub_ ? timestamp_ub_->size() : 0),
active_mem_(active_mem),
memtable_seqno_lb_(kMaxSequenceNumber),
memtable_op_scan_flush_trigger_(0),
avg_op_scan_flush_trigger_(0),
iter_step_since_seek_(1),
mem_hidden_op_scanned_since_seek_(0),
direction_(kForward),
valid_(false),
current_entry_is_merged_(false),
@@ -84,7 +76,11 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
expose_blob_index_(expose_blob_index),
allow_unprepared_value_(read_options.allow_unprepared_value),
is_blob_(false),
arena_mode_(arena_mode) {
arena_mode_(arena_mode),
cfh_(cfh),
timestamp_ub_(read_options.timestamp),
timestamp_lb_(read_options.iter_start_ts),
timestamp_size_(timestamp_ub_ ? timestamp_ub_->size() : 0) {
RecordTick(statistics_, NO_ITERATOR_CREATED);
if (pin_thru_lifetime_) {
pinned_iters_mgr_.StartPinning();
@@ -98,25 +94,6 @@ DBIter::DBIter(Env* _env, const ReadOptions& read_options,
// prefix_seek_opt_in_only should force total_order_seek whereever the caller
// is duplicating the original ReadOptions
assert(!ioptions.prefix_seek_opt_in_only || read_options.total_order_seek);
if (active_mem_) {
// FIXME: GetEarliestSequenceNumber() may return a seqno that is one smaller
// than the smallest seqno in the memtable. This violates its comment and
// entries with that seqno may not be in the active memtable. Before it's
// fixed, we use GetFirstSequenceNumber() for more accurate result.
memtable_seqno_lb_ = active_mem_->IsEmpty()
? active_mem_->GetEarliestSequenceNumber()
: active_mem_->GetFirstSequenceNumber();
memtable_op_scan_flush_trigger_ =
mutable_cf_options.memtable_op_scan_flush_trigger;
if (memtable_op_scan_flush_trigger_) {
// avg_op_scan_flush_trigger_ requires memtable_op_scan_flush_trigger_ > 0
avg_op_scan_flush_trigger_ =
mutable_cf_options.memtable_avg_op_scan_flush_trigger;
}
} else {
// memtable_op_scan_flush_trigger_ and avg_op_scan_flush_trigger_ are
// initialized to 0(disabled) as default.
}
}
Status DBIter::GetProperty(std::string prop_name, std::string* prop) {
@@ -178,7 +155,6 @@ void DBIter::Next() {
local_stats_.skip_count_ += num_internal_keys_skipped_;
local_stats_.skip_count_--;
num_internal_keys_skipped_ = 0;
iter_step_since_seek_++;
bool ok = true;
if (direction_ == kReverse) {
is_key_seqnum_zero_ = false;
@@ -393,7 +369,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
// to one.
bool reseek_done = false;
uint64_t mem_hidden_op_scanned = 0;
do {
// Will update is_key_seqnum_zero_ as soon as we parsed the current key
// but we need to save the previous value to be used in the loop.
@@ -450,7 +425,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
CompareKeyForSkip(ikey_.user_key, saved_key_.GetUserKey()) <= 0) {
num_skipped++; // skip this entry
PERF_COUNTER_ADD(internal_key_skipped_count, 1);
MarkMemtableForFlushForPerOpTrigger(mem_hidden_op_scanned);
} else {
assert(!skipping_saved_key ||
CompareKeyForSkip(ikey_.user_key, saved_key_.GetUserKey()) > 0);
@@ -472,7 +446,6 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
!iter_.iter()->IsKeyPinned() /* copy */);
skipping_saved_key = true;
PERF_COUNTER_ADD(internal_delete_skipped_count, 1);
MarkMemtableForFlushForPerOpTrigger(mem_hidden_op_scanned);
}
break;
case kTypeValue:
@@ -511,6 +484,7 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
valid_ = true;
return true;
break;
case kTypeMerge:
if (!PrepareValueInternal()) {
return false;
@@ -522,6 +496,7 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
current_entry_is_merged_ = true;
valid_ = true;
return MergeValuesNewToOld(); // Go to a different state machine
break;
default:
valid_ = false;
status_ = Status::Corruption(
@@ -1122,6 +1097,7 @@ bool DBIter::FindValueForCurrentKey() {
}
return true;
}
break;
case kTypeValue:
case kTypeValuePreferredSeqno:
SetValueAndColumnsFromPlain(pinned_value_);
@@ -1248,8 +1224,6 @@ bool DBIter::FindValueForCurrentKeyUsingSeek() {
if (timestamp_lb_ != nullptr) {
saved_key_.SetInternalKey(ikey);
} else {
saved_key_.SetUserKey(ikey.user_key);
}
valid_ = true;
@@ -1594,7 +1568,6 @@ void DBIter::Seek(const Slice& target) {
ResetBlobData();
ResetValueAndColumns();
ResetInternalKeysSkippedCounter();
MarkMemtableForFlushForAvgTrigger();
// Seek the inner iterator based on the target key.
{
@@ -1671,7 +1644,6 @@ void DBIter::SeekForPrev(const Slice& target) {
ResetBlobData();
ResetValueAndColumns();
ResetInternalKeysSkippedCounter();
MarkMemtableForFlushForAvgTrigger();
// Seek the inner iterator based on the target key.
{
@@ -1733,7 +1705,6 @@ void DBIter::SeekToFirst() {
ResetBlobData();
ResetValueAndColumns();
ResetInternalKeysSkippedCounter();
MarkMemtableForFlushForAvgTrigger();
ClearSavedValue();
is_key_seqnum_zero_ = false;
@@ -1797,7 +1768,6 @@ void DBIter::SeekToLast() {
ResetBlobData();
ResetValueAndColumns();
ResetInternalKeysSkippedCounter();
MarkMemtableForFlushForAvgTrigger();
ClearSavedValue();
is_key_seqnum_zero_ = false;
@@ -1820,4 +1790,21 @@ void DBIter::SeekToLast() {
StripTimestampFromUserKey(saved_key_.GetUserKey(), timestamp_size_)));
}
}
Iterator* NewDBIterator(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator,
InternalIterator* internal_iter, const Version* version,
const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index) {
DBIter* db_iter = new DBIter(
env, read_options, ioptions, mutable_cf_options, user_key_comparator,
internal_iter, version, sequence, false,
max_sequential_skip_in_iterations, read_callback, cfh, expose_blob_index);
return db_iter;
}
} // namespace ROCKSDB_NAMESPACE
+31 -96
View File
@@ -12,6 +12,7 @@
#include <string>
#include "db/db_impl/db_impl.h"
#include "db/range_del_aggregator.h"
#include "memory/arena.h"
#include "options/cf_options.h"
#include "rocksdb/db.h"
@@ -56,34 +57,6 @@ class Version;
// numbers, deletion markers, overwrites, etc.
class DBIter final : public Iterator {
public:
// Return a new DBIter that reads from `internal_iter` at the specified
// `sequence` number.
//
// @param active_mem Pointer to the active memtable that `internal_iter`
// is reading from. If not null, the memtable can be marked for flush
// according to options mutable_cf_options.memtable_op_scan_flush_trigger
// and mutable_cf_options.memtable_avg_op_scan_flush_trigger.
// @param arena_mode If true, the DBIter will be allocated from the arena.
static DBIter* NewIter(Env* env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator,
InternalIterator* internal_iter,
const Version* version, const SequenceNumber& sequence,
ReadCallback* read_callback,
ReadOnlyMemTable* active_mem,
ColumnFamilyHandleImpl* cfh = nullptr,
bool expose_blob_index = false,
Arena* arena = nullptr) {
void* mem = arena ? arena->AllocateAligned(sizeof(DBIter))
: operator new(sizeof(DBIter));
DBIter* db_iter = new (mem)
DBIter(env, read_options, ioptions, mutable_cf_options,
user_key_comparator, internal_iter, version, sequence, arena,
read_callback, cfh, expose_blob_index, active_mem);
return db_iter;
}
// The following is grossly complicated. TODO: clean it up
// Which direction is the iterator currently moving?
// (1) When moving forward:
@@ -140,12 +113,19 @@ class DBIter final : public Iterator {
uint64_t skip_count_;
};
DBIter(Env* _env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Comparator* cmp,
InternalIterator* iter, const Version* version, SequenceNumber s,
bool arena_mode, uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, ColumnFamilyHandleImpl* cfh,
bool expose_blob_index);
// No copying allowed
DBIter(const DBIter&) = delete;
void operator=(const DBIter&) = delete;
~DBIter() override {
MarkMemtableForFlushForAvgTrigger();
ThreadStatus::OperationType cur_op_type =
ThreadStatusUtil::GetThreadOperation();
ThreadStatusUtil::SetThreadOperation(
@@ -240,26 +220,7 @@ class DBIter final : public Iterator {
bool PrepareValue() override;
void Prepare(const std::vector<ScanOptions>& scan_opts) override {
std::optional<std::vector<ScanOptions>> new_scan_opts;
new_scan_opts.emplace(scan_opts);
scan_opts_.swap(new_scan_opts);
if (!scan_opts.empty()) {
iter_.Prepare(&scan_opts_.value());
} else {
iter_.Prepare(nullptr);
}
}
private:
DBIter(Env* _env, const ReadOptions& read_options,
const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options, const Comparator* cmp,
InternalIterator* iter, const Version* version, SequenceNumber s,
bool arena_mode, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh, bool expose_blob_index,
ReadOnlyMemTable* active_mem);
class BlobReader {
public:
BlobReader(const Version* version, ReadTier read_tier,
@@ -418,36 +379,6 @@ class DBIter final : public Iterator {
return true;
}
void MarkMemtableForFlushForAvgTrigger() {
if (avg_op_scan_flush_trigger_ &&
mem_hidden_op_scanned_since_seek_ >= memtable_op_scan_flush_trigger_ &&
mem_hidden_op_scanned_since_seek_ >=
static_cast<uint64_t>(iter_step_since_seek_) *
avg_op_scan_flush_trigger_) {
assert(memtable_op_scan_flush_trigger_ > 0);
active_mem_->MarkForFlush();
avg_op_scan_flush_trigger_ = 0;
memtable_op_scan_flush_trigger_ = 0;
}
iter_step_since_seek_ = 1;
mem_hidden_op_scanned_since_seek_ = 0;
}
void MarkMemtableForFlushForPerOpTrigger(uint64_t& mem_hidden_op_scanned) {
if (memtable_op_scan_flush_trigger_ &&
ikey_.sequence >= memtable_seqno_lb_) {
if (++mem_hidden_op_scanned >= memtable_op_scan_flush_trigger_) {
active_mem_->MarkForFlush();
// Turn off the flush trigger checks.
memtable_op_scan_flush_trigger_ = 0;
avg_op_scan_flush_trigger_ = 0;
}
if (avg_op_scan_flush_trigger_) {
++mem_hidden_op_scanned_since_seek_;
}
}
}
const SliceTransform* prefix_extractor_;
Env* const env_;
SystemClock* clock_;
@@ -494,24 +425,6 @@ class DBIter final : public Iterator {
IterKey prefix_;
Status status_;
Slice lazy_blob_index_;
// List of operands for merge operator.
MergeContext merge_context_;
LocalStatistics local_stats_;
PinnedIteratorsManager pinned_iters_mgr_;
ColumnFamilyHandleImpl* cfh_;
const Slice* const timestamp_ub_;
const Slice* const timestamp_lb_;
const size_t timestamp_size_;
std::string saved_timestamp_;
std::optional<std::vector<ScanOptions>> scan_opts_;
ReadOnlyMemTable* const active_mem_;
SequenceNumber memtable_seqno_lb_;
uint32_t memtable_op_scan_flush_trigger_;
uint32_t avg_op_scan_flush_trigger_;
uint32_t iter_step_since_seek_;
uint32_t mem_hidden_op_scanned_since_seek_;
Direction direction_;
bool valid_;
bool current_entry_is_merged_;
@@ -530,7 +443,29 @@ class DBIter final : public Iterator {
// the stacked BlobDB implementation is used, false otherwise.
bool expose_blob_index_;
bool allow_unprepared_value_;
Slice lazy_blob_index_;
bool is_blob_;
bool arena_mode_;
// List of operands for merge operator.
MergeContext merge_context_;
LocalStatistics local_stats_;
PinnedIteratorsManager pinned_iters_mgr_;
ColumnFamilyHandleImpl* cfh_;
const Slice* const timestamp_ub_;
const Slice* const timestamp_lb_;
const size_t timestamp_size_;
std::string saved_timestamp_;
};
// Return a new iterator that converts internal keys (yielded by
// "*internal_iter") that were live at the specified `sequence` number
// into appropriate user keys.
Iterator* NewDBIterator(
Env* env, const ReadOptions& read_options, const ImmutableOptions& ioptions,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator, InternalIterator* internal_iter,
const Version* version, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, ReadCallback* read_callback,
ColumnFamilyHandleImpl* cfh = nullptr, bool expose_blob_index = false);
} // namespace ROCKSDB_NAMESPACE
+4 -3
View File
@@ -528,11 +528,12 @@ TEST_F(DBIteratorStressTest, StressTest) {
internal_iter->target_hidden_fraction =
target_hidden_fraction;
internal_iter->trace = trace;
db_iter.reset(DBIter::NewIter(
db_iter.reset(NewDBIterator(
env_, ropt, ImmutableOptions(options),
MutableCFOptions(options), BytewiseComparator(),
internal_iter, /*version=*/nullptr, sequence,
nullptr /*read_callback*/, /*active_mem=*/nullptr));
internal_iter, nullptr /* version */, sequence,
options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
}
// Do a random operation. It's important to do it on ref_it
Loaded 100 of 586 files, more files were not shown because too many files have changed in this diff. Show more