mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-07 03:22:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a66daec541 | ||
|
|
537ea661cb | ||
|
|
29219c208c | ||
|
|
15a6520154 | ||
|
|
54d6286027 |
No files matched your search
+77
-16
@@ -146,12 +146,9 @@ commands:
|
||||
install-maven:
|
||||
steps:
|
||||
- run:
|
||||
name: Install Maven
|
||||
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
|
||||
sudo apt-get update -y && sudo apt-get install -y maven
|
||||
|
||||
setup-folly:
|
||||
steps:
|
||||
@@ -234,7 +231,6 @@ executors:
|
||||
- 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:
|
||||
@@ -248,7 +244,7 @@ jobs:
|
||||
- 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
|
||||
- run: ulimit -S -n `ulimit -H -n` && OPT=-DCIRCLECI make V=1 J=16 -j16 all
|
||||
- post-steps
|
||||
|
||||
build-macos-cmake:
|
||||
@@ -547,7 +543,7 @@ jobs:
|
||||
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
|
||||
- run: ulimit -S -n `ulimit -H -n` && make V=1 -j8 CRASH_TEST_EXT_ARGS='--duration=960 --max_key=2500000 --use_io_uring=0' blackbox_crash_test_with_atomic_flush
|
||||
- post-steps
|
||||
|
||||
build-linux-crashtest-tiered-storage-bb:
|
||||
@@ -557,7 +553,7 @@ jobs:
|
||||
- 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
|
||||
command: ulimit -S -n `ulimit -H -n` && make V=1 -j32 CRASH_TEST_EXT_ARGS='--duration=10800 --use_io_uring=0' blackbox_crash_test_with_tiered_storage
|
||||
no_output_timeout: 100m
|
||||
- post-steps
|
||||
|
||||
@@ -568,7 +564,7 @@ jobs:
|
||||
- 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
|
||||
command: ulimit -S -n `ulimit -H -n` && make V=1 -j32 CRASH_TEST_EXT_ARGS='--duration=10800 --use_io_uring=0' whitebox_crash_test_with_tiered_storage
|
||||
no_output_timeout: 100m
|
||||
- post-steps
|
||||
|
||||
@@ -627,7 +623,7 @@ jobs:
|
||||
- windows-build-steps
|
||||
|
||||
build-linux-java:
|
||||
executor: linux-java-docker
|
||||
executor: linux-docker
|
||||
resource_class: large
|
||||
steps:
|
||||
- pre-steps
|
||||
@@ -640,13 +636,17 @@ jobs:
|
||||
which javac && javac -version
|
||||
- run:
|
||||
name: "Test RocksDBJava"
|
||||
command: scl enable devtoolset-7 'make V=1 J=8 -j8 jtest'
|
||||
command: make V=1 J=8 -j8 jtest
|
||||
- post-steps
|
||||
|
||||
build-linux-java-pmd:
|
||||
executor: linux-java-docker
|
||||
machine:
|
||||
image: ubuntu-2004:202111-02
|
||||
resource_class: large
|
||||
environment:
|
||||
JAVA_HOME: /usr/lib/jvm/java-8-openjdk-amd64
|
||||
steps:
|
||||
- install-maven
|
||||
- pre-steps
|
||||
- run:
|
||||
name: "Set Java Environment"
|
||||
@@ -655,10 +655,9 @@ jobs:
|
||||
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'
|
||||
command: make V=1 J=8 -j8 jpmd
|
||||
- post-pmd-steps
|
||||
|
||||
build-linux-java-static:
|
||||
@@ -878,11 +877,66 @@ jobs:
|
||||
- perform-benchmarks
|
||||
- post-benchmarks
|
||||
|
||||
workflows: # Only jobs that haven't been successfully migrated to GitHub Actions
|
||||
workflows:
|
||||
version: 2
|
||||
jobs-linux-run-tests:
|
||||
jobs:
|
||||
- build-linux
|
||||
- build-linux-cmake-with-folly
|
||||
- build-linux-cmake-with-folly-lite-no-test
|
||||
- build-linux-gcc-7-with-folly
|
||||
- build-linux-gcc-7-with-folly-lite-no-test
|
||||
- build-linux-cmake-with-folly-coroutines
|
||||
- build-linux-cmake-with-benchmark
|
||||
- build-linux-encrypted_env-no_compression
|
||||
jobs-linux-run-tests-san:
|
||||
jobs:
|
||||
- build-linux-clang10-asan
|
||||
- build-linux-clang10-ubsan
|
||||
- build-linux-clang10-mini-tsan
|
||||
- build-linux-static_lib-alt_namespace-status_checked
|
||||
jobs-linux-no-test-run:
|
||||
jobs:
|
||||
- build-linux-release
|
||||
- build-linux-release-rtti
|
||||
- build-examples
|
||||
- build-fuzzers
|
||||
- build-linux-clang-no_test_run
|
||||
- build-linux-clang-13-no_test_run
|
||||
- build-linux-gcc-8-no_test_run
|
||||
- build-linux-gcc-10-cxx20-no_test_run
|
||||
- build-linux-gcc-11-no_test_run
|
||||
- build-linux-arm-cmake-no_test_run
|
||||
jobs-linux-other-checks:
|
||||
jobs:
|
||||
- build-linux-clang10-clang-analyze
|
||||
- build-linux-unity-and-headers
|
||||
- build-linux-mini-crashtest
|
||||
jobs-windows:
|
||||
jobs:
|
||||
- build-windows-vs2019
|
||||
- build-cmake-mingw
|
||||
jobs-java:
|
||||
jobs:
|
||||
- build-linux-java
|
||||
- build-linux-java-static
|
||||
- build-macos-java
|
||||
- build-macos-java-static
|
||||
- build-macos-java-static-universal
|
||||
- build-linux-java-pmd
|
||||
jobs-macos:
|
||||
jobs:
|
||||
- build-macos
|
||||
- build-macos-cmake:
|
||||
run_even_tests: true
|
||||
- build-macos-cmake:
|
||||
run_even_tests: false
|
||||
jobs-linux-arm:
|
||||
jobs:
|
||||
- build-linux-arm
|
||||
build-fuzzers:
|
||||
jobs:
|
||||
- build-fuzzers
|
||||
benchmark-linux:
|
||||
triggers:
|
||||
- schedule:
|
||||
@@ -902,4 +956,11 @@ workflows: # Only jobs that haven't been successfully migrated to GitHub Actions
|
||||
only:
|
||||
- main
|
||||
jobs:
|
||||
- build-format-compatible
|
||||
- build-linux-arm-test-full
|
||||
- build-linux-run-microbench
|
||||
- build-linux-non-shm
|
||||
- build-linux-clang-13-asan-ubsan-with-folly
|
||||
- build-linux-valgrind
|
||||
- build-windows-vs2022-avx2
|
||||
- build-windows-vs2022
|
||||
@@ -1,7 +0,0 @@
|
||||
name: build-folly
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Build folly and dependencies
|
||||
run: make build_folly
|
||||
shell: bash
|
||||
@@ -1,8 +0,0 @@
|
||||
name: build-for-benchmarks
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- name: Linux build for benchmarks
|
||||
run: make V=1 J=8 -j8 release
|
||||
shell: bash
|
||||
@@ -1,10 +0,0 @@
|
||||
name: increase-max-open-files-on-macos
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Increase max open files
|
||||
run: |-
|
||||
sudo sysctl -w kern.maxfiles=1048576
|
||||
sudo sysctl -w kern.maxfilesperproc=1048576
|
||||
sudo launchctl limit maxfiles 1048576
|
||||
shell: bash
|
||||
@@ -1,7 +0,0 @@
|
||||
name: install-gflags-on-macos
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install gflags on macos
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install gflags
|
||||
shell: bash
|
||||
@@ -1,7 +0,0 @@
|
||||
name: install-gflags
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install gflags
|
||||
run: sudo apt-get update -y && sudo apt-get install -y libgflags-dev
|
||||
shell: bash
|
||||
@@ -1,9 +0,0 @@
|
||||
name: install-jdk8-on-macos
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install JDK 8 on macos
|
||||
run: |-
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew tap bell-sw/liberica
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install --cask liberica-jdk8
|
||||
shell: bash
|
||||
@@ -1,11 +0,0 @@
|
||||
name: install-maven
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Maven
|
||||
run: |
|
||||
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
|
||||
@@ -1,22 +0,0 @@
|
||||
name: perform-benchmarks
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Test low-variance benchmarks
|
||||
run: "./tools/benchmark_ci.py --db_dir ${{ runner.temp }}/rocksdb-benchmark-datadir --output_dir ${{ runner.temp }}/benchmark-results --num_keys 20000000"
|
||||
env:
|
||||
LD_LIBRARY_PATH: "/usr/local/lib"
|
||||
DURATION_RO: 300
|
||||
DURATION_RW: 500
|
||||
NUM_THREADS: 1
|
||||
MAX_BACKGROUND_JOBS: 4
|
||||
CI_TESTS_ONLY: 'true'
|
||||
WRITE_BUFFER_SIZE_MB: 16
|
||||
TARGET_FILE_SIZE_BASE_MB: 16
|
||||
MAX_BYTES_FOR_LEVEL_BASE_MB: 64
|
||||
COMPRESSION_TYPE: none
|
||||
CACHE_INDEX_AND_FILTER_BLOCKS: 1
|
||||
MIN_LEVEL_TO_COMPRESS: 3
|
||||
CACHE_SIZE_MB: 10240
|
||||
MB_WRITE_PER_SEC: 2
|
||||
shell: bash
|
||||
@@ -1,17 +0,0 @@
|
||||
name: post-benchmarks
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Upload Benchmark Results artifact
|
||||
uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: benchmark-results
|
||||
path: "${{ runner.temp }}/benchmark-results/**"
|
||||
if-no-files-found: error
|
||||
- name: Send benchmark report to visualisation
|
||||
run: |-
|
||||
set +e
|
||||
set +o pipefail
|
||||
./build_tools/benchmark_log_tool.py --tsvfile ${{ runner.temp }}/benchmark-results/report.tsv --esdocument https://search-rocksdb-bench-k2izhptfeap2hjfxteolsgsynm.us-west-2.es.amazonaws.com/bench_test3_rix/_doc
|
||||
true
|
||||
shell: bash
|
||||
@@ -1,38 +0,0 @@
|
||||
name: post-steps
|
||||
description: Steps that are taken after a RocksDB job
|
||||
inputs:
|
||||
artifact-prefix:
|
||||
description: Prefix to append to the name of artifacts that are uploaded
|
||||
required: true
|
||||
default: "${{ github.job }}"
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Upload Test Results artifact
|
||||
uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: "${{ inputs.artifact-prefix }}-test-results"
|
||||
path: "${{ runner.temp }}/test-results/**"
|
||||
- name: Upload DB LOG file artifact
|
||||
uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: "${{ inputs.artifact-prefix }}-db-log-file"
|
||||
path: LOG
|
||||
- name: Copy Test Logs (on Failure)
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/failure-test-logs
|
||||
cp -r t/* ${{ runner.temp }}/failure-test-logs
|
||||
shell: bash
|
||||
- name: Upload Test Logs (on Failure) artifact
|
||||
uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: "${{ inputs.artifact-prefix }}-failure-test-logs"
|
||||
path: ${{ runner.temp }}/failure-test-logs/**
|
||||
if-no-files-found: ignore
|
||||
- name: Upload Core Dumps artifact
|
||||
uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: "${{ inputs.artifact-prefix }}-core-dumps"
|
||||
path: "core.*"
|
||||
if-no-files-found: ignore
|
||||
@@ -1,5 +0,0 @@
|
||||
name: pre-steps-macos
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
@@ -1,18 +0,0 @@
|
||||
name: pre-steps
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Environment Variables
|
||||
run: |-
|
||||
echo "GTEST_THROW_ON_FAILURE=0" >> "$GITHUB_ENV"
|
||||
echo "GTEST_OUTPUT=\"xml:${{ runner.temp }}/test-results/\"" >> "$GITHUB_ENV"
|
||||
echo "SKIP_FORMAT_BUCK_CHECKS=1" >> "$GITHUB_ENV"
|
||||
echo "GTEST_COLOR=1" >> "$GITHUB_ENV"
|
||||
echo "CTEST_OUTPUT_ON_FAILURE=1" >> "$GITHUB_ENV"
|
||||
echo "CTEST_TEST_TIMEOUT=300" >> "$GITHUB_ENV"
|
||||
echo "ZLIB_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zlib" >> "$GITHUB_ENV"
|
||||
echo "BZIP2_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/bzip2" >> "$GITHUB_ENV"
|
||||
echo "SNAPPY_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/snappy" >> "$GITHUB_ENV"
|
||||
echo "LZ4_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/lz4" >> "$GITHUB_ENV"
|
||||
echo "ZSTD_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zstd" >> "$GITHUB_ENV"
|
||||
shell: bash
|
||||
@@ -1,7 +0,0 @@
|
||||
name: setup-folly
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout folly sources
|
||||
run: make checkout_folly
|
||||
shell: bash
|
||||
@@ -1,20 +0,0 @@
|
||||
name: build-folly
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Fix repo ownership
|
||||
# Needed in some cases, as safe.directory setting doesn't take effect
|
||||
# under env -i
|
||||
run: chown `whoami` . || true
|
||||
shell: bash
|
||||
- name: Set upstream
|
||||
run: git remote add upstream https://github.com/facebook/rocksdb.git
|
||||
shell: bash
|
||||
- name: Fetch upstream
|
||||
run: git fetch upstream
|
||||
shell: bash
|
||||
- name: Git status
|
||||
# NOTE: some old branch builds under check_format_compatible.sh invoke
|
||||
# git under env -i
|
||||
run: git status && git remote -v && env -i git branch
|
||||
shell: bash
|
||||
@@ -1,54 +0,0 @@
|
||||
name: windows-build-steps
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
- name: Custom steps
|
||||
env:
|
||||
THIRDPARTY_HOME: ${{ github.workspace }}/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: ${{ 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 =====================
|
||||
choco install liberica8jdk -y
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
mkdir $Env:THIRDPARTY_HOME
|
||||
cd $Env:THIRDPARTY_HOME
|
||||
echo "Building Snappy dependency..."
|
||||
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.1.8.zip
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
cd snappy-1.1.8
|
||||
mkdir build
|
||||
cd build
|
||||
& cmake -G "$Env:CMAKE_GENERATOR" ..
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
msbuild Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
echo ======================== Build RocksDB =========================
|
||||
cd ${{ github.workspace }}
|
||||
$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 -DJNI=1 ..
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
cd ..
|
||||
echo "Building with VS version: $Env:CMAKE_GENERATOR"
|
||||
msbuild build/rocksdb.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
echo ========================= Test RocksDB =========================
|
||||
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
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
echo ======================== Test RocksJava ========================
|
||||
cd build\java
|
||||
& ctest -C Debug -j 16
|
||||
if(!$?) { Exit $LASTEXITCODE }
|
||||
shell: pwsh
|
||||
@@ -1,15 +0,0 @@
|
||||
name: facebook/rocksdb/benchmark-linux
|
||||
on: workflow_dispatch
|
||||
jobs:
|
||||
# FIXME: when this job is fixed, it should be given a cron schedule like
|
||||
# schedule:
|
||||
# - cron: 0 * * * *
|
||||
# workflow_dispatch:
|
||||
benchmark-linux:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/build-for-benchmarks"
|
||||
- uses: "./.github/actions/perform-benchmarks"
|
||||
- uses: "./.github/actions/post-benchmarks"
|
||||
@@ -1,18 +0,0 @@
|
||||
name: facebook/rocksdb/nightly
|
||||
on: workflow_dispatch
|
||||
jobs:
|
||||
# These jobs would be in nightly but are failing or otherwise broken for
|
||||
# some reason.
|
||||
build-linux-arm-test-full:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: arm64large
|
||||
container:
|
||||
image: ubuntu-2004:202111-02
|
||||
options: --shm-size=16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- uses: "./.github/actions/install-gflags"
|
||||
- run: make V=1 J=4 -j4 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
@@ -1,111 +0,0 @@
|
||||
name: facebook/rocksdb/nightly
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 9 * * *
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build-format-compatible:
|
||||
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
|
||||
with:
|
||||
fetch-depth: 0 # Need full repo history
|
||||
fetch-tags: true
|
||||
- uses: "./.github/actions/setup-upstream"
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- name: test
|
||||
run: |-
|
||||
export TEST_TMPDIR=/dev/shm/rocksdb
|
||||
rm -rf /dev/shm/rocksdb
|
||||
mkdir /dev/shm/rocksdb
|
||||
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:
|
||||
labels: 16-core-ubuntu
|
||||
container:
|
||||
image: zjay437/rocksdb:0.6
|
||||
options: --shm-size=16gb
|
||||
env:
|
||||
TEST_TMPDIR: "/tmp/rocksdb_test_tmp"
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- run: make V=1 -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-clang-13-asan-ubsan-with-folly:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 16-core-ubuntu
|
||||
container:
|
||||
image: zjay437/rocksdb:0.6
|
||||
options: --shm-size=16gb
|
||||
env:
|
||||
CC: clang-13
|
||||
CXX: clang++-13
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- uses: "./.github/actions/setup-folly"
|
||||
- uses: "./.github/actions/build-folly"
|
||||
- run: LIB_MODE=static USE_CLANG=1 USE_FOLLY=1 COMPILE_WITH_UBSAN=1 COMPILE_WITH_ASAN=1 make -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-valgrind:
|
||||
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: PORTABLE=1 make V=1 -j32 valgrind_test
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-windows-vs2022-avx2:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
CMAKE_GENERATOR: Visual Studio 17 2022
|
||||
CMAKE_PORTABLE: AVX2
|
||||
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:
|
||||
labels: 4-core-ubuntu-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- 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"
|
||||
@@ -1,46 +0,0 @@
|
||||
name: facebook/rocksdb/pr-jobs-candidate
|
||||
on: workflow_dispatch
|
||||
jobs:
|
||||
# These jobs would be in pr-jobs but are failing or otherwise broken for
|
||||
# some reason.
|
||||
# =========================== ARM Jobs ============================ #
|
||||
build-linux-arm:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: arm64large # GitHub hosted ARM runners do not yet exist
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- uses: "./.github/actions/install-gflags"
|
||||
- run: ROCKSDBTESTS_PLATFORM_DEPENDENT=only make V=1 J=4 -j4 all_but_some_tests check_some
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-arm-cmake-no_test_run:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: arm64large # GitHub hosted ARM runners do not yet exist
|
||||
env:
|
||||
JAVA_HOME: "/usr/lib/jvm/java-8-openjdk-arm64"
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- uses: "./.github/actions/install-gflags"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> $BASH_ENV
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Build with cmake
|
||||
run: |-
|
||||
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
|
||||
- name: Build Java with cmake
|
||||
run: |-
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DJNI=1 -DCMAKE_BUILD_TYPE=Release -DWITH_GFLAGS=1 ..
|
||||
make -j4 rocksdb rocksdbjni
|
||||
- uses: "./.github/actions/post-steps"
|
||||
@@ -1,631 +0,0 @@
|
||||
name: facebook/rocksdb/pr-jobs
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
# NOTE: multiple workflows would be recommended, but the current GHA UI in
|
||||
# PRs doesn't make it clear when there's an overall error with a workflow,
|
||||
# making it easy to overlook something broken. Grouping everything into one
|
||||
# workflow minimizes the problem because it will be suspicious if there are
|
||||
# no GHA results.
|
||||
#
|
||||
# The if: ${{ github.repository_owner == 'facebook' }} lines prevent the
|
||||
# jobs from attempting to run on repo forks, because of a few problems:
|
||||
# * runs-on labels are repository (owner) specific, so the job might wait
|
||||
# for days waiting for a runner that simply isn't available.
|
||||
# * Pushes to branches on forks for pull requests (the normal process) would
|
||||
# run the workflow jobs twice: once in the pull-from fork and once for the PR
|
||||
# destination repo. This is wasteful and dumb.
|
||||
# * It is not known how to avoid copy-pasting the line to each job,
|
||||
# increasing the risk of misconfiguration, especially on forks that might
|
||||
# want to run with this GHA setup.
|
||||
#
|
||||
# DEBUGGING WITH SSH: Temporarily add this as a job step, either before the
|
||||
# step of interest without the "if:" line or after the failing step with the
|
||||
# "if:" line. Then use ssh command printed in CI output.
|
||||
# - name: Setup tmate session # TEMPORARY!
|
||||
# if: ${{ failure() }}
|
||||
# uses: mxschmitt/action-tmate@v3
|
||||
# with:
|
||||
# limit-access-to-actor: true
|
||||
|
||||
# ======================== Fast Initial Checks ====================== #
|
||||
check-format-and-targets:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
with:
|
||||
fetch-depth: 0 # Need full checkout to determine merge base
|
||||
fetch-tags: true
|
||||
- uses: "./.github/actions/setup-upstream"
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
- name: Install Dependencies
|
||||
run: python -m pip install --upgrade pip
|
||||
- name: Install argparse
|
||||
run: pip install argparse
|
||||
- name: Download 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
|
||||
# ========================= Linux With Tests ======================== #
|
||||
build-linux:
|
||||
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: make V=1 J=32 -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-cmake-mingw:
|
||||
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"
|
||||
- run: update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
|
||||
- name: Build cmake-mingw
|
||||
run: |-
|
||||
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
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-cmake-with-folly:
|
||||
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"
|
||||
- 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:
|
||||
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"
|
||||
- uses: "./.github/actions/build-folly"
|
||||
- run: USE_FOLLY=1 LIB_MODE=static V=1 make -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-make-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: USE_FOLLY_LITE=1 V=1 make -j32 all
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-cmake-with-folly-coroutines:
|
||||
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"
|
||||
- uses: "./.github/actions/build-folly"
|
||||
- run: "(mkdir build && cd build && cmake -DUSE_COROUTINES=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 .. && make V=1 -j20 && ctest -j20)"
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-cmake-with-benchmark:
|
||||
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: mkdir build && cd build && cmake -DWITH_GFLAGS=1 -DWITH_BENCHMARK=1 .. && make V=1 -j20 && ctest -j20
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-encrypted_env-no_compression:
|
||||
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: 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\n"
|
||||
- uses: "./.github/actions/post-steps"
|
||||
# ======================== Linux No Test Runs ======================= #
|
||||
build-linux-release:
|
||||
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
|
||||
- run: make V=1 -j32 LIB_MODE=shared release
|
||||
- run: ls librocksdb.so
|
||||
- run: "./db_stress --version"
|
||||
- run: make clean
|
||||
- run: make V=1 -j32 release
|
||||
- run: ls librocksdb.a
|
||||
- run: "./db_stress --version"
|
||||
- run: make clean
|
||||
- run: apt-get remove -y libgflags-dev
|
||||
- run: make V=1 -j32 LIB_MODE=shared release
|
||||
- run: ls librocksdb.so
|
||||
- run: if ./db_stress --version; then false; else true; fi
|
||||
- run: make clean
|
||||
- run: make V=1 -j32 release
|
||||
- run: ls librocksdb.a
|
||||
- run: if ./db_stress --version; then false; else true; fi
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-release-rtti:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 8-core-ubuntu
|
||||
container:
|
||||
image: zjay437/rocksdb:0.6
|
||||
options: --shm-size=16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench
|
||||
- run: "./db_stress --version"
|
||||
- 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
|
||||
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:
|
||||
labels: 8-core-ubuntu
|
||||
container:
|
||||
image: zjay437/rocksdb:0.6
|
||||
options: --shm-size=16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- run: CC=clang CXX=clang++ USE_CLANG=1 PORTABLE=1 make V=1 -j16 all
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-clang-13-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: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j32 all microbench
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-gcc-8-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: CC=gcc-8 CXX=g++-8 V=1 make -j32 all
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-gcc-10-cxx20-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: 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' }}
|
||||
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: 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
|
||||
- uses: "./.github/actions/post-steps"
|
||||
- name: compress test report
|
||||
run: tar -cvzf scan_build_report.tar.gz scan_build_report
|
||||
if: failure()
|
||||
- uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: scan-build-report
|
||||
path: scan_build_report.tar.gz
|
||||
build-linux-unity-and-headers:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 4-core-ubuntu
|
||||
container:
|
||||
image: gcc:latest
|
||||
options: --shm-size=16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- run: apt-get update -y && apt-get install -y libgflags-dev
|
||||
- name: Unity build
|
||||
run: make V=1 -j8 unity_test
|
||||
- run: make V=1 -j8 -k check-headers
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-mini-crashtest:
|
||||
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"
|
||||
- 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
|
||||
- uses: "./.github/actions/post-steps"
|
||||
# ======================= Linux with Sanitizers ===================== #
|
||||
build-linux-clang10-asan:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 32-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: COMPILE_WITH_ASAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-clang10-ubsan:
|
||||
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: 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-clang10-mini-tsan:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 32-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: COMPILE_WITH_TSAN=1 CC=clang-13 CXX=clang++-13 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-static_lib-alt_namespace-status_checked:
|
||||
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: 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
|
||||
- uses: "./.github/actions/post-steps"
|
||||
# ========================= MacOS build only ======================== #
|
||||
build-macos:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: macos-13
|
||||
env:
|
||||
ROCKSDB_DISABLE_JEMALLOC: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: 14.3.1
|
||||
- uses: "./.github/actions/increase-max-open-files-on-macos"
|
||||
- uses: "./.github/actions/install-gflags-on-macos"
|
||||
- uses: "./.github/actions/pre-steps-macos"
|
||||
- name: Build
|
||||
run: ulimit -S -n `ulimit -H -n` && make V=1 J=16 -j16 all
|
||||
- uses: "./.github/actions/post-steps"
|
||||
# ========================= MacOS with Tests ======================== #
|
||||
build-macos-cmake:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: macos-13
|
||||
strategy:
|
||||
matrix:
|
||||
run_even_tests: [true, false]
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: 14.3.1
|
||||
- uses: "./.github/actions/increase-max-open-files-on-macos"
|
||||
- uses: "./.github/actions/install-gflags-on-macos"
|
||||
- uses: "./.github/actions/pre-steps-macos"
|
||||
- name: cmake generate project file
|
||||
run: ulimit -S -n `ulimit -H -n` && mkdir build && cd build && cmake -DWITH_GFLAGS=1 ..
|
||||
- name: Build tests
|
||||
run: cd build && make V=1 -j16
|
||||
- name: Run even tests
|
||||
run: ulimit -S -n `ulimit -H -n` && cd build && ctest -j16 -I 0,,2
|
||||
if: ${{ matrix.run_even_tests }}
|
||||
- name: Run odd tests
|
||||
run: ulimit -S -n `ulimit -H -n` && cd build && ctest -j16 -I 1,,2
|
||||
if: ${{ ! matrix.run_even_tests }}
|
||||
- uses: "./.github/actions/post-steps"
|
||||
# ======================== Windows with Tests ======================= #
|
||||
# NOTE: some windows jobs are in "nightly" to save resources
|
||||
build-windows-vs2019:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: windows-2019
|
||||
env:
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
CMAKE_PORTABLE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/windows-build-steps"
|
||||
# ============================ Java Jobs ============================ #
|
||||
build-linux-java:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 4-core-ubuntu
|
||||
container:
|
||||
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.
|
||||
# That GLIBC is incompatibile with GitHub's actions/checkout. Thus we implement a manual checkout step.
|
||||
- name: Checkout
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
chown `whoami` . || true
|
||||
git clone --no-checkout https://oath2:$GH_TOKEN@github.com/${{ github.repository }}.git .
|
||||
git -c protocol.version=2 fetch --update-head-ok --no-tags --prune --no-recurse-submodules --depth=1 origin +${{ github.sha }}:${{ github.ref }}
|
||||
git checkout --progress --force ${{ github.ref }}
|
||||
git log -1 --format='%H'
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Test RocksDBJava
|
||||
run: scl enable devtoolset-7 'make V=1 J=8 -j8 jtest'
|
||||
# NOTE: post-steps skipped because of compatibility issues with docker image
|
||||
build-linux-java-static:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 4-core-ubuntu
|
||||
container:
|
||||
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.
|
||||
# That GLIBC is incompatibile with GitHub's actions/checkout. Thus we implement a manual checkout step.
|
||||
- name: Checkout
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
chown `whoami` . || true
|
||||
git clone --no-checkout https://oath2:$GH_TOKEN@github.com/${{ github.repository }}.git .
|
||||
git -c protocol.version=2 fetch --update-head-ok --no-tags --prune --no-recurse-submodules --depth=1 origin +${{ github.sha }}:${{ github.ref }}
|
||||
git checkout --progress --force ${{ github.ref }}
|
||||
git log -1 --format='%H'
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Build RocksDBJava Static Library
|
||||
run: scl enable devtoolset-7 'make V=1 J=8 -j8 rocksdbjavastatic'
|
||||
# NOTE: post-steps skipped because of compatibility issues with docker image
|
||||
build-macos-java:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: macos-13
|
||||
env:
|
||||
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
|
||||
ROCKSDB_DISABLE_JEMALLOC: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: 14.3.1
|
||||
- uses: "./.github/actions/increase-max-open-files-on-macos"
|
||||
- uses: "./.github/actions/install-gflags-on-macos"
|
||||
- uses: "./.github/actions/install-jdk8-on-macos"
|
||||
- uses: "./.github/actions/pre-steps-macos"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Test RocksDBJava
|
||||
run: make V=1 J=16 -j16 jtest
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-macos-java-static:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: macos-13
|
||||
env:
|
||||
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: 14.3.1
|
||||
- uses: "./.github/actions/increase-max-open-files-on-macos"
|
||||
- uses: "./.github/actions/install-gflags-on-macos"
|
||||
- uses: "./.github/actions/install-jdk8-on-macos"
|
||||
- uses: "./.github/actions/pre-steps-macos"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Build RocksDBJava x86 and ARM Static Libraries
|
||||
run: make V=1 J=16 -j16 rocksdbjavastaticosx
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-macos-java-static-universal:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on: macos-13
|
||||
env:
|
||||
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: maxim-lobanov/setup-xcode@v1.6.0
|
||||
with:
|
||||
xcode-version: 14.3.1
|
||||
- uses: "./.github/actions/increase-max-open-files-on-macos"
|
||||
- uses: "./.github/actions/install-gflags-on-macos"
|
||||
- uses: "./.github/actions/install-jdk8-on-macos"
|
||||
- uses: "./.github/actions/pre-steps-macos"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: Build RocksDBJava Universal Binary Static Library
|
||||
run: make V=1 J=16 -j16 rocksdbjavastaticosx_ub
|
||||
- uses: "./.github/actions/post-steps"
|
||||
build-linux-java-pmd:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 4-core-ubuntu
|
||||
container:
|
||||
image: evolvedbinary/rocksjava:rockylinux8_x64-be
|
||||
options: --shm-size=16gb
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/install-maven"
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- name: Set Java Environment
|
||||
run: |-
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
- name: PMD RocksDBJava
|
||||
run: make V=1 J=8 -j8 jpmd
|
||||
- uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: pmd-report
|
||||
path: "${{ github.workspace }}/java/target/pmd.xml"
|
||||
- uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: maven-site
|
||||
path: "${{ github.workspace }}/java/target/site"
|
||||
build-linux-arm:
|
||||
if: ${{ github.repository_owner == 'facebook' }}
|
||||
runs-on:
|
||||
labels: 4-core-ubuntu-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.0
|
||||
- uses: "./.github/actions/pre-steps"
|
||||
- run: sudo apt-get update && sudo apt-get install -y build-essential
|
||||
- run: ROCKSDBTESTS_PLATFORM_DEPENDENT=only make V=1 J=4 -j4 all_but_some_tests check_some
|
||||
- uses: "./.github/actions/post-steps"
|
||||
@@ -0,0 +1,45 @@
|
||||
name: Check buck targets and code format
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check TARGETS file and code format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout feature branch
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch from upstream
|
||||
run: |
|
||||
git remote add upstream https://github.com/facebook/rocksdb.git && git fetch upstream
|
||||
|
||||
- name: Where am I
|
||||
run: |
|
||||
echo git status && git status
|
||||
echo "git remote -v" && git remote -v
|
||||
echo git branch && git branch
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v1
|
||||
|
||||
- name: Install Dependencies
|
||||
run: python -m pip install --upgrade pip
|
||||
|
||||
- name: Install argparse
|
||||
run: pip install argparse
|
||||
|
||||
- name: Download 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
|
||||
@@ -47,9 +47,6 @@ package/
|
||||
unity.a
|
||||
tags
|
||||
etags
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
rocksdb_dump
|
||||
rocksdb_undump
|
||||
db_test2
|
||||
|
||||
+14
-53
@@ -44,29 +44,6 @@ project(rocksdb
|
||||
HOMEPAGE_URL https://rocksdb.org/
|
||||
LANGUAGES CXX C ASM)
|
||||
|
||||
if(APPLE)
|
||||
# On macOS Cmake, when cross-compiling, sometimes CMAKE_SYSTEM_PROCESSOR wrongfully stays
|
||||
# the same as CMAKE_HOST_SYSTEM_PROCESSOR regardless the target CPU.
|
||||
# The manual call to set(CMAKE_SYSTEM_PROCESSOR) has to be set after the project() call.
|
||||
# because project() might reset CMAKE_SYSTEM_PROCESSOR back to the value of CMAKE_HOST_SYSTEM_PROCESSOR.
|
||||
# Check if CMAKE_SYSTEM_PROCESSOR is not equal to CMAKE_OSX_ARCHITECTURES
|
||||
if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
|
||||
if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_OSX_ARCHITECTURES)
|
||||
# Split CMAKE_OSX_ARCHITECTURES into a list
|
||||
string(REPLACE ";" " " ARCH_LIST ${CMAKE_OSX_ARCHITECTURES})
|
||||
separate_arguments(ARCH_LIST UNIX_COMMAND ${ARCH_LIST})
|
||||
# Count the number of architectures
|
||||
list(LENGTH ARCH_LIST ARCH_COUNT)
|
||||
# Ensure that exactly one architecture is specified
|
||||
if(NOT ARCH_COUNT EQUAL 1)
|
||||
message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES must have exactly one value. Current value: ${CMAKE_OSX_ARCHITECTURES}")
|
||||
endif()
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_OSX_ARCHITECTURES})
|
||||
message(STATUS "CMAKE_SYSTEM_PROCESSOR is manually set to ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
@@ -99,6 +76,11 @@ if (WITH_WINDOWS_UTF8_FILENAMES)
|
||||
endif()
|
||||
option(ROCKSDB_BUILD_SHARED "Build shared versions of the RocksDB libraries" ON)
|
||||
|
||||
if ($ENV{CIRCLECI})
|
||||
message(STATUS "Build for CircieCI env, a few tests may be disabled")
|
||||
add_definitions(-DCIRCLECI)
|
||||
endif()
|
||||
|
||||
if( NOT DEFINED CMAKE_CXX_STANDARD )
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
@@ -189,7 +171,7 @@ else()
|
||||
if(WITH_ZSTD)
|
||||
find_package(zstd REQUIRED)
|
||||
add_definitions(-DZSTD)
|
||||
include_directories(${ZSTD_INCLUDE_DIRS})
|
||||
include_directories(${ZSTD_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS zstd::zstd)
|
||||
endif()
|
||||
endif()
|
||||
@@ -205,7 +187,7 @@ endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W4 /wd4127 /wd4996 /wd4100 /wd4324")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W4 /wd4127 /wd4800 /wd4996 /wd4351 /wd4100 /wd4204 /wd4324")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall -pthread")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers -Wno-strict-aliasing -Wno-invalid-offsetof")
|
||||
@@ -214,7 +196,6 @@ else()
|
||||
endif()
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
|
||||
add_definitions(-D_POSIX_C_SOURCE=1)
|
||||
endif()
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
@@ -267,8 +248,8 @@ endif(CMAKE_SYSTEM_PROCESSOR MATCHES "s390x")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "loongarch64")
|
||||
CHECK_C_COMPILER_FLAG("-march=loongarch64" HAS_LOONGARCH64)
|
||||
if(HAS_LOONGARCH64)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=loongarch64 -mtune=loongarch64")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=loongarch64 -mtune=loongarch64")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=loongarch64 -mtune=loongarch64")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=loongarch64 -mtune=loongarch64")
|
||||
endif(HAS_LOONGARCH64)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "loongarch64")
|
||||
|
||||
@@ -395,7 +376,7 @@ option(WITH_NUMA "build with NUMA policy support" OFF)
|
||||
if(WITH_NUMA)
|
||||
find_package(NUMA REQUIRED)
|
||||
add_definitions(-DNUMA)
|
||||
include_directories(${NUMA_INCLUDE_DIRS})
|
||||
include_directories(${NUMA_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS NUMA::NUMA)
|
||||
endif()
|
||||
|
||||
@@ -488,8 +469,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Cygwin")
|
||||
add_definitions(-fno-builtin-memcmp -DCYGWIN)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
add_definitions(-DOS_MACOSX)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "iOS")
|
||||
add_definitions(-DOS_MACOSX -DIOS_CROSS_COMPILE)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_definitions(-DOS_LINUX)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "SunOS")
|
||||
@@ -617,7 +596,7 @@ if(USE_FOLLY)
|
||||
FMT_INST_PATH)
|
||||
exec_program(ls ARGS -d ${FOLLY_INST_PATH}/../gflags* OUTPUT_VARIABLE
|
||||
GFLAGS_INST_PATH)
|
||||
set(Boost_DIR ${BOOST_INST_PATH}/lib/cmake/Boost-1.83.0)
|
||||
set(Boost_DIR ${BOOST_INST_PATH}/lib/cmake/Boost-1.78.0)
|
||||
if(EXISTS ${FMT_INST_PATH}/lib64)
|
||||
set(fmt_DIR ${FMT_INST_PATH}/lib64/cmake/fmt)
|
||||
else()
|
||||
@@ -655,7 +634,6 @@ set(SOURCES
|
||||
cache/sharded_cache.cc
|
||||
cache/tiered_secondary_cache.cc
|
||||
db/arena_wrapped_db_iter.cc
|
||||
db/attribute_group_iterator_impl.cc
|
||||
db/blob/blob_contents.cc
|
||||
db/blob/blob_fetcher.cc
|
||||
db/blob/blob_file_addition.cc
|
||||
@@ -672,7 +650,6 @@ set(SOURCES
|
||||
db/blob/prefetch_buffer_collection.cc
|
||||
db/builder.cc
|
||||
db/c.cc
|
||||
db/coalescing_iterator.cc
|
||||
db/column_family.cc
|
||||
db/compaction/compaction.cc
|
||||
db/compaction/compaction_iterator.cc
|
||||
@@ -693,7 +670,6 @@ set(SOURCES
|
||||
db/db_impl/db_impl_write.cc
|
||||
db/db_impl/db_impl_compaction_flush.cc
|
||||
db/db_impl/db_impl_files.cc
|
||||
db/db_impl/db_impl_follower.cc
|
||||
db/db_impl/db_impl_open.cc
|
||||
db/db_impl/db_impl_debug.cc
|
||||
db/db_impl/db_impl_experimental.cc
|
||||
@@ -751,7 +727,6 @@ set(SOURCES
|
||||
env/env_encryption.cc
|
||||
env/file_system.cc
|
||||
env/file_system_tracer.cc
|
||||
env/fs_on_demand.cc
|
||||
env/fs_remap.cc
|
||||
env/mock_env.cc
|
||||
env/unique_id_gen.cc
|
||||
@@ -939,7 +914,6 @@ set(SOURCES
|
||||
utilities/persistent_cache/volatile_tier_impl.cc
|
||||
utilities/simulator_cache/cache_simulator.cc
|
||||
utilities/simulator_cache/sim_cache.cc
|
||||
utilities/table_properties_collectors/compact_for_tiering_collector.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector.cc
|
||||
utilities/trace/file_trace_reader_writer.cc
|
||||
utilities/trace/replayer_impl.cc
|
||||
@@ -960,7 +934,6 @@ set(SOURCES
|
||||
utilities/transactions/write_prepared_txn_db.cc
|
||||
utilities/transactions/write_unprepared_txn.cc
|
||||
utilities/transactions/write_unprepared_txn_db.cc
|
||||
utilities/types_util.cc
|
||||
utilities/ttl/db_ttl_impl.cc
|
||||
utilities/wal_filter.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index.cc
|
||||
@@ -1052,7 +1025,6 @@ if(USE_FOLLY_LITE)
|
||||
list(APPEND SOURCES
|
||||
third-party/folly/folly/container/detail/F14Table.cpp
|
||||
third-party/folly/folly/detail/Futex.cpp
|
||||
third-party/folly/folly/lang/Exception.cpp
|
||||
third-party/folly/folly/lang/SafeAssert.cpp
|
||||
third-party/folly/folly/lang/ToAscii.cpp
|
||||
third-party/folly/folly/ScopeGuard.cpp
|
||||
@@ -1060,12 +1032,6 @@ if(USE_FOLLY_LITE)
|
||||
third-party/folly/folly/synchronization/DistributedMutex.cpp
|
||||
third-party/folly/folly/synchronization/ParkingLot.cpp)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/third-party/folly)
|
||||
exec_program(python3 ${PROJECT_SOURCE_DIR}/third-party/folly ARGS
|
||||
build/fbcode_builder/getdeps.py show-source-dir boost OUTPUT_VARIABLE
|
||||
BOOST_SOURCE_PATH)
|
||||
exec_program(ls ARGS -d ${BOOST_SOURCE_PATH}/boost* OUTPUT_VARIABLE
|
||||
BOOST_INCLUDE_DIR)
|
||||
include_directories(${BOOST_INCLUDE_DIR})
|
||||
add_definitions(-DUSE_FOLLY -DFOLLY_NO_CONFIG)
|
||||
list(APPEND THIRDPARTY_LIBS glog)
|
||||
endif()
|
||||
@@ -1375,7 +1341,6 @@ if(WITH_TESTS)
|
||||
db/file_indexer_test.cc
|
||||
db/filename_test.cc
|
||||
db/flush_job_test.cc
|
||||
db/db_follower_test.cc
|
||||
db/import_column_family_test.cc
|
||||
db/listener_test.cc
|
||||
db/log_test.cc
|
||||
@@ -1383,7 +1348,6 @@ if(WITH_TESTS)
|
||||
db/memtable_list_test.cc
|
||||
db/merge_helper_test.cc
|
||||
db/merge_test.cc
|
||||
db/multi_cf_iterator_test.cc
|
||||
db/options_file_test.cc
|
||||
db/perf_context_test.cc
|
||||
db/periodic_task_scheduler_test.cc
|
||||
@@ -1464,7 +1428,6 @@ if(WITH_TESTS)
|
||||
util/ribbon_test.cc
|
||||
util/slice_test.cc
|
||||
util/slice_transform_test.cc
|
||||
util/string_util_test.cc
|
||||
util/timer_queue_test.cc
|
||||
util/timer_test.cc
|
||||
util/thread_list_test.cc
|
||||
@@ -1489,7 +1452,6 @@ if(WITH_TESTS)
|
||||
utilities/persistent_cache/persistent_cache_test.cc
|
||||
utilities/simulator_cache/cache_simulator_test.cc
|
||||
utilities/simulator_cache/sim_cache_test.cc
|
||||
utilities/table_properties_collectors/compact_for_tiering_collector_test.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc
|
||||
utilities/transactions/optimistic_transaction_test.cc
|
||||
utilities/transactions/transaction_test.cc
|
||||
@@ -1500,7 +1462,6 @@ if(WITH_TESTS)
|
||||
utilities/transactions/lock/range/range_locking_test.cc
|
||||
utilities/transactions/timestamped_snapshot_test.cc
|
||||
utilities/ttl/ttl_test.cc
|
||||
utilities/types_util_test.cc
|
||||
utilities/util_merge_operators_test.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index_test.cc
|
||||
${PLUGIN_TESTS}
|
||||
@@ -1516,7 +1477,7 @@ if(WITH_TESTS)
|
||||
utilities/cassandra/test_utils.cc
|
||||
)
|
||||
enable_testing()
|
||||
add_custom_target(rocksdb_check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
set(TESTUTILLIB testutillib${ARTIFACT_SUFFIX})
|
||||
add_library(${TESTUTILLIB} STATIC ${TESTUTIL_SOURCE})
|
||||
target_link_libraries(${TESTUTILLIB} ${ROCKSDB_LIB} ${FOLLY_LIBS})
|
||||
@@ -1541,7 +1502,7 @@ if(WITH_TESTS)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} testharness gtest ${THIRDPARTY_LIBS} ${ROCKSDB_LIB})
|
||||
if(NOT "${exename}" MATCHES "db_sanity_test")
|
||||
gtest_discover_tests(${exename} DISCOVERY_TIMEOUT 120)
|
||||
add_dependencies(rocksdb_check ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
|
||||
endif()
|
||||
endforeach(sourcefile ${TESTS})
|
||||
|
||||
@@ -1561,7 +1522,7 @@ if(WITH_TESTS)
|
||||
add_executable(c_test db/c_test.c)
|
||||
target_link_libraries(c_test ${ROCKSDB_LIB_FOR_C} testharness)
|
||||
add_test(NAME c_test COMMAND c_test${ARTIFACT_SUFFIX})
|
||||
add_dependencies(rocksdb_check c_test)
|
||||
add_dependencies(check c_test)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
+3
-233
@@ -1,242 +1,12 @@
|
||||
# Rocksdb Change Log
|
||||
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
|
||||
|
||||
## 9.6.2 (10/31/2024)
|
||||
### Bug Fixes
|
||||
* Fix a leak of obsolete blob files left open until DB::Close(). This bug was introduced in version 9.4.0.
|
||||
|
||||
## 9.6.1 (08/24/2024)
|
||||
### Bug Fixes
|
||||
* Fix correctness of MultiGet across column families with user timestamp.
|
||||
|
||||
## 9.6.0 (08/19/2024)
|
||||
### New Features
|
||||
* *Best efforts recovery supports recovering to incomplete Version with a clean seqno cut that presents a valid point in time view from the user's perspective, if versioning history doesn't include atomic flush.
|
||||
* New option `BlockBasedTableOptions::decouple_partitioned_filters` should improve efficiency in serving read queries because filter and index partitions can consistently target the configured `metadata_block_size`. This option is currently opt-in.
|
||||
* Introduce a new mutable CF option `paranoid_memory_checks`. It enables additional validation on data integrity during reads/scanning. Currently, skip list based memtable will validate key ordering during look up and scans.
|
||||
|
||||
### Public API Changes
|
||||
* Add ticker stats to count file read retries due to checksum mismatch
|
||||
* Adds optional installation callback function for remote compaction
|
||||
|
||||
### Behavior Changes
|
||||
* There may be less intra-L0 compaction triggered by total L0 size being too small. We now use compensated file size (tombstones are assigned some value size) when calculating L0 size and reduce the threshold for L0 size limit. This is to avoid accumulating too much data/tombstones in L0.
|
||||
|
||||
### Bug Fixes
|
||||
* *Make DestroyDB supports slow deletion when it's configured in `SstFileManager`. The slow deletion is subject to the configured `rate_bytes_per_sec`, but not subject to the `max_trash_db_ratio`.
|
||||
* Fixed a bug where we set unprep_seqs_ even when WriteImpl() fails. This was caught by stress test write fault injection in WriteImpl(). This may have incorrectly caused iteration creation failure for unvalidated writes or returned wrong result for WriteUnpreparedTxn::GetUnpreparedSequenceNumbers().
|
||||
* Fixed a bug where successful write right after error recovery for last failed write finishes causes duplicate WAL entries
|
||||
* Fixed a data race involving the background error status in `unordered_write` mode.
|
||||
* *Fix a bug where file snapshot functions like backup, checkpoint may attempt to copy a non-existing manifest file. #12882
|
||||
* Fix a bug where per kv checksum corruption may be ignored in MultiGet().
|
||||
* Fix a race condition in pessimistic transactions that could allow multiple transactions with the same name to be registered simultaneously, resulting in a crash or other unpredictable behavior.
|
||||
|
||||
## 9.5.0 (07/19/2024)
|
||||
### Public API Changes
|
||||
* Introduced new C API function rocksdb_writebatch_iterate_cf for column family-aware iteration over the contents of a WriteBatch
|
||||
* Add support to ingest SST files generated by a DB instead of SstFileWriter. This can be enabled with experimental option `IngestExternalFileOptions::allow_db_generated_files`.
|
||||
|
||||
### Behavior Changes
|
||||
* When calculating total log size for the `log_size_for_flush` argument in `CreateCheckpoint` API, the size of the archived log will not be included to avoid unnecessary flush
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a major bug in which an iterator using prefix filtering and SeekForPrev might miss data when the DB is using `whole_key_filtering=false` and `partition_filters=true`.
|
||||
* Fixed a bug where `OnErrorRecoveryBegin()` is not called before auto recovery starts.
|
||||
* Fixed a bug where event listener reads ErrorHandler's `bg_error_` member without holding db mutex(#12803).
|
||||
* Fixed a bug in handling MANIFEST write error that caused the latest valid MANIFEST file to get deleted, resulting in the DB being unopenable.
|
||||
* Fixed a race between error recovery due to manifest sync or write failure and external SST file ingestion. Both attempt to write a new manifest file, which causes an assertion failure.
|
||||
|
||||
### Performance Improvements
|
||||
* Fix an issue where compactions were opening table files and reading table properties while holding db mutex_.
|
||||
* Reduce unnecessary filesystem queries and DB mutex acquires in creating backups and checkpoints.
|
||||
|
||||
## 9.4.0 (06/23/2024)
|
||||
### New Features
|
||||
* Added a `CompactForTieringCollectorFactory` to auto trigger compaction for tiering use case.
|
||||
* Optimistic transactions and pessimistic transactions with the WriteCommitted policy now support the `GetEntityForUpdate` API.
|
||||
* Added a new "count" command to the ldb repl shell. By default, it prints a count of keys in the database from start to end. The options --from=<key> and/or --to=<key> can be specified to limit the range.
|
||||
* Add `rocksdb_writebatch_update_timestamps`, `rocksdb_writebatch_wi_update_timestamps` in C API.
|
||||
* Add `rocksdb_iter_refresh` in C API.
|
||||
* Add `rocksdb_writebatch_create_with_params`, `rocksdb_writebatch_wi_create_with_params` to create WB and WBWI with all options in C API
|
||||
|
||||
### Public API Changes
|
||||
* Deprecated names `LogFile` and `VectorLogPtr` in favor of new names `WalFile` and `VectorWalPtr`.
|
||||
* Introduce a new universal compaction option CompactionOptionsUniversal::max_read_amp which allows user to define the limit on the number of sorted runs separately from the trigger for compaction (`level0_file_num_compaction_trigger`) #12477.
|
||||
|
||||
### Behavior Changes
|
||||
* Inactive WALs are immediately closed upon being fully sync-ed rather than in a background thread. This is to ensure LinkFile() is not called on files still open for write, which might not be supported by some FileSystem implementations. This should not be a performance issue, but an opt-out is available with with new DB option `background_close_inactive_wals`.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a rare case in which a hard-linked WAL in a Checkpoint is not fully synced (so might lose data on power loss).
|
||||
* Fixed the output of the `ldb dump_wal` command for `PutEntity` records so it prints the key and correctly resets the hexadecimal formatting flag after printing the wide-column entity.
|
||||
* Fixed an issue where `PutEntity` records were handled incorrectly while rebuilding transactions during recovery.
|
||||
* Various read operations could ignore various ReadOptions that might be relevant. Fixed many such cases, which can result in behavior change but a better reflection of specified options.
|
||||
|
||||
### Performance Improvements
|
||||
* Improved write throughput to memtable when there's a large number of concurrent writers and allow_concurrent_memtable_write=true(#12545)
|
||||
|
||||
## 9.3.0 (05/17/2024)
|
||||
### New Features
|
||||
* Optimistic transactions and pessimistic transactions with the WriteCommitted policy now support the `GetEntity` API.
|
||||
* Added new `Iterator` property, "rocksdb.iterator.is-value-pinned", for checking whether the `Slice` returned by `Iterator::value()` can be used until the `Iterator` is destroyed.
|
||||
* Optimistic transactions and WriteCommitted pessimistic transactions now support the `MultiGetEntity` API.
|
||||
* Optimistic transactions and pessimistic transactions with the WriteCommitted policy now support the `PutEntity` API. Support for read APIs and other write policies (WritePrepared, WriteUnprepared) will be added later.
|
||||
|
||||
### Public API Changes
|
||||
* Exposed block based metadata cache options via C API
|
||||
* Exposed compaction pri via c api.
|
||||
* Add a kAdmPolicyAllowAll option to TieredAdmissionPolicy that admits all blocks evicted from the primary block cache into the compressed secondary cache.
|
||||
|
||||
### Behavior Changes
|
||||
* CompactRange() with change_level=true on a CF with FIFO compaction will return Status::NotSupported().
|
||||
* External file ingestion with FIFO compaction will always ingest to L0.
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed a bug for databases using `DBOptions::allow_2pc == true` (all `TransactionDB`s except `OptimisticTransactionDB`) that have exactly one column family. Due to a missing WAL sync, attempting to open the DB could have returned a `Status::Corruption` with a message like "SST file is ahead of WALs".
|
||||
* Fix a bug in CreateColumnFamilyWithImport() where if multiple CFs are imported, we were not resetting files' epoch number and L0 files can have overlapping key range but the same epoch number.
|
||||
* Fixed race conditions when `ColumnFamilyOptions::inplace_update_support == true` between user overwrites and reads on the same key.
|
||||
* Fix a bug where `CompactFiles()` can compact files of range conflict with other ongoing compactions' when `preclude_last_level_data_seconds > 0` is used
|
||||
* Fixed a false positive `Status::Corruption` reported when reopening a DB that used `DBOptions::recycle_log_file_num > 0` and `DBOptions::wal_compression != kNoCompression`.
|
||||
* While WAL is locked with LockWAL(), some operations like Flush() and IngestExternalFile() are now blocked as they should have been.
|
||||
* Fixed a bug causing stale memory access when using the TieredSecondaryCache with an NVM secondary cache, and a file system that supports return an FS allocated buffer for MultiRead (FSSupportedOps::kFSBuffer is set).
|
||||
|
||||
## 9.2.0 (05/01/2024)
|
||||
### New Features
|
||||
* Added two options `deadline` and `max_size_bytes` for CacheDumper to exit early
|
||||
* Added a new API `GetEntityFromBatchAndDB` to `WriteBatchWithIndex` that can be used for wide-column point lookups with read-your-own-writes consistency. Similarly to `GetFromBatchAndDB`, the API can combine data from the write batch with data from the underlying database if needed. See the API comments for more details.
|
||||
* [Experimental] Introduce two new cross-column-family iterators - CoalescingIterator and AttributeGroupIterator. The CoalescingIterator enables users to iterate over multiple column families and access their values and columns. During this iteration, if the same key exists in more than one column family, the keys in the later column family will overshadow the previous ones. The AttributeGroupIterator allows users to gather wide columns per Column Family and create attribute groups while iterating over keys across all CFs.
|
||||
* Added a new API `MultiGetEntityFromBatchAndDB` to `WriteBatchWithIndex` that can be used for batched wide-column point lookups with read-your-own-writes consistency. Similarly to `MultiGetFromBatchAndDB`, the API can combine data from the write batch with data from the underlying database if needed. See the API comments for more details.
|
||||
* *Adds a `SstFileReader::NewTableIterator` API to support programmatically read a SST file as a raw table file.
|
||||
* Add an option to `WaitForCompactOptions` - `wait_for_purge` to make `WaitForCompact()` API wait for background purge to complete
|
||||
|
||||
### Public API Changes
|
||||
* DeleteRange() will return NotSupported() if row_cache is configured since they don't work together in some cases.
|
||||
* Deprecated `CompactionOptions::compression` since `CompactionOptions`'s API for configuring compression was incomplete, unsafe, and likely unnecessary
|
||||
* Using `OptionChangeMigration()` to migrate from non-FIFO to FIFO compaction
|
||||
with `Options::compaction_options_fifo.max_table_files_size` > 0 can cause
|
||||
the whole DB to be dropped right after migration if the migrated data is larger than
|
||||
`max_table_files_size`
|
||||
|
||||
### Behavior Changes
|
||||
* Enabling `BlockBasedTableOptions::block_align` is now incompatible (i.e., APIs will return `Status::InvalidArgument`) with more ways of enabling compression: `CompactionOptions::compression`, `ColumnFamilyOptions::compression_per_level`, and `ColumnFamilyOptions::bottommost_compression`.
|
||||
* Changed the default value of `CompactionOptions::compression` to `kDisableCompressionOption`, which means the compression type is determined by the `ColumnFamilyOptions`.
|
||||
* `BlockBasedTableOptions::optimize_filters_for_memory` is now set to true by default. When `partition_filters=false`, this could lead to somewhat increased average RSS memory usage by the block cache, but this "extra" usage is within the allowed memory budget and should make memory usage more consistent (by minimizing internal fragmentation for more kinds of blocks).
|
||||
* Dump all keys for cache dumper impl if `SetDumpFilter()` is not called
|
||||
* `CompactRange()` with `CompactRangeOptions::change_level = true` and `CompactRangeOptions::target_level = 0` that ends up moving more than 1 file from non-L0 to L0 will return `Status::Aborted()`.
|
||||
* On distributed file systems that support file system level checksum verification and reconstruction reads, RocksDB will now retry a file read if the initial read fails RocksDB block level or record level checksum verification. This applies to MANIFEST file reads when the DB is opened, and to SST file reads at all times.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a bug causing `VerifyFileChecksums()` to return false-positive corruption under `BlockBasedTableOptions::block_align=true`
|
||||
* Provide consistent view of the database across the column families for `NewIterators()` API.
|
||||
* Fixed feature interaction bug for `DeleteRange()` together with `ColumnFamilyOptions::memtable_insert_with_hint_prefix_extractor`. The impact of this bug would likely be corruption or crashing.
|
||||
* Fixed hang in `DisableManualCompactions()` where compactions waiting to be scheduled due to conflicts would not be canceled promptly
|
||||
* Fixed a regression when `ColumnFamilyOptions::max_successive_merges > 0` where the CPU overhead for deciding whether to merge could have increased unless the user had set the option `ColumnFamilyOptions::strict_max_successive_merges`
|
||||
* Fixed a bug in `MultiGet()` and `MultiGetEntity()` together with blob files (`ColumnFamilyOptions::enable_blob_files == true`). An error looking up one of the keys could cause the results to be wrong for other keys for which the statuses were `Status::OK`.
|
||||
* Fixed a bug where wrong padded bytes are used to generate file checksum and `DataVerificationInfo::checksum` upon file creation
|
||||
* Correctly implemented the move semantics of `PinnableWideColumns`.
|
||||
* Fixed a bug when the recycle_log_file_num in DBOptions is changed from 0 to non-zero when a DB is reopened. On a subsequent reopen, if a log file created when recycle_log_file_num==0 was reused previously, is alive and is empty, we could end up inserting stale WAL records into the memtable.
|
||||
* *Fix a bug where obsolete files' deletion during DB::Open are not rate limited with `SstFilemManager`'s slow deletion feature even if it's configured.
|
||||
|
||||
## 9.1.0 (03/22/2024)
|
||||
### New Features
|
||||
* Added an option, `GetMergeOperandsOptions::continue_cb`, to give users the ability to end `GetMergeOperands()`'s lookup process before all merge operands were found.
|
||||
* *Add sanity checks for ingesting external files that currently checks if the user key comparator used to create the file is compatible with the column family's user key comparator.
|
||||
*Support ingesting external files for column family that has user-defined timestamps in memtable only enabled.
|
||||
* On file systems that support storage level data checksum and reconstruction, retry SST block reads for point lookups, scans, and flush and compaction if there's a checksum mismatch on the initial read.
|
||||
* Some enhancements and fixes to experimental Temperature handling features, including new `default_write_temperature` CF option and opening an `SstFileWriter` with a temperature.
|
||||
* `WriteBatchWithIndex` now supports wide-column point lookups via the `GetEntityFromBatch` API. See the API comments for more details.
|
||||
* *Implement experimental features: API `Iterator::GetProperty("rocksdb.iterator.write-time")` to allow users to get data's approximate write unix time and write data with a specific write time via `WriteBatch::TimedPut` API.
|
||||
|
||||
### Public API Changes
|
||||
* Best-effort recovery (`best_efforts_recovery == true`) may now be used together with atomic flush (`atomic_flush == true`). The all-or-nothing recovery guarantee for atomically flushed data will be upheld.
|
||||
* Remove deprecated option `bottommost_temperature`, already replaced by `last_level_temperature`
|
||||
* Added new PerfContext counters for block cache bytes read - block_cache_index_read_byte, block_cache_filter_read_byte, block_cache_compression_dict_read_byte, and block_cache_read_byte.
|
||||
* Deprecate experimental Remote Compaction APIs - StartV2() and WaitForCompleteV2() and introduce Schedule() and Wait(). The new APIs essentially does the same thing as the old APIs. They allow taking externally generated unique id to wait for remote compaction to complete.
|
||||
* *For API `WriteCommittedTransaction::GetForUpdate`, if the column family enables user-defined timestamp, it was mandated that argument `do_validate` cannot be false, and UDT based validation has to be done with a user set read timestamp. It's updated to make the UDT based validation optional if user sets `do_validate` to false and does not set a read timestamp. With this, `GetForUpdate` skips UDT based validation and it's users' responsibility to enforce the UDT invariant. SO DO NOT skip this UDT-based validation if users do not have ways to enforce the UDT invariant. Ways to enforce the invariant on the users side include manage a monotonically increasing timestamp, commit transactions in a single thread etc.
|
||||
* Defined a new PerfLevel `kEnableWait` to measure time spent by user threads blocked in RocksDB other than mutex, such as a write thread waiting to be added to a write group, a write thread delayed or stalled etc.
|
||||
* `RateLimiter`'s API no longer requires the burst size to be the refill size. Users of `NewGenericRateLimiter()` can now provide burst size in `single_burst_bytes`. Implementors of `RateLimiter::SetSingleBurstBytes()` need to adapt their implementations to match the changed API doc.
|
||||
* Add `write_memtable_time` to the newly introduced PerfLevel `kEnableWait`.
|
||||
|
||||
### Behavior Changes
|
||||
* `RateLimiter`s created by `NewGenericRateLimiter()` no longer modify the refill period when `SetSingleBurstBytes()` is called.
|
||||
* Merge writes will only keep merge operand count within `ColumnFamilyOptions::max_successive_merges` when the key's merge operands are all found in memory, unless `strict_max_successive_merges` is explicitly set.
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed `kBlockCacheTier` reads to return `Status::Incomplete` when I/O is needed to fetch a merge chain's base value from a blob file.
|
||||
* Fixed `kBlockCacheTier` reads to return `Status::Incomplete` on table cache miss rather than incorrectly returning an empty value.
|
||||
* Fixed a data race in WalManager that may affect how frequent PurgeObsoleteWALFiles() runs.
|
||||
* Re-enable the recycle_log_file_num option in DBOptions for kPointInTimeRecovery WAL recovery mode, which was previously disabled due to a bug in the recovery logic. This option is incompatible with WriteOptions::disableWAL. A Status::InvalidArgument() will be returned if disableWAL is specified.
|
||||
|
||||
### Performance Improvements
|
||||
* Java API `multiGet()` variants now take advantage of the underlying batched `multiGet()` performance improvements.
|
||||
Before
|
||||
```
|
||||
Benchmark (columnFamilyTestType) (keyCount) (keySize) (multiGetSize) (valueSize) Mode Cnt Score Error Units
|
||||
MultiGetBenchmarks.multiGetList10 no_column_family 10000 16 100 64 thrpt 25 6315.541 ± 8.106 ops/s
|
||||
MultiGetBenchmarks.multiGetList10 no_column_family 10000 16 100 1024 thrpt 25 6975.468 ± 68.964 ops/s
|
||||
```
|
||||
After
|
||||
```
|
||||
Benchmark (columnFamilyTestType) (keyCount) (keySize) (multiGetSize) (valueSize) Mode Cnt Score Error Units
|
||||
MultiGetBenchmarks.multiGetList10 no_column_family 10000 16 100 64 thrpt 25 7046.739 ± 13.299 ops/s
|
||||
MultiGetBenchmarks.multiGetList10 no_column_family 10000 16 100 1024 thrpt 25 7654.521 ± 60.121 ops/s
|
||||
```
|
||||
|
||||
## 9.0.0 (02/16/2024)
|
||||
### New Features
|
||||
* Provide support for FSBuffer for point lookups. Also added support for scans and compactions that don't go through prefetching.
|
||||
* *Make `SstFileWriter` create SST files without persisting user defined timestamps when the `Option.persist_user_defined_timestamps` flag is set to false.
|
||||
* Add support for user-defined timestamps in APIs `DeleteFilesInRanges` and `GetPropertiesOfTablesInRange`.
|
||||
* Mark wal\_compression feature as production-ready. Currently only compatible with ZSTD compression.
|
||||
|
||||
### Public API Changes
|
||||
* Allow setting Stderr logger via C API
|
||||
* Declare one Get and one MultiGet variant as pure virtual, and make all the other variants non-overridable. The methods required to be implemented by derived classes of DB allow returning timestamps. It is up to the implementation to check and return an error if timestamps are not supported. The non-batched MultiGet APIs are reimplemented in terms of batched MultiGet, so callers might see a performance improvement.
|
||||
* Exposed mode option to Rate Limiter via c api.
|
||||
* Removed deprecated option `access_hint_on_compaction_start`
|
||||
* Removed deprecated option `ColumnFamilyOptions::check_flush_compaction_key_order`
|
||||
* *Remove the default `WritableFile::GetFileSize` and `FSWritableFile::GetFileSize` implementation that returns 0 and make it pure virtual, so that subclasses are enforced to explicitly provide an implementation.
|
||||
* Removed deprecated option `ColumnFamilyOptions::level_compaction_dynamic_file_size`
|
||||
* *Removed tickers with typos "rocksdb.error.handler.bg.errro.count", "rocksdb.error.handler.bg.io.errro.count", "rocksdb.error.handler.bg.retryable.io.errro.count".
|
||||
* Remove the force mode for `EnableFileDeletions` API because it is unsafe with no known legitimate use.
|
||||
* Removed deprecated option `ColumnFamilyOptions::ignore_max_compaction_bytes_for_input`
|
||||
* `sst_dump --command=check` now compares the number of records in a table with `num_entries` in table property, and reports corruption if there is a mismatch. API `SstFileDumper::ReadSequential()` is updated to optionally do this verification. (#12322)
|
||||
|
||||
### Behavior Changes
|
||||
* format\_version=6 is the new default setting in BlockBasedTableOptions, for more robust data integrity checking. DBs and SST files written with this setting cannot be read by RocksDB versions before 8.6.0.
|
||||
* Compactions can be scheduled in parallel in an additional scenario: multiple files are marked for compaction within a single column family
|
||||
* For leveled compaction, RocksDB will try to do intra-L0 compaction if the total L0 size is small compared to Lbase (#12214). Users with atomic_flush=true are more likely to see the impact of this change.
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed a data race in `DBImpl::RenameTempFileToOptionsFile`.
|
||||
* Fix some perf context statistics error in write steps. which include missing write_memtable_time in unordered_write. missing write_memtable_time in PipelineWrite when Writer stat is STATE_PARALLEL_MEMTABLE_WRITER. missing write_delay_time when calling DelayWrite in WriteImplWALOnly function.
|
||||
* Fixed a bug that can, under rare circumstances, cause MultiGet to return an incorrect result for a duplicate key in a MultiGet batch.
|
||||
* Fix a bug where older data of an ingested key can be returned for read when universal compaction is used
|
||||
|
||||
## 8.11.0 (01/19/2024)
|
||||
### New Features
|
||||
* Add new statistics: `rocksdb.sst.write.micros` measures time of each write to SST file; `rocksdb.file.write.{flush|compaction|db.open}.micros` measure time of each write to SST table (currently only block-based table format) and blob file for flush, compaction and db open.
|
||||
|
||||
### Public API Changes
|
||||
* Added another enumerator `kVerify` to enum class `FileOperationType` in listener.h. Update your `switch` statements as needed.
|
||||
* Add CompressionOptions to the CompressedSecondaryCacheOptions structure to allow users to specify library specific options when creating the compressed secondary cache.
|
||||
* Deprecated several options: `level_compaction_dynamic_file_size`, `ignore_max_compaction_bytes_for_input`, `check_flush_compaction_key_order`, `flush_verify_memtable_count`, `compaction_verify_record_count`, `fail_if_options_file_error`, and `enforce_single_del_contracts`
|
||||
* Exposed options ttl via c api.
|
||||
|
||||
### Behavior Changes
|
||||
* `rocksdb.blobdb.blob.file.write.micros` expands to also measure time writing the header and footer. Therefore the COUNT may be higher and values may be smaller than before. For stacked BlobDB, it no longer measures the time of explictly flushing blob file.
|
||||
* Files will be compacted to the next level if the data age exceeds periodic_compaction_seconds except for the last level.
|
||||
* Reduced the compaction debt ratio trigger for scheduling parallel compactions
|
||||
* For leveled compaction with default compaction pri (kMinOverlappingRatio), files marked for compaction will be prioritized over files not marked when picking a file from a level for compaction.
|
||||
## 8.10.2 (02/16/2024)
|
||||
* Update zlib to 1.3.1 for Java builds
|
||||
|
||||
## 8.10.1 (01/16/2024)
|
||||
### Bug Fixes
|
||||
* Fix bug in auto_readahead_size that combined with IndexType::kBinarySearchWithFirstKey + fails or iterator lands at a wrong key
|
||||
* Fixed some cases in which DB file corruption was detected but ignored on creating a backup with BackupEngine.
|
||||
* Fix bugs where `rocksdb.blobdb.blob.file.synced` includes blob files failed to get synced and `rocksdb.blobdb.blob.file.bytes.written` includes blob bytes failed to get written.
|
||||
* Fixed a possible memory leak or crash on a failure (such as I/O error) in automatic atomic flush of multiple column families.
|
||||
* Fixed some cases of in-memory data corruption using mmap reads with `BackupEngine`, `sst_dump`, or `ldb`.
|
||||
* Fixed issues with experimental `preclude_last_level_data_seconds` option that could interfere with expected data tiering.
|
||||
* Fixed the handling of the edge case when all existing blob files become unreferenced. Such files are now correctly deleted.
|
||||
|
||||
## 8.10.0 (12/15/2023)
|
||||
### New Features
|
||||
|
||||
+4
-8
@@ -126,6 +126,7 @@ most processors made since roughly 2013.
|
||||
* Update XCode: run `xcode-select --install` (or install it from XCode App's settting).
|
||||
* Install via [homebrew](http://brew.sh/).
|
||||
* If you're first time developer in MacOS, you still need to run: `xcode-select --install` in your command line.
|
||||
* run `brew tap homebrew/versions; brew install gcc7 --use-llvm` to install gcc 7 (or higher).
|
||||
* run `brew install rocksdb`
|
||||
|
||||
* **FreeBSD** (11.01):
|
||||
@@ -168,26 +169,21 @@ most processors made since roughly 2013.
|
||||
|
||||
* Install the dependencies for RocksDB:
|
||||
|
||||
`pkg_add gmake gflags snappy bzip2 lz4 zstd git bash findutils gnuwatch`
|
||||
pkg_add gmake gflags snappy bzip2 lz4 zstd git jdk bash findutils gnuwatch
|
||||
|
||||
* Build RocksDB from source:
|
||||
|
||||
```bash
|
||||
cd ~
|
||||
git clone https://github.com/facebook/rocksdb.git
|
||||
cd rocksdb
|
||||
gmake static_lib
|
||||
```
|
||||
|
||||
* Build RocksJava from source (optional):
|
||||
* In OpenBSD, JDK depends on XWindows system, so please check that you installed OpenBSD with `xbase` package.
|
||||
* Install dependencies : `pkg_add -v jdk%1.8`
|
||||
```bash
|
||||
|
||||
cd rocksdb
|
||||
export JAVA_HOME=/usr/local/jdk-1.8.0
|
||||
export PATH=$PATH:/usr/local/jdk-1.8.0/bin
|
||||
gmake rocksdbjava SHA256_CMD='sha256 -q'
|
||||
```
|
||||
gmake rocksdbjava
|
||||
|
||||
* **iOS**:
|
||||
* Run: `TARGET_OS=IOS make static_lib`. When building the project which uses rocksdb iOS library, make sure to define an important pre-processing macros: `IOS_CROSS_COMPILE`.
|
||||
|
||||
@@ -103,7 +103,6 @@ dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; \
|
||||
export LIB_MODE="$(LIB_MODE)"; \
|
||||
export ROCKSDB_CXX_STANDARD="$(ROCKSDB_CXX_STANDARD)"; \
|
||||
export USE_FOLLY="$(USE_FOLLY)"; \
|
||||
export USE_FOLLY_LITE="$(USE_FOLLY_LITE)"; \
|
||||
"$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk"))
|
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include make_config.mk
|
||||
@@ -501,17 +500,6 @@ endif
|
||||
ifeq ($(USE_FOLLY_LITE),1)
|
||||
# Path to the Folly source code and include files
|
||||
FOLLY_DIR = ./third-party/folly
|
||||
ifneq ($(strip $(BOOST_SOURCE_PATH)),)
|
||||
BOOST_INCLUDE = $(shell (ls -d $(BOOST_SOURCE_PATH)/boost*/))
|
||||
# AIX: pre-defined system headers are surrounded by an extern "C" block
|
||||
ifeq ($(PLATFORM), OS_AIX)
|
||||
PLATFORM_CCFLAGS += -I$(BOOST_INCLUDE)
|
||||
PLATFORM_CXXFLAGS += -I$(BOOST_INCLUDE)
|
||||
else
|
||||
PLATFORM_CCFLAGS += -isystem $(BOOST_INCLUDE)
|
||||
PLATFORM_CXXFLAGS += -isystem $(BOOST_INCLUDE)
|
||||
endif
|
||||
endif # BOOST_SOURCE_PATH
|
||||
# AIX: pre-defined system headers are surrounded by an extern "C" block
|
||||
ifeq ($(PLATFORM), OS_AIX)
|
||||
PLATFORM_CCFLAGS += -I$(FOLLY_DIR)
|
||||
@@ -551,8 +539,7 @@ endif
|
||||
|
||||
ifdef USE_CLANG
|
||||
# Used by some teams in Facebook
|
||||
WARNING_FLAGS += -Wshift-sign-overflow -Wambiguous-reversed-operator \
|
||||
-Wimplicit-fallthrough -Wreinterpret-base-class -Wundefined-reinterpret-cast
|
||||
WARNING_FLAGS += -Wshift-sign-overflow -Wambiguous-reversed-operator -Wimplicit-fallthrough
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
@@ -648,37 +635,26 @@ TESTS = $(patsubst %.cc, %, $(notdir $(TEST_MAIN_SOURCES)))
|
||||
TESTS += $(patsubst %.c, %, $(notdir $(TEST_MAIN_SOURCES_C)))
|
||||
TESTS += $(PLUGIN_TESTS)
|
||||
|
||||
# `make check-headers` to verify that each header file includes its own deps
|
||||
# and that public headers do not depend on internal headers
|
||||
# `make check-headers` to very that each header file includes its own
|
||||
# dependencies
|
||||
ifneq ($(filter check-headers, $(MAKECMDGOALS)),)
|
||||
# TODO: add/support JNI headers
|
||||
DEV_HEADER_DIRS := $(sort include/ $(dir $(ALL_SOURCES)))
|
||||
# Some headers like in port/ are platform-specific
|
||||
DEV_HEADERS_TO_CHECK := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | grep -E -v 'port/|plugin/|lua/|range_tree/')
|
||||
PUBLIC_HEADERS_TO_CHECK := $(shell $(FIND) include/ -type f -name '*.h' | grep -E -v 'lua/')
|
||||
DEV_HEADERS := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | grep -E -v 'port/|plugin/|lua/|range_tree/')
|
||||
else
|
||||
DEV_HEADERS_TO_CHECK :=
|
||||
PUBLIC_HEADERS_TO_CHECK :=
|
||||
DEV_HEADERS :=
|
||||
endif
|
||||
HEADER_OK_FILES = $(patsubst %.h, %.h.ok, $(DEV_HEADERS_TO_CHECK)) \
|
||||
$(patsubst %.h, %.h.pub, $(PUBLIC_HEADERS_TO_CHECK))
|
||||
HEADER_OK_FILES = $(patsubst %.h, %.h.ok, $(DEV_HEADERS))
|
||||
|
||||
AM_V_CCH = $(am__v_CCH_$(V))
|
||||
am__v_CCH_ = $(am__v_CCH_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CCH_0 = @echo " CC.h " $<;
|
||||
am__v_CCH_1 =
|
||||
|
||||
# verify headers include their own dependencies, under dev build settings
|
||||
%.h.ok: %.h # .h.ok not actually created, so re-checked on each invocation
|
||||
# -DROCKSDB_NAMESPACE=42 ensures the namespace header is included
|
||||
$(AM_V_CCH) echo '#include "$<"' | $(CXX) $(CXXFLAGS) \
|
||||
-DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
|
||||
|
||||
# verify public headers do not depend on internal headers, under typical
|
||||
# user build settings
|
||||
%.h.pub: %.h # .h.pub not actually created, so re-checked on each invocation
|
||||
$(AM_V_CCH) cd include/ && echo '#include "$(patsubst include/%,%,$<)"' | \
|
||||
$(CXX) -I. -DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
|
||||
$(AM_V_CCH) echo '#include "$<"' | $(CXX) $(CXXFLAGS) -DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
|
||||
|
||||
check-headers: $(HEADER_OK_FILES)
|
||||
|
||||
@@ -1633,9 +1609,6 @@ object_registry_test: $(OBJ_DIR)/utilities/object_registry_test.o $(TEST_LIBRARY
|
||||
ttl_test: $(OBJ_DIR)/utilities/ttl/ttl_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
types_util_test: $(OBJ_DIR)/utilities/types_util_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
write_batch_with_index_test: $(OBJ_DIR)/utilities/write_batch_with_index/write_batch_with_index_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1654,9 +1627,6 @@ compaction_job_stats_test: $(OBJ_DIR)/db/compaction/compaction_job_stats_test.o
|
||||
compaction_service_test: $(OBJ_DIR)/db/compaction/compaction_service_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
compact_for_tiering_collector_test: $(OBJ_DIR)/utilities/table_properties_collectors/compact_for_tiering_collector_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
compact_on_deletion_collector_test: $(OBJ_DIR)/utilities/table_properties_collectors/compact_on_deletion_collector_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1669,9 +1639,6 @@ wal_edit_test: $(OBJ_DIR)/db/wal_edit_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
dbformat_test: $(OBJ_DIR)/db/dbformat_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
multi_cf_iterator_test: $(OBJ_DIR)/db/multi_cf_iterator_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
env_basic_test: $(OBJ_DIR)/env/env_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1801,9 +1768,6 @@ cuckoo_table_db_test: $(OBJ_DIR)/db/cuckoo_table_db_test.o $(TEST_LIBRARY) $(LIB
|
||||
listener_test: $(OBJ_DIR)/db/listener_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
string_util_test: $(OBJ_DIR)/util/string_util_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
thread_list_test: $(OBJ_DIR)/util/thread_list_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1948,9 +1912,6 @@ sst_file_reader_test: $(OBJ_DIR)/table/sst_file_reader_test.o $(TEST_LIBRARY) $(
|
||||
db_secondary_test: $(OBJ_DIR)/db/db_secondary_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_follower_test: $(OBJ_DIR)/db/db_follower_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
block_cache_tracer_test: $(OBJ_DIR)/trace_replay/block_cache_tracer_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -2139,8 +2100,8 @@ 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.1
|
||||
SNAPPY_SHA256 ?= 736aeb64d86566d2236ddffa2865ee5d7a82d26c9016b36218fcc27ea4f09f86
|
||||
SNAPPY_VER ?= 1.1.8
|
||||
SNAPPY_SHA256 ?= 16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f
|
||||
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
|
||||
LZ4_VER ?= 1.9.4
|
||||
LZ4_SHA256 ?= 0b0e3aa07c8c063ddf40b082bdf7e37a1562bda40a0ff5272957f3e987e0e54b
|
||||
@@ -2237,7 +2198,7 @@ libsnappy.a: snappy-$(SNAPPY_VER).tar.gz
|
||||
-rm -rf snappy-$(SNAPPY_VER)
|
||||
tar xvzf snappy-$(SNAPPY_VER).tar.gz
|
||||
mkdir snappy-$(SNAPPY_VER)/build
|
||||
cd snappy-$(SNAPPY_VER)/build && CFLAGS='$(ARCHFLAG) ${JAVA_STATIC_DEPS_CCFLAGS} ${EXTRA_CFLAGS}' CXXFLAGS='$(ARCHFLAG) ${JAVA_STATIC_DEPS_CXXFLAGS} ${EXTRA_CXXFLAGS}' LDFLAGS='${JAVA_STATIC_DEPS_LDFLAGS} ${EXTRA_LDFLAGS}' cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DSNAPPY_BUILD_BENCHMARKS=OFF -DSNAPPY_BUILD_TESTS=OFF --compile-no-warning-as-error ${PLATFORM_CMAKE_FLAGS} .. && $(MAKE) ${SNAPPY_MAKE_TARGET}
|
||||
cd snappy-$(SNAPPY_VER)/build && CFLAGS='$(ARCHFLAG) ${JAVA_STATIC_DEPS_CCFLAGS} ${EXTRA_CFLAGS}' CXXFLAGS='$(ARCHFLAG) ${JAVA_STATIC_DEPS_CXXFLAGS} ${EXTRA_CXXFLAGS}' LDFLAGS='${JAVA_STATIC_DEPS_LDFLAGS} ${EXTRA_LDFLAGS}' cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON ${PLATFORM_CMAKE_FLAGS} .. && $(MAKE) ${SNAPPY_MAKE_TARGET}
|
||||
cp snappy-$(SNAPPY_VER)/build/libsnappy.a .
|
||||
|
||||
lz4-$(LZ4_VER).tar.gz:
|
||||
@@ -2367,47 +2328,47 @@ 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:centos6_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) evolvedbinary/rocksjava:centos6_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerx86_64:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:centos6_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerppc64le:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerarm64v8:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockers390x:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:ubuntu18_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerriscv64:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:ubuntu20_riscv64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerx86musl:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_x86-musl-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:alpine3_x86-be /rocksdb-host/java/crossbuild/docker-build-linux.sh
|
||||
docker run --rm --name rocksdb_linux_x86-musl-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) evolvedbinary/rocksjava:alpine3_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-alpine.sh
|
||||
|
||||
rocksdbjavastaticdockerx86_64musl:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:alpine3_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-alpine.sh
|
||||
|
||||
rocksdbjavastaticdockerppc64lemusl:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:alpine3_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-alpine.sh
|
||||
|
||||
rocksdbjavastaticdockerarm64v8musl:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:alpine3_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-alpine.sh
|
||||
|
||||
rocksdbjavastaticdockers390xmusl:
|
||||
mkdir -p java/target
|
||||
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
|
||||
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) evolvedbinary/rocksjava:alpine3_s390x-be /rocksdb-host/java/crossbuild/docker-build-linux-alpine.sh
|
||||
|
||||
rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral
|
||||
|
||||
@@ -2484,13 +2445,14 @@ 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 c48fdd205c1c291651749d532b8055fe822bba25
|
||||
cd third-party/folly && git reset --hard beacd86d63cd71c904632262e6c36f60874d78ba
|
||||
@# A hack to remove boost dependency.
|
||||
@# NOTE: this hack is only needed if building using USE_FOLLY_LITE
|
||||
perl -pi -e 's/^(#include <boost)/\/\/$$1/' third-party/folly/folly/functional/Invoke.h
|
||||
@# 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
|
||||
|
||||
CXX_M_FLAGS = $(filter -m%, $(CXXFLAGS))
|
||||
|
||||
@@ -2502,6 +2464,8 @@ build_folly:
|
||||
echo "Please run checkout_folly first"; \
|
||||
false; \
|
||||
fi
|
||||
# Restore the original version of Invoke.h with boost dependency
|
||||
cd third-party/folly && ${GIT_COMMAND} checkout folly/functional/Invoke.h
|
||||
cd third-party/folly && \
|
||||
CXXFLAGS=" $(CXX_M_FLAGS) -DHAVE_CXX11_ATOMIC " $(PYTHON) build/fbcode_builder/getdeps.py build --no-tests
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# This file is a Facebook-specific integration for buck builds, so can
|
||||
# only be validated by Facebook employees.
|
||||
load("//rocks/buckifier:defs.bzl", "cpp_library_wrapper","rocks_cpp_library_wrapper","cpp_binary_wrapper","cpp_unittest_wrapper","fancy_bench_wrapper","add_c_test_wrapper")
|
||||
load("@fbcode_macros//build_defs:export_files.bzl", "export_file")
|
||||
|
||||
|
||||
cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
@@ -22,7 +21,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"cache/sharded_cache.cc",
|
||||
"cache/tiered_secondary_cache.cc",
|
||||
"db/arena_wrapped_db_iter.cc",
|
||||
"db/attribute_group_iterator_impl.cc",
|
||||
"db/blob/blob_contents.cc",
|
||||
"db/blob/blob_fetcher.cc",
|
||||
"db/blob/blob_file_addition.cc",
|
||||
@@ -39,7 +37,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"db/blob/prefetch_buffer_collection.cc",
|
||||
"db/builder.cc",
|
||||
"db/c.cc",
|
||||
"db/coalescing_iterator.cc",
|
||||
"db/column_family.cc",
|
||||
"db/compaction/compaction.cc",
|
||||
"db/compaction/compaction_iterator.cc",
|
||||
@@ -61,7 +58,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"db/db_impl/db_impl_debug.cc",
|
||||
"db/db_impl/db_impl_experimental.cc",
|
||||
"db/db_impl/db_impl_files.cc",
|
||||
"db/db_impl/db_impl_follower.cc",
|
||||
"db/db_impl/db_impl_open.cc",
|
||||
"db/db_impl/db_impl_readonly.cc",
|
||||
"db/db_impl/db_impl_secondary.cc",
|
||||
@@ -119,7 +115,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"env/env_posix.cc",
|
||||
"env/file_system.cc",
|
||||
"env/file_system_tracer.cc",
|
||||
"env/fs_on_demand.cc",
|
||||
"env/fs_posix.cc",
|
||||
"env/fs_remap.cc",
|
||||
"env/io_posix.cc",
|
||||
@@ -317,7 +312,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"utilities/persistent_cache/volatile_tier_impl.cc",
|
||||
"utilities/simulator_cache/cache_simulator.cc",
|
||||
"utilities/simulator_cache/sim_cache.cc",
|
||||
"utilities/table_properties_collectors/compact_for_tiering_collector.cc",
|
||||
"utilities/table_properties_collectors/compact_on_deletion_collector.cc",
|
||||
"utilities/trace/file_trace_reader_writer.cc",
|
||||
"utilities/trace/replayer_impl.cc",
|
||||
@@ -351,7 +345,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"utilities/transactions/write_unprepared_txn.cc",
|
||||
"utilities/transactions/write_unprepared_txn_db.cc",
|
||||
"utilities/ttl/db_ttl_impl.cc",
|
||||
"utilities/types_util.cc",
|
||||
"utilities/wal_filter.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index_internal.cc",
|
||||
@@ -395,7 +388,6 @@ rocks_cpp_library_wrapper(name="rocksdb_stress_lib", srcs=[
|
||||
"db_stress_tool/cf_consistency_stress.cc",
|
||||
"db_stress_tool/db_stress_common.cc",
|
||||
"db_stress_tool/db_stress_driver.cc",
|
||||
"db_stress_tool/db_stress_filters.cc",
|
||||
"db_stress_tool/db_stress_gflags.cc",
|
||||
"db_stress_tool/db_stress_listener.cc",
|
||||
"db_stress_tool/db_stress_shared_state.cc",
|
||||
@@ -413,8 +405,6 @@ rocks_cpp_library_wrapper(name="rocksdb_stress_lib", srcs=[
|
||||
], headers=None)
|
||||
|
||||
|
||||
cpp_binary_wrapper(name="ldb", srcs=["tools/ldb.cc"], deps=[":rocksdb_tools_lib"], extra_preprocessor_flags=[], extra_bench_libs=False)
|
||||
|
||||
cpp_binary_wrapper(name="db_stress", srcs=["db_stress_tool/db_stress.cc"], deps=[":rocksdb_stress_lib"], extra_preprocessor_flags=[], extra_bench_libs=False)
|
||||
|
||||
cpp_binary_wrapper(name="cache_bench", srcs=["cache/cache_bench.cc"], deps=[":rocksdb_cache_bench_tools_lib"], extra_preprocessor_flags=[], extra_bench_libs=False)
|
||||
@@ -4628,12 +4618,6 @@ cpp_unittest_wrapper(name="compact_files_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="compact_for_tiering_collector_test",
|
||||
srcs=["utilities/table_properties_collectors/compact_for_tiering_collector_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="compact_on_deletion_collector_test",
|
||||
srcs=["utilities/table_properties_collectors/compact_on_deletion_collector_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
@@ -4808,12 +4792,6 @@ cpp_unittest_wrapper(name="db_flush_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_follower_test",
|
||||
srcs=["db/db_follower_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_inplace_update_test",
|
||||
srcs=["db/db_inplace_update_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
@@ -5248,12 +5226,6 @@ cpp_unittest_wrapper(name="mock_env_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="multi_cf_iterator_test",
|
||||
srcs=["db/multi_cf_iterator_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="object_registry_test",
|
||||
srcs=["utilities/object_registry_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
@@ -5548,12 +5520,6 @@ cpp_unittest_wrapper(name="ttl_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="types_util_test",
|
||||
srcs=["utilities/types_util_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="udt_util_test",
|
||||
srcs=["util/udt_util_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
|
||||
@@ -193,10 +193,6 @@ def generate_targets(repo_path, deps_map):
|
||||
+ src_mk.get("STRESS_LIB_SOURCES", [])
|
||||
+ ["test_util/testutil.cc"],
|
||||
)
|
||||
# ldb binary
|
||||
TARGETS.add_binary(
|
||||
"ldb", ["tools/ldb.cc"], [":rocksdb_tools_lib"]
|
||||
)
|
||||
# db_stress binary
|
||||
TARGETS.add_binary(
|
||||
"db_stress", ["db_stress_tool/db_stress.cc"], [":rocksdb_stress_lib"]
|
||||
|
||||
@@ -7,7 +7,6 @@ rocksdb_target_header_template = """# This file \100generated by:
|
||||
# This file is a Facebook-specific integration for buck builds, so can
|
||||
# only be validated by Facebook employees.
|
||||
load("//rocks/buckifier:defs.bzl", "cpp_library_wrapper","rocks_cpp_library_wrapper","cpp_binary_wrapper","cpp_unittest_wrapper","fancy_bench_wrapper","add_c_test_wrapper")
|
||||
load("@fbcode_macros//build_defs:export_files.bzl", "export_file")
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -163,6 +163,24 @@ case "$TARGET_OS" in
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -latomic"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt -ldl"
|
||||
if test -z "$ROCKSDB_USE_IO_URING"; then
|
||||
ROCKSDB_USE_IO_URING=1
|
||||
fi
|
||||
if test "$ROCKSDB_USE_IO_URING" -ne 0; then
|
||||
# check for liburing
|
||||
$CXX $PLATFORM_CXXFLAGS -x c++ - -luring -o test.o 2>/dev/null <<EOF
|
||||
#include <liburing.h>
|
||||
int main() {
|
||||
struct io_uring ring;
|
||||
io_uring_queue_init(1, &ring, 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -luring"
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_IOURING_PRESENT"
|
||||
fi
|
||||
fi
|
||||
# PORT_FILES=port/linux/linux_specific.cc
|
||||
;;
|
||||
SunOS)
|
||||
@@ -585,7 +603,7 @@ EOF
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lbenchmark"
|
||||
fi
|
||||
fi
|
||||
if test $USE_FOLLY || test $USE_FOLLY_LITE; then
|
||||
if test $USE_FOLLY; then
|
||||
# Test whether libfolly library is installed
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <folly/synchronization/DistributedMutex.h>
|
||||
@@ -596,29 +614,11 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$ROCKSDB_USE_IO_URING"; then
|
||||
ROCKSDB_USE_IO_URING=1
|
||||
fi
|
||||
if [ "$ROCKSDB_USE_IO_URING" -ne 0 -a "$PLATFORM" = OS_LINUX ]; then
|
||||
# check for liburing
|
||||
$CXX $PLATFORM_CXXFLAGS -x c++ - -luring -o test.o 2>/dev/null <<EOF
|
||||
#include <liburing.h>
|
||||
int main() {
|
||||
struct io_uring ring;
|
||||
io_uring_queue_init(1, &ring, 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -luring"
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_IOURING_PRESENT"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# TODO(tec): Fix -Wshorten-64-to-32 errors on FreeBSD and enable the warning.
|
||||
# -Wshorten-64-to-32 breaks compilation on FreeBSD aarch64 and i386
|
||||
if ! { [ "$TARGET_OS" = FreeBSD -o "$TARGET_OS" = OpenBSD ] && [ "$TARGET_ARCHITECTURE" = arm64 -o "$TARGET_ARCHITECTURE" = i386 ]; }; then
|
||||
if ! { [ "$TARGET_OS" = FreeBSD ] && [ "$TARGET_ARCHITECTURE" = arm64 -o "$TARGET_ARCHITECTURE" = i386 ]; }; then
|
||||
# Test whether -Wshorten-64-to-32 is available
|
||||
$CXX $PLATFORM_CXXFLAGS -x c++ - -o test.o -Wshorten-64-to-32 2>/dev/null <<EOF
|
||||
int main() {}
|
||||
@@ -751,11 +751,6 @@ if [ "$USE_FOLLY" ]; then
|
||||
FOLLY_PATH=`cd $FOLLY_DIR && $PYTHON build/fbcode_builder/getdeps.py show-inst-dir folly`
|
||||
fi
|
||||
fi
|
||||
if [ "$USE_FOLLY_LITE" ]; then
|
||||
if [ "$FOLLY_DIR" ]; then
|
||||
BOOST_SOURCE_PATH=`cd $FOLLY_DIR && $PYTHON build/fbcode_builder/getdeps.py show-source-dir boost`
|
||||
fi
|
||||
fi
|
||||
|
||||
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
|
||||
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS"
|
||||
@@ -797,7 +792,6 @@ echo "PROFILING_FLAGS=$PROFILING_FLAGS" >> "$OUTPUT"
|
||||
echo "FIND=$FIND" >> "$OUTPUT"
|
||||
echo "WATCH=$WATCH" >> "$OUTPUT"
|
||||
echo "FOLLY_PATH=$FOLLY_PATH" >> "$OUTPUT"
|
||||
echo "BOOST_SOURCE_PATH=$BOOST_SOURCE_PATH" >> "$OUTPUT"
|
||||
|
||||
# This will enable some related identifiers for the preprocessor
|
||||
if test -n "$JEMALLOC"; then
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
# The file is generated using update_dependencies.sh.
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/62de5a92e5f23c661c3d4b9f322e04eb14e7a5bd/11.x/centos8-native/886b5eb
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/1f6edd1ff15c99c861afc8f3cd69054cd974dd64/15/platform010/72a2ff8
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/fed6e93d87571fb162734c86636119d45a398963/2.34/platform010/f259413
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/31a346126a1f3b64812c362511cb04cc1bd40855/1.1.8/platform010/76ebdda
|
||||
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/0c65c05468b5a38cef1a106a1f526463e120c8dd/1.2.8/platform010/76ebdda
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/e40bde78650fa91b8405a857e3f10bf336633fb0/11.x/centos7-native/886b5eb
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/2043340983c032915adbb6f78903dc855b65aee8/12/platform010/9520e0f
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/c00dcc6a3e4125c7e8b248e9a79c14b78ac9e0ca/11.x/platform010/5684a5a
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/0b9c8e4b060eda62f3bc1c6127bbe1256697569b/2.34/platform010/f259413
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/bc9647f7912b131315827d65cb6189c21f381d05/1.1.3/platform010/76ebdda
|
||||
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/a6f5f3f1d063d2d00cd02fc12f0f05fc3ab3a994/1.2.11/platform010/76ebdda
|
||||
BZIP2_BASE=/mnt/gvfs/third-party2/bzip2/09703139cfc376bd8a82642385a0e97726b28287/1.0.6/platform010/76ebdda
|
||||
LZ4_BASE=/mnt/gvfs/third-party2/lz4/ff23d17b932725cc1734a14896a8b67c518ba169/1.9.4/platform010/76ebdda
|
||||
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/576397d8b1d9cea7306ad1e454d5e55caaa2ff1c/1.4.x/platform010/64091f4
|
||||
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/fecac07861cb829f5e60dbeff0503d3272db73c0/2.2.0/platform010/76ebdda
|
||||
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/0bb3f5756788ce26e2e16a1cb2f2af2c59b51abe/master/platform010/f57cc4a
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/5b602edd46fda54cdd7ea45f77dbe4061206e174/2.0.11/platform010/76ebdda
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/97cac22a149c2e202917e05d44e87e516b68216f/1.4/platform010/5074a48
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/53953ebc4e3eda85ad6fc3e429ba146035e97b90/2018_U5/platform010/76ebdda
|
||||
LZ4_BASE=/mnt/gvfs/third-party2/lz4/60220d6a5bf7722b9cc239a1368c596619b12060/1.9.1/platform010/76ebdda
|
||||
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/50eace8143eaaea9473deae1f3283e0049e05633/1.4.x/platform010/64091f4
|
||||
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/5d27e5919771603da06000a027b12f799e58a4f7/2.2.0/platform010/76ebdda
|
||||
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/b62912d333ef33f9760efa6219dbe3fe6abb3b0e/master/platform010/f57cc4a
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/6b412770957aa3c8a87e5e0dcd8cc2f45f393bc0/2.0.11/platform010/76ebdda
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/52f69816e936e147664ad717eb71a1a0e9dc973a/1.4/platform010/5074a48
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/c9cc192099fa84c0dcd0ffeedd44a373ad6e4925/2018_U5/platform010/76ebdda
|
||||
LIBURING_BASE=/mnt/gvfs/third-party2/liburing/a98e2d137007e3ebf7f33bd6f99c2c56bdaf8488/20210212/platform010/76ebdda
|
||||
BENCHMARK_BASE=/mnt/gvfs/third-party2/benchmark/780c7a0f9cf0967961e69ad08e61cddd85d61821/trunk/platform010/76ebdda
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/624a2f8f6c93c3c1df8aa4a6255d8202631a6c80/fb/platform010/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/39579e8603b48b3540f8b0633f43adf29acccb8b/2.37/centos8-native/da39a3e
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/cd9cc656d49ecb53797ce4d055e49fde29fd57ff/3.19.0/platform010/76ebdda
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/02d9f76aaaba580611cf75e741753c800c7fdc12/fb/platform010/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/938dc3f064ef3a48c0446f5b11d788d50b3eb5ee/2.37/centos7-native/da39a3e
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/429a6b3203eb415f1599bd15183659153129188e/3.15.0/platform010/76ebdda
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/363787fa5cac2a8aa20638909210443278fa138e/5.3.4/platform010/9079c97
|
||||
@@ -113,7 +113,7 @@ CLANG_LIB="$CLANG_BASE/lib"
|
||||
CLANG_SRC="$CLANG_BASE/../../src"
|
||||
|
||||
CLANG_ANALYZER="$CLANG_BIN/clang++"
|
||||
CLANG_SCAN_BUILD="$CLANG_BIN/scan-build
|
||||
CLANG_SCAN_BUILD="$CLANG_SRC/llvm/tools/clang/tools/scan-build/bin/scan-build"
|
||||
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
# gcc
|
||||
|
||||
@@ -110,7 +110,7 @@ CLANG_LIB="$CLANG_BASE/lib"
|
||||
CLANG_SRC="$CLANG_BASE/../../src"
|
||||
|
||||
CLANG_ANALYZER="$CLANG_BIN/clang++"
|
||||
CLANG_SCAN_BUILD="$CLANG_BIN/scan-build"
|
||||
CLANG_SCAN_BUILD="$CLANG_SRC/llvm/clang/tools/scan-build/bin/scan-build"
|
||||
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
# gcc
|
||||
|
||||
@@ -137,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" | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
diffs=$(git diff -U0 "$FORMAT_UPSTREAM_MERGE_BASE" | $CLANG_FORMAT_DIFF -p 1)
|
||||
echo "Checking format of changes not yet in $FORMAT_UPSTREAM..."
|
||||
else
|
||||
# Check the format of uncommitted lines,
|
||||
diffs=$(git diff -U0 HEAD | $CLANG_FORMAT_DIFF -p 1) || true
|
||||
diffs=$(git diff -U0 HEAD | $CLANG_FORMAT_DIFF -p 1)
|
||||
echo "Checking format of uncommitted changes..."
|
||||
fi
|
||||
|
||||
@@ -149,9 +149,6 @@ if [ -z "$diffs" ]
|
||||
then
|
||||
echo "Nothing needs to be reformatted!"
|
||||
exit 0
|
||||
elif [ $? -ne 1 ]; then
|
||||
# CLANG_FORMAT_DIFF will exit on 1 while there is suggested changes.
|
||||
exit $?
|
||||
elif [ $CHECK_ONLY ]
|
||||
then
|
||||
echo "Your change has unformatted code. Please run make format!"
|
||||
|
||||
@@ -1561,7 +1561,7 @@ sub save_stdin_stdout_stderr {
|
||||
::die_bug("Can't dup STDERR: $!");
|
||||
open $Global::original_stdin, "<&", "STDIN" or
|
||||
::die_bug("Can't dup STDIN: $!");
|
||||
$Global::is_terminal = (-t $Global::original_stderr) && !$ENV{'CIRCLECI'}&& !$ENV{'GITHUB_ACTIONS'} && !$ENV{'TRAVIS'};
|
||||
$Global::is_terminal = (-t $Global::original_stderr) && !$ENV{'CIRCLECI'} && !$ENV{'TRAVIS'};
|
||||
}
|
||||
|
||||
sub enough_file_handles {
|
||||
|
||||
@@ -75,8 +75,8 @@ touch "$OUTPUT"
|
||||
echo "Writing dependencies to $OUTPUT"
|
||||
|
||||
# Compilers locations
|
||||
GCC_BASE=`readlink -f $TP2_LATEST/gcc/11.x/centos8-native/*/`
|
||||
CLANG_BASE=`readlink -f $TP2_LATEST/llvm-fb/15/platform010/*/`
|
||||
GCC_BASE=`readlink -f $TP2_LATEST/gcc/11.x/centos7-native/*/`
|
||||
CLANG_BASE=`readlink -f $TP2_LATEST/llvm-fb/12/platform010/*/`
|
||||
|
||||
log_header
|
||||
log_variable GCC_BASE
|
||||
@@ -86,7 +86,7 @@ log_variable CLANG_BASE
|
||||
get_lib_base libgcc 11.x platform010
|
||||
get_lib_base glibc 2.34 platform010
|
||||
get_lib_base snappy LATEST platform010
|
||||
get_lib_base zlib 1.2.8 platform010
|
||||
get_lib_base zlib LATEST platform010
|
||||
get_lib_base bzip2 LATEST platform010
|
||||
get_lib_base lz4 LATEST platform010
|
||||
get_lib_base zstd LATEST platform010
|
||||
@@ -99,7 +99,7 @@ get_lib_base liburing LATEST platform010
|
||||
get_lib_base benchmark LATEST platform010
|
||||
|
||||
get_lib_base kernel-headers fb platform010
|
||||
get_lib_base binutils LATEST centos8-native
|
||||
get_lib_base binutils LATEST centos7-native
|
||||
get_lib_base valgrind LATEST platform010
|
||||
get_lib_base lua 5.3.4 platform010
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -194,7 +194,7 @@ class SharedState {
|
||||
: cv_(&mu_),
|
||||
cache_bench_(cache_bench) {}
|
||||
|
||||
~SharedState() = default;
|
||||
~SharedState() {}
|
||||
|
||||
port::Mutex* GetMutex() { return &mu_; }
|
||||
|
||||
@@ -425,7 +425,7 @@ class CacheBench {
|
||||
}
|
||||
}
|
||||
|
||||
~CacheBench() = default;
|
||||
~CacheBench() {}
|
||||
|
||||
void PopulateCache() {
|
||||
Random64 rnd(FLAGS_seed);
|
||||
|
||||
+1
@@ -129,6 +129,7 @@ TEST_F(CacheReservationManagerTest,
|
||||
|
||||
TEST(CacheReservationManagerIncreaseReservcationOnFullCacheTest,
|
||||
IncreaseCacheReservationOnFullCache) {
|
||||
;
|
||||
constexpr std::size_t kSizeDummyEntry =
|
||||
CacheReservationManagerImpl<CacheEntryRole::kMisc>::GetDummyEntrySize();
|
||||
constexpr std::size_t kSmallCacheCapacity = 4 * kSizeDummyEntry;
|
||||
|
||||
Vendored
+3
-63
@@ -18,7 +18,6 @@
|
||||
#include "cache/lru_cache.h"
|
||||
#include "cache/typed_cache.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "table/block_based/block_cache.h"
|
||||
#include "test_util/secondary_cache_test_util.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/coding.h"
|
||||
@@ -107,7 +106,7 @@ class CacheTest : public testing::Test,
|
||||
type_ = GetParam();
|
||||
}
|
||||
|
||||
~CacheTest() override = default;
|
||||
~CacheTest() override {}
|
||||
|
||||
// These functions encode/decode keys in tests cases that use
|
||||
// int keys.
|
||||
@@ -767,9 +766,7 @@ TEST_P(CacheTest, OverCapacity) {
|
||||
std::string key = EncodeKey(i + 1);
|
||||
auto h = cache.Lookup(key);
|
||||
ASSERT_TRUE(h != nullptr);
|
||||
if (h) {
|
||||
cache.Release(h);
|
||||
}
|
||||
if (h) cache.Release(h);
|
||||
}
|
||||
|
||||
// the cache is over capacity since nothing could be evicted
|
||||
@@ -780,7 +777,7 @@ TEST_P(CacheTest, OverCapacity) {
|
||||
|
||||
if (IsHyperClock()) {
|
||||
// Make sure eviction is triggered.
|
||||
ASSERT_OK(cache.Insert(EncodeKey(-1), nullptr, 1, handles.data()));
|
||||
ASSERT_OK(cache.Insert(EncodeKey(-1), nullptr, 1, &handles[0]));
|
||||
|
||||
// cache is under capacity now since elements were released
|
||||
ASSERT_GE(n, cache.get()->GetUsage());
|
||||
@@ -1018,63 +1015,6 @@ INSTANTIATE_TEST_CASE_P(CacheTestInstance, CacheTest,
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, LRUCacheTest,
|
||||
testing::Values(secondary_cache_test_util::kLRU));
|
||||
|
||||
TEST(MiscBlockCacheTest, UncacheAggressivenessAdvisor) {
|
||||
// Aggressiveness to a sequence of Report() calls (as string of 0s and 1s)
|
||||
// exactly until the first ShouldContinue() == false.
|
||||
const std::vector<std::pair<uint32_t, Slice>> expectedTraces{
|
||||
// Aggressiveness 1 aborts on first unsuccessful erasure.
|
||||
{1, "0"},
|
||||
{1, "11111111111111111111110"},
|
||||
// For sufficient evidence, aggressiveness 2 requires a minimum of two
|
||||
// unsuccessful erasures.
|
||||
{2, "00"},
|
||||
{2, "0110"},
|
||||
{2, "1100"},
|
||||
{2, "011111111111111111111111111111111111111111111111111111111111111100"},
|
||||
{2, "0111111111111111111111111111111111110"},
|
||||
// For sufficient evidence, aggressiveness 3 and higher require a minimum
|
||||
// of three unsuccessful erasures.
|
||||
{3, "000"},
|
||||
{3, "01010"},
|
||||
{3, "111000"},
|
||||
{3, "00111111111111111111111111111111111100"},
|
||||
{3, "00111111111111111111110"},
|
||||
|
||||
{4, "000"},
|
||||
{4, "01010"},
|
||||
{4, "111000"},
|
||||
{4, "001111111111111111111100"},
|
||||
{4, "0011111111111110"},
|
||||
|
||||
{6, "000"},
|
||||
{6, "01010"},
|
||||
{6, "111000"},
|
||||
{6, "00111111111111100"},
|
||||
{6, "0011111110"},
|
||||
|
||||
// 69 -> 50% threshold, now up to minimum of 4
|
||||
{69, "0000"},
|
||||
{69, "010000"},
|
||||
{69, "01010000"},
|
||||
{69, "101010100010101000"},
|
||||
|
||||
// 230 -> 10% threshold, appropriately higher minimum
|
||||
{230, "000000000000"},
|
||||
{230, "0000000000010000000000"},
|
||||
{230, "00000000000100000000010000000000"}};
|
||||
for (const auto& [aggressiveness, t] : expectedTraces) {
|
||||
SCOPED_TRACE("aggressiveness=" + std::to_string(aggressiveness) + " with " +
|
||||
t.ToString());
|
||||
UncacheAggressivenessAdvisor uaa(aggressiveness);
|
||||
for (size_t i = 0; i < t.size(); ++i) {
|
||||
SCOPED_TRACE("i=" + std::to_string(i));
|
||||
ASSERT_TRUE(uaa.ShouldContinue());
|
||||
uaa.Report(t[i] & 1);
|
||||
}
|
||||
ASSERT_FALSE(uaa.ShouldContinue());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Vendored
+4
-4
@@ -560,7 +560,7 @@ void BaseClockTable::TrackAndReleaseEvictedEntry(ClockHandle* h) {
|
||||
took_value_ownership =
|
||||
eviction_callback_(ClockCacheShard<FixedHyperClockTable>::ReverseHash(
|
||||
h->GetHash(), &unhashed, hash_seed_),
|
||||
static_cast<Cache::Handle*>(h),
|
||||
reinterpret_cast<Cache::Handle*>(h),
|
||||
h->meta.LoadRelaxed() & ClockHandle::kHitBitMask);
|
||||
}
|
||||
if (!took_value_ownership) {
|
||||
@@ -1428,19 +1428,19 @@ BaseHyperClockCache<Table>::BaseHyperClockCache(
|
||||
|
||||
template <class Table>
|
||||
Cache::ObjectPtr BaseHyperClockCache<Table>::Value(Handle* handle) {
|
||||
return static_cast<const typename Table::HandleImpl*>(handle)->value;
|
||||
return reinterpret_cast<const typename Table::HandleImpl*>(handle)->value;
|
||||
}
|
||||
|
||||
template <class Table>
|
||||
size_t BaseHyperClockCache<Table>::GetCharge(Handle* handle) const {
|
||||
return static_cast<const typename Table::HandleImpl*>(handle)
|
||||
return reinterpret_cast<const typename Table::HandleImpl*>(handle)
|
||||
->GetTotalCharge();
|
||||
}
|
||||
|
||||
template <class Table>
|
||||
const Cache::CacheItemHelper* BaseHyperClockCache<Table>::GetCacheItemHelper(
|
||||
Handle* handle) const {
|
||||
auto h = static_cast<const typename Table::HandleImpl*>(handle);
|
||||
auto h = reinterpret_cast<const typename Table::HandleImpl*>(handle);
|
||||
return h->helper;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -298,7 +298,7 @@ class ClockCacheTest;
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
struct ClockHandleBasicData : public Cache::Handle {
|
||||
struct ClockHandleBasicData {
|
||||
Cache::ObjectPtr value = nullptr;
|
||||
const Cache::CacheItemHelper* helper = nullptr;
|
||||
// A lossless, reversible hash of the fixed-size (16 byte) cache key. This
|
||||
|
||||
Vendored
+6
-11
@@ -26,7 +26,7 @@ CompressedSecondaryCache::CompressedSecondaryCache(
|
||||
cache_))),
|
||||
disable_cache_(opts.capacity == 0) {}
|
||||
|
||||
CompressedSecondaryCache::~CompressedSecondaryCache() = default;
|
||||
CompressedSecondaryCache::~CompressedSecondaryCache() {}
|
||||
|
||||
std::unique_ptr<SecondaryCacheResultHandle> CompressedSecondaryCache::Lookup(
|
||||
const Slice& key, const Cache::CacheItemHelper* helper,
|
||||
@@ -192,13 +192,13 @@ Status CompressedSecondaryCache::InsertInternal(
|
||||
type == kNoCompression &&
|
||||
!cache_options_.do_not_compress_roles.Contains(helper->role)) {
|
||||
PERF_COUNTER_ADD(compressed_sec_cache_uncompressed_bytes, data_size);
|
||||
CompressionOptions compression_opts;
|
||||
CompressionContext compression_context(cache_options_.compression_type,
|
||||
cache_options_.compression_opts);
|
||||
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);
|
||||
compression_opts, compression_context, CompressionDict::GetEmptyDict(),
|
||||
cache_options_.compression_type, sample_for_compression);
|
||||
|
||||
bool success =
|
||||
CompressData(val, compression_info,
|
||||
@@ -291,11 +291,6 @@ std::string CompressedSecondaryCache::GetPrintableOptions() const {
|
||||
snprintf(buffer, kBufferSize, " compression_type : %s\n",
|
||||
CompressionTypeToString(cache_options_.compression_type).c_str());
|
||||
ret.append(buffer);
|
||||
snprintf(buffer, kBufferSize, " compression_opts : %s\n",
|
||||
CompressionOptionsToString(
|
||||
const_cast<CompressionOptions&>(cache_options_.compression_opts))
|
||||
.c_str());
|
||||
ret.append(buffer);
|
||||
snprintf(buffer, kBufferSize, " compress_format_version : %d\n",
|
||||
cache_options_.compress_format_version);
|
||||
ret.append(buffer);
|
||||
@@ -384,7 +379,7 @@ const Cache::CacheItemHelper* CompressedSecondaryCache::GetHelper(
|
||||
chunks_head = chunks_head->next;
|
||||
tmp_chunk->Free();
|
||||
obj = nullptr;
|
||||
}
|
||||
};
|
||||
}};
|
||||
return &kHelper;
|
||||
} else {
|
||||
|
||||
+6
-6
@@ -33,7 +33,7 @@ const std::string key3 = "____ ____key3";
|
||||
class CompressedSecondaryCacheTestBase : public testing::Test,
|
||||
public WithCacheType {
|
||||
public:
|
||||
CompressedSecondaryCacheTestBase() = default;
|
||||
CompressedSecondaryCacheTestBase() {}
|
||||
~CompressedSecondaryCacheTestBase() override = default;
|
||||
|
||||
protected:
|
||||
@@ -1062,7 +1062,7 @@ bool CacheUsageWithinBounds(size_t val1, size_t val2, size_t error) {
|
||||
|
||||
TEST_P(CompressedSecCacheTestWithTiered, CacheReservationManager) {
|
||||
CompressedSecondaryCache* sec_cache =
|
||||
static_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
reinterpret_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
|
||||
// Use EXPECT_PRED3 instead of EXPECT_NEAR to void too many size_t to
|
||||
// double explicit casts
|
||||
@@ -1085,7 +1085,7 @@ TEST_P(CompressedSecCacheTestWithTiered, CacheReservationManager) {
|
||||
TEST_P(CompressedSecCacheTestWithTiered,
|
||||
CacheReservationManagerMultipleUpdate) {
|
||||
CompressedSecondaryCache* sec_cache =
|
||||
static_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
reinterpret_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
|
||||
EXPECT_PRED3(CacheUsageWithinBounds, GetCache()->GetUsage(), (30 << 20),
|
||||
GetPercent(30 << 20, 1));
|
||||
@@ -1171,7 +1171,7 @@ TEST_P(CompressedSecCacheTestWithTiered, AdmissionPolicy) {
|
||||
|
||||
TEST_P(CompressedSecCacheTestWithTiered, DynamicUpdate) {
|
||||
CompressedSecondaryCache* sec_cache =
|
||||
static_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
reinterpret_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
std::shared_ptr<Cache> tiered_cache = GetTieredCache();
|
||||
|
||||
// Use EXPECT_PRED3 instead of EXPECT_NEAR to void too many size_t to
|
||||
@@ -1235,7 +1235,7 @@ TEST_P(CompressedSecCacheTestWithTiered, DynamicUpdate) {
|
||||
|
||||
TEST_P(CompressedSecCacheTestWithTiered, DynamicUpdateWithReservation) {
|
||||
CompressedSecondaryCache* sec_cache =
|
||||
static_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
reinterpret_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
std::shared_ptr<Cache> tiered_cache = GetTieredCache();
|
||||
|
||||
ASSERT_OK(cache_res_mgr()->UpdateCacheReservation(10 << 20));
|
||||
@@ -1329,7 +1329,7 @@ TEST_P(CompressedSecCacheTestWithTiered, DynamicUpdateWithReservation) {
|
||||
|
||||
TEST_P(CompressedSecCacheTestWithTiered, ReservationOverCapacity) {
|
||||
CompressedSecondaryCache* sec_cache =
|
||||
static_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
reinterpret_cast<CompressedSecondaryCache*>(GetSecondaryCache());
|
||||
std::shared_ptr<Cache> tiered_cache = GetTieredCache();
|
||||
|
||||
ASSERT_OK(cache_res_mgr()->UpdateCacheReservation(110 << 20));
|
||||
|
||||
Vendored
+7
-8
@@ -277,8 +277,8 @@ void LRUCacheShard::LRU_Insert(LRUHandle* e) {
|
||||
e->SetInHighPriPool(false);
|
||||
e->SetInLowPriPool(true);
|
||||
low_pri_pool_usage_ += e->total_charge;
|
||||
lru_low_pri_ = e;
|
||||
MaintainPoolSize();
|
||||
lru_low_pri_ = e;
|
||||
} else {
|
||||
// Insert "e" to the head of bottom-pri pool.
|
||||
e->next = lru_bottom_pri_->next;
|
||||
@@ -301,7 +301,6 @@ void LRUCacheShard::MaintainPoolSize() {
|
||||
// Overflow last entry in high-pri pool to low-pri pool.
|
||||
lru_low_pri_ = lru_low_pri_->next;
|
||||
assert(lru_low_pri_ != &lru_);
|
||||
assert(lru_low_pri_->InHighPriPool());
|
||||
lru_low_pri_->SetInHighPriPool(false);
|
||||
lru_low_pri_->SetInLowPriPool(true);
|
||||
assert(high_pri_pool_usage_ >= lru_low_pri_->total_charge);
|
||||
@@ -313,7 +312,6 @@ void LRUCacheShard::MaintainPoolSize() {
|
||||
// Overflow last entry in low-pri pool to bottom-pri pool.
|
||||
lru_bottom_pri_ = lru_bottom_pri_->next;
|
||||
assert(lru_bottom_pri_ != &lru_);
|
||||
assert(lru_bottom_pri_->InLowPriPool());
|
||||
lru_bottom_pri_->SetInHighPriPool(false);
|
||||
lru_bottom_pri_->SetInLowPriPool(false);
|
||||
assert(low_pri_pool_usage_ >= lru_bottom_pri_->total_charge);
|
||||
@@ -341,7 +339,8 @@ void LRUCacheShard::NotifyEvicted(
|
||||
MemoryAllocator* alloc = table_.GetAllocator();
|
||||
for (LRUHandle* entry : evicted_handles) {
|
||||
if (eviction_callback_ &&
|
||||
eviction_callback_(entry->key(), static_cast<Cache::Handle*>(entry),
|
||||
eviction_callback_(entry->key(),
|
||||
reinterpret_cast<Cache::Handle*>(entry),
|
||||
entry->HasHit())) {
|
||||
// Callback took ownership of obj; just free handle
|
||||
free(entry);
|
||||
@@ -507,7 +506,7 @@ bool LRUCacheShard::Release(LRUHandle* e, bool /*useful*/,
|
||||
// Only call eviction callback if we're sure no one requested erasure
|
||||
// FIXME: disabled because of test churn
|
||||
if (false && was_in_cache && !erase_if_last_ref && eviction_callback_ &&
|
||||
eviction_callback_(e->key(), static_cast<Cache::Handle*>(e),
|
||||
eviction_callback_(e->key(), reinterpret_cast<Cache::Handle*>(e),
|
||||
e->HasHit())) {
|
||||
// Callback took ownership of obj; just free handle
|
||||
free(e);
|
||||
@@ -662,18 +661,18 @@ LRUCache::LRUCache(const LRUCacheOptions& opts) : ShardedCache(opts) {
|
||||
}
|
||||
|
||||
Cache::ObjectPtr LRUCache::Value(Handle* handle) {
|
||||
auto h = static_cast<const LRUHandle*>(handle);
|
||||
auto h = reinterpret_cast<const LRUHandle*>(handle);
|
||||
return h->value;
|
||||
}
|
||||
|
||||
size_t LRUCache::GetCharge(Handle* handle) const {
|
||||
return static_cast<const LRUHandle*>(handle)->GetCharge(
|
||||
return reinterpret_cast<const LRUHandle*>(handle)->GetCharge(
|
||||
GetShard(0).metadata_charge_policy_);
|
||||
}
|
||||
|
||||
const Cache::CacheItemHelper* LRUCache::GetCacheItemHelper(
|
||||
Handle* handle) const {
|
||||
auto h = static_cast<const LRUHandle*>(handle);
|
||||
auto h = reinterpret_cast<const LRUHandle*>(handle);
|
||||
return h->helper;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -47,7 +47,7 @@ namespace lru_cache {
|
||||
// LRUCacheShard::Lookup.
|
||||
// While refs > 0, public properties like value and deleter must not change.
|
||||
|
||||
struct LRUHandle : public Cache::Handle {
|
||||
struct LRUHandle {
|
||||
Cache::ObjectPtr value;
|
||||
const Cache::CacheItemHelper* helper;
|
||||
LRUHandle* next_hash;
|
||||
|
||||
Vendored
+10
-29
@@ -32,7 +32,7 @@ namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class LRUCacheTest : public testing::Test {
|
||||
public:
|
||||
LRUCacheTest() = default;
|
||||
LRUCacheTest() {}
|
||||
~LRUCacheTest() override { DeleteCache(); }
|
||||
|
||||
void DeleteCache() {
|
||||
@@ -47,7 +47,7 @@ class LRUCacheTest : public testing::Test {
|
||||
double low_pri_pool_ratio = 1.0,
|
||||
bool use_adaptive_mutex = kDefaultToAdaptiveMutex) {
|
||||
DeleteCache();
|
||||
cache_ = static_cast<LRUCacheShard*>(
|
||||
cache_ = reinterpret_cast<LRUCacheShard*>(
|
||||
port::cacheline_aligned_alloc(sizeof(LRUCacheShard)));
|
||||
new (cache_) LRUCacheShard(capacity, /*strict_capacity_limit=*/false,
|
||||
high_pri_pool_ratio, low_pri_pool_ratio,
|
||||
@@ -57,11 +57,10 @@ class LRUCacheTest : public testing::Test {
|
||||
}
|
||||
|
||||
void Insert(const std::string& key,
|
||||
Cache::Priority priority = Cache::Priority::LOW,
|
||||
size_t charge = 1) {
|
||||
Cache::Priority priority = Cache::Priority::LOW) {
|
||||
EXPECT_OK(cache_->Insert(key, 0 /*hash*/, nullptr /*value*/,
|
||||
&kNoopCacheItemHelper, charge, nullptr /*handle*/,
|
||||
priority));
|
||||
&kNoopCacheItemHelper, 1 /*charge*/,
|
||||
nullptr /*handle*/, priority));
|
||||
}
|
||||
|
||||
void Insert(char key, Cache::Priority priority = Cache::Priority::LOW) {
|
||||
@@ -145,10 +144,8 @@ class LRUCacheTest : public testing::Test {
|
||||
ASSERT_EQ(num_bottom_pri_pool_keys, bottom_pri_pool_keys);
|
||||
}
|
||||
|
||||
protected:
|
||||
LRUCacheShard* cache_ = nullptr;
|
||||
|
||||
private:
|
||||
LRUCacheShard* cache_ = nullptr;
|
||||
Cache::EvictionCallback eviction_callback_;
|
||||
};
|
||||
|
||||
@@ -381,7 +378,7 @@ class ClockCacheTest : public testing::Test {
|
||||
using Table = typename Shard::Table;
|
||||
using TableOpts = typename Table::Opts;
|
||||
|
||||
ClockCacheTest() = default;
|
||||
ClockCacheTest() {}
|
||||
~ClockCacheTest() override { DeleteShard(); }
|
||||
|
||||
void DeleteShard() {
|
||||
@@ -395,7 +392,8 @@ class ClockCacheTest : public testing::Test {
|
||||
void NewShard(size_t capacity, bool strict_capacity_limit = true,
|
||||
int eviction_effort_cap = 30) {
|
||||
DeleteShard();
|
||||
shard_ = static_cast<Shard*>(port::cacheline_aligned_alloc(sizeof(Shard)));
|
||||
shard_ =
|
||||
reinterpret_cast<Shard*>(port::cacheline_aligned_alloc(sizeof(Shard)));
|
||||
|
||||
TableOpts opts{1 /*value_size*/, eviction_effort_cap};
|
||||
new (shard_)
|
||||
@@ -1979,7 +1977,7 @@ TEST_P(BasicSecondaryCacheTest, BasicWaitAllTest) {
|
||||
ah.priority = Cache::Priority::LOW;
|
||||
cache->StartAsyncLookup(ah);
|
||||
}
|
||||
cache->WaitAll(async_handles.data(), async_handles.size());
|
||||
cache->WaitAll(&async_handles[0], async_handles.size());
|
||||
for (size_t i = 0; i < async_handles.size(); ++i) {
|
||||
SCOPED_TRACE("i = " + std::to_string(i));
|
||||
Cache::Handle* result = async_handles[i].Result();
|
||||
@@ -2706,23 +2704,6 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionTwoDB) {
|
||||
ASSERT_OK(DestroyDB(dbname2, options));
|
||||
}
|
||||
|
||||
TEST_F(LRUCacheTest, InsertAfterReducingCapacity) {
|
||||
// Fix a bug in LRU cache where it may try to remove a low pri entry's
|
||||
// charge from high pri pool. It causes
|
||||
// Assertion failed: (high_pri_pool_usage_ >= lru_low_pri_->total_charge),
|
||||
// function MaintainPoolSize, file lru_cache.cc
|
||||
NewCache(/*capacity=*/10, /*high_pri_pool_ratio=*/0.2,
|
||||
/*low_pri_pool_ratio=*/0.8);
|
||||
// high pri pool size and usage are both 2
|
||||
Insert("x", Cache::Priority::HIGH);
|
||||
Insert("y", Cache::Priority::HIGH);
|
||||
cache_->SetCapacity(5);
|
||||
// high_pri_pool_size is 1, the next time we try to maintain pool size,
|
||||
// we will move entries from high pri pool to low pri pool
|
||||
// The bug was deducting this entry's charge from high pri pool usage.
|
||||
Insert("aaa", Cache::Priority::LOW, /*charge=*/3);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Vendored
+3
-6
@@ -134,14 +134,12 @@ bool CacheWithSecondaryAdapter::EvictionHandler(const Slice& key,
|
||||
auto obj = target_->Value(handle);
|
||||
// Ignore dummy entry
|
||||
if (obj != kDummyObj) {
|
||||
bool force = false;
|
||||
bool hit = false;
|
||||
if (adm_policy_ == TieredAdmissionPolicy::kAdmPolicyAllowCacheHits) {
|
||||
force = was_hit;
|
||||
} else if (adm_policy_ == TieredAdmissionPolicy::kAdmPolicyAllowAll) {
|
||||
force = true;
|
||||
hit = was_hit;
|
||||
}
|
||||
// Spill into secondary cache.
|
||||
secondary_cache_->Insert(key, obj, helper, force).PermitUncheckedError();
|
||||
secondary_cache_->Insert(key, obj, helper, hit).PermitUncheckedError();
|
||||
}
|
||||
}
|
||||
// Never takes ownership of obj
|
||||
@@ -663,7 +661,6 @@ std::shared_ptr<Cache> NewTieredCache(const TieredCacheOptions& _opts) {
|
||||
break;
|
||||
case TieredAdmissionPolicy::kAdmPolicyPlaceholder:
|
||||
case TieredAdmissionPolicy::kAdmPolicyAllowCacheHits:
|
||||
case TieredAdmissionPolicy::kAdmPolicyAllowAll:
|
||||
if (opts.nvm_sec_cache) {
|
||||
valid_adm_policy = false;
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -139,7 +139,7 @@ class ShardedCache : public ShardedCacheBase {
|
||||
|
||||
explicit ShardedCache(const ShardedCacheOptions& opts)
|
||||
: ShardedCacheBase(opts),
|
||||
shards_(static_cast<CacheShard*>(port::cacheline_aligned_alloc(
|
||||
shards_(reinterpret_cast<CacheShard*>(port::cacheline_aligned_alloc(
|
||||
sizeof(CacheShard) * GetNumShards()))),
|
||||
destroy_shards_in_dtor_(false) {}
|
||||
|
||||
@@ -192,7 +192,7 @@ class ShardedCache : public ShardedCacheBase {
|
||||
HashVal hash = CacheShard::ComputeHash(key, hash_seed_);
|
||||
HandleImpl* result = GetShard(hash).CreateStandalone(
|
||||
key, hash, obj, helper, charge, allow_uncharged);
|
||||
return static_cast<Handle*>(result);
|
||||
return reinterpret_cast<Handle*>(result);
|
||||
}
|
||||
|
||||
Handle* Lookup(const Slice& key, const CacheItemHelper* helper = nullptr,
|
||||
@@ -202,7 +202,7 @@ class ShardedCache : public ShardedCacheBase {
|
||||
HashVal hash = CacheShard::ComputeHash(key, hash_seed_);
|
||||
HandleImpl* result = GetShard(hash).Lookup(key, hash, helper,
|
||||
create_context, priority, stats);
|
||||
return static_cast<Handle*>(result);
|
||||
return reinterpret_cast<Handle*>(result);
|
||||
}
|
||||
|
||||
void Erase(const Slice& key) override {
|
||||
@@ -212,11 +212,11 @@ class ShardedCache : public ShardedCacheBase {
|
||||
|
||||
bool Release(Handle* handle, bool useful,
|
||||
bool erase_if_last_ref = false) override {
|
||||
auto h = static_cast<HandleImpl*>(handle);
|
||||
auto h = reinterpret_cast<HandleImpl*>(handle);
|
||||
return GetShard(h->GetHash()).Release(h, useful, erase_if_last_ref);
|
||||
}
|
||||
bool Ref(Handle* handle) override {
|
||||
auto h = static_cast<HandleImpl*>(handle);
|
||||
auto h = reinterpret_cast<HandleImpl*>(handle);
|
||||
return GetShard(h->GetHash()).Ref(h);
|
||||
}
|
||||
bool Release(Handle* handle, bool erase_if_last_ref = false) override {
|
||||
@@ -259,7 +259,7 @@ class ShardedCache : public ShardedCacheBase {
|
||||
} while (remaining_work);
|
||||
}
|
||||
|
||||
void EraseUnRefEntries() override {
|
||||
virtual void EraseUnRefEntries() override {
|
||||
ForEachShard([](CacheShard* cs) { cs->EraseUnRefEntries(); });
|
||||
}
|
||||
|
||||
|
||||
Vendored
+10
-8
@@ -42,25 +42,27 @@ class TieredSecondaryCache : public SecondaryCacheWrapper {
|
||||
|
||||
// This is a no-op as we currently don't allow demotion (i.e
|
||||
// insertion by the upper layer) of evicted blocks.
|
||||
Status Insert(const Slice& /*key*/, Cache::ObjectPtr /*obj*/,
|
||||
const Cache::CacheItemHelper* /*helper*/,
|
||||
bool /*force_insert*/) override {
|
||||
virtual Status Insert(const Slice& /*key*/, Cache::ObjectPtr /*obj*/,
|
||||
const Cache::CacheItemHelper* /*helper*/,
|
||||
bool /*force_insert*/) override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// Warm up the nvm tier directly
|
||||
Status InsertSaved(const Slice& key, const Slice& saved,
|
||||
CompressionType type = CompressionType::kNoCompression,
|
||||
CacheTier source = CacheTier::kVolatileTier) override {
|
||||
virtual Status InsertSaved(
|
||||
const Slice& key, const Slice& saved,
|
||||
CompressionType type = CompressionType::kNoCompression,
|
||||
CacheTier source = CacheTier::kVolatileTier) override {
|
||||
return nvm_sec_cache_->InsertSaved(key, saved, type, source);
|
||||
}
|
||||
|
||||
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
|
||||
virtual std::unique_ptr<SecondaryCacheResultHandle> Lookup(
|
||||
const Slice& key, const Cache::CacheItemHelper* helper,
|
||||
Cache::CreateContext* create_context, bool wait, bool advise_erase,
|
||||
Statistics* stats, bool& kept_in_sec_cache) override;
|
||||
|
||||
void WaitAll(std::vector<SecondaryCacheResultHandle*> handles) override;
|
||||
virtual void WaitAll(
|
||||
std::vector<SecondaryCacheResultHandle*> handles) override;
|
||||
|
||||
private:
|
||||
struct CreateContext : public Cache::CreateContext {
|
||||
|
||||
Vendored
+18
-181
@@ -386,7 +386,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 3u);
|
||||
@@ -400,7 +400,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -414,7 +414,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -428,7 +428,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -442,7 +442,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -456,7 +456,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -470,7 +470,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -484,7 +484,7 @@ TEST_F(DBTieredSecondaryCacheTest, BasicMultiGetTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -528,7 +528,7 @@ TEST_F(DBTieredSecondaryCacheTest, WaitAllTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 3u);
|
||||
@@ -542,7 +542,7 @@ TEST_F(DBTieredSecondaryCacheTest, WaitAllTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -561,7 +561,7 @@ TEST_F(DBTieredSecondaryCacheTest, WaitAllTest) {
|
||||
keys.push_back(Key(36));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 10u);
|
||||
@@ -582,7 +582,7 @@ TEST_F(DBTieredSecondaryCacheTest, WaitAllTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 10u);
|
||||
@@ -629,7 +629,7 @@ TEST_F(DBTieredSecondaryCacheTest, ReadyBeforeWaitAllTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 3u);
|
||||
@@ -644,7 +644,7 @@ TEST_F(DBTieredSecondaryCacheTest, ReadyBeforeWaitAllTest) {
|
||||
keys.push_back(Key(20));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -659,7 +659,7 @@ TEST_F(DBTieredSecondaryCacheTest, ReadyBeforeWaitAllTest) {
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 6u);
|
||||
@@ -676,7 +676,7 @@ TEST_F(DBTieredSecondaryCacheTest, ReadyBeforeWaitAllTest) {
|
||||
keys.push_back(Key(36));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 8u);
|
||||
@@ -691,7 +691,7 @@ TEST_F(DBTieredSecondaryCacheTest, ReadyBeforeWaitAllTest) {
|
||||
keys.push_back(Key(36));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
for (auto value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 8u);
|
||||
@@ -816,174 +816,11 @@ TEST_P(DBTieredAdmPolicyTest, CompressedOnlyTest) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_P(DBTieredAdmPolicyTest, CompressedCacheAdmission) {
|
||||
if (!LZ4_Supported()) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires LZ4 support.");
|
||||
return;
|
||||
}
|
||||
|
||||
BlockBasedTableOptions table_options;
|
||||
// We want a block cache of size 5KB, and a compressed secondary cache of
|
||||
// size 5KB. However, we specify a block cache size of 256KB here in order
|
||||
// to take into account the cache reservation in the block cache on
|
||||
// behalf of the compressed cache. The unit of cache reservation is 256KB.
|
||||
// The effective block cache capacity will be calculated as 256 + 5 = 261KB,
|
||||
// and 256KB will be reserved for the compressed cache, leaving 10KB for
|
||||
// the primary block cache. We only have to worry about this here because
|
||||
// the cache size is so small.
|
||||
table_options.block_cache = NewCache(256 * 1024, 5 * 1024, 0, GetParam());
|
||||
table_options.block_size = 4 * 1024;
|
||||
table_options.cache_index_and_filter_blocks = false;
|
||||
Options options = GetDefaultOptions();
|
||||
options.create_if_missing = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
size_t comp_cache_usage = compressed_secondary_cache()->TEST_GetUsage();
|
||||
// Disable paranoid_file_checks so that flush will not read back the newly
|
||||
// written file
|
||||
options.paranoid_file_checks = false;
|
||||
DestroyAndReopen(options);
|
||||
Random rnd(301);
|
||||
const int N = 256;
|
||||
for (int i = 0; i < N; i++) {
|
||||
std::string p_v;
|
||||
test::CompressibleString(&rnd, 0.5, 1007, &p_v);
|
||||
ASSERT_OK(Put(Key(i), p_v));
|
||||
}
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// The second Get (for 5) will evict the data block loaded by the first
|
||||
// Get, which will be admitted into the compressed secondary cache only
|
||||
// for the kAdmPolicyAllowAll policy
|
||||
std::string v = Get(Key(0));
|
||||
ASSERT_EQ(1007, v.size());
|
||||
|
||||
v = Get(Key(5));
|
||||
ASSERT_EQ(1007, v.size());
|
||||
|
||||
if (GetParam() == TieredAdmissionPolicy::kAdmPolicyAllowAll) {
|
||||
ASSERT_GT(compressed_secondary_cache()->TEST_GetUsage(),
|
||||
comp_cache_usage + 128);
|
||||
} else {
|
||||
ASSERT_LT(compressed_secondary_cache()->TEST_GetUsage(),
|
||||
comp_cache_usage + 128);
|
||||
}
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBTieredSecondaryCacheTest, FSBufferTest) {
|
||||
class WrapFS : public FileSystemWrapper {
|
||||
public:
|
||||
explicit WrapFS(const std::shared_ptr<FileSystem>& _target)
|
||||
: FileSystemWrapper(_target) {}
|
||||
~WrapFS() override {}
|
||||
const char* Name() const override { return "WrapFS"; }
|
||||
|
||||
IOStatus NewRandomAccessFile(const std::string& fname,
|
||||
const FileOptions& opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* result,
|
||||
IODebugContext* dbg) override {
|
||||
class WrappedRandomAccessFile : public FSRandomAccessFileOwnerWrapper {
|
||||
public:
|
||||
explicit WrappedRandomAccessFile(
|
||||
std::unique_ptr<FSRandomAccessFile>& file)
|
||||
: FSRandomAccessFileOwnerWrapper(std::move(file)) {}
|
||||
|
||||
IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
||||
const IOOptions& options,
|
||||
IODebugContext* dbg) override {
|
||||
for (size_t i = 0; i < num_reqs; ++i) {
|
||||
FSReadRequest& req = reqs[i];
|
||||
FSAllocationPtr buffer(new char[req.len], [](void* ptr) {
|
||||
delete[] static_cast<char*>(ptr);
|
||||
});
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<FSRandomAccessFile> file;
|
||||
IOStatus s = target()->NewRandomAccessFile(fname, opts, &file, dbg);
|
||||
EXPECT_OK(s);
|
||||
result->reset(new WrappedRandomAccessFile(file));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void SupportedOps(int64_t& supported_ops) override {
|
||||
supported_ops = 1 << FSSupportedOps::kAsyncIO;
|
||||
supported_ops |= 1 << FSSupportedOps::kFSBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
if (!LZ4_Supported()) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires LZ4 support.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<WrapFS> wrap_fs =
|
||||
std::make_shared<WrapFS>(env_->GetFileSystem());
|
||||
std::unique_ptr<Env> wrap_env(new CompositeEnvWrapper(env_, wrap_fs));
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.block_cache = NewCache(250 * 1024, 20 * 1024, 256 * 1024,
|
||||
TieredAdmissionPolicy::kAdmPolicyAuto,
|
||||
/*ready_before_wait=*/true);
|
||||
table_options.block_size = 4 * 1024;
|
||||
table_options.cache_index_and_filter_blocks = false;
|
||||
Options options = GetDefaultOptions();
|
||||
options.create_if_missing = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
options.statistics = CreateDBStatistics();
|
||||
options.env = wrap_env.get();
|
||||
|
||||
options.paranoid_file_checks = false;
|
||||
DestroyAndReopen(options);
|
||||
Random rnd(301);
|
||||
const int N = 256;
|
||||
for (int i = 0; i < N; i++) {
|
||||
std::string p_v;
|
||||
test::CompressibleString(&rnd, 0.5, 1007, &p_v);
|
||||
ASSERT_OK(Put(Key(i), p_v));
|
||||
}
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
|
||||
keys.push_back(Key(0));
|
||||
keys.push_back(Key(4));
|
||||
keys.push_back(Key(8));
|
||||
values = MultiGet(keys, /*snapshot=*/nullptr, /*async=*/true);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (const auto& value : values) {
|
||||
ASSERT_EQ(1007, value.size());
|
||||
}
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 3u);
|
||||
ASSERT_EQ(nvm_sec_cache()->num_misses(), 3u);
|
||||
ASSERT_EQ(nvm_sec_cache()->num_hits(), 0u);
|
||||
|
||||
std::string v = Get(Key(12));
|
||||
ASSERT_EQ(1007, v.size());
|
||||
ASSERT_EQ(nvm_sec_cache()->num_insert_saved(), 4u);
|
||||
ASSERT_EQ(nvm_sec_cache()->num_misses(), 4u);
|
||||
ASSERT_EQ(options.statistics->getTickerCount(BLOCK_CACHE_MISS), 4u);
|
||||
|
||||
Close();
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DBTieredAdmPolicyTest, DBTieredAdmPolicyTest,
|
||||
::testing::Values(TieredAdmissionPolicy::kAdmPolicyAuto,
|
||||
TieredAdmissionPolicy::kAdmPolicyPlaceholder,
|
||||
TieredAdmissionPolicy::kAdmPolicyAllowCacheHits,
|
||||
TieredAdmissionPolicy::kAdmPolicyAllowAll));
|
||||
TieredAdmissionPolicy::kAdmPolicyAllowCacheHits));
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
||||
Vendored
+4
-3
@@ -155,7 +155,7 @@ class BasicTypedCacheInterface : public BaseCacheInterface<CachePtr>,
|
||||
using BaseCacheInterface<CachePtr>::BaseCacheInterface;
|
||||
struct TypedAsyncLookupHandle : public Cache::AsyncLookupHandle {
|
||||
TypedHandle* Result() {
|
||||
return static_cast<TypedHandle*>(Cache::AsyncLookupHandle::Result());
|
||||
return reinterpret_cast<TypedHandle*>(Cache::AsyncLookupHandle::Result());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -169,7 +169,8 @@ class BasicTypedCacheInterface : public BaseCacheInterface<CachePtr>,
|
||||
}
|
||||
|
||||
inline TypedHandle* Lookup(const Slice& key, Statistics* stats = nullptr) {
|
||||
return static_cast<TypedHandle*>(this->cache_->BasicLookup(key, stats));
|
||||
return reinterpret_cast<TypedHandle*>(
|
||||
this->cache_->BasicLookup(key, stats));
|
||||
}
|
||||
|
||||
inline void StartAsyncLookup(TypedAsyncLookupHandle& async_handle) {
|
||||
@@ -346,7 +347,7 @@ class FullTypedCacheInterface
|
||||
Priority priority = Priority::LOW, Statistics* stats = nullptr,
|
||||
CacheTier lowest_used_cache_tier = CacheTier::kNonVolatileBlockTier) {
|
||||
if (lowest_used_cache_tier > CacheTier::kVolatileTier) {
|
||||
return static_cast<TypedHandle*>(this->cache_->Lookup(
|
||||
return reinterpret_cast<TypedHandle*>(this->cache_->Lookup(
|
||||
key, GetFullHelper(), create_context, priority, stats));
|
||||
} else {
|
||||
return BasicTypedCacheInterface<TValue, kRole, CachePtr>::Lookup(key,
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
# - Find zstd
|
||||
# Find the zstd compression library and includes
|
||||
#
|
||||
# ZSTD_INCLUDE_DIRS - where to find zstd.h, etc.
|
||||
# ZSTD_LIBRARIES - List of libraries when using zstd.
|
||||
# ZSTD_FOUND - True if zstd found.
|
||||
# zstd_INCLUDE_DIRS - where to find zstd.h, etc.
|
||||
# zstd_LIBRARIES - List of libraries when using zstd.
|
||||
# zstd_FOUND - True if zstd found.
|
||||
|
||||
find_path(ZSTD_INCLUDE_DIRS
|
||||
find_path(zstd_INCLUDE_DIRS
|
||||
NAMES zstd.h
|
||||
HINTS ${zstd_ROOT_DIR}/include)
|
||||
|
||||
find_library(ZSTD_LIBRARIES
|
||||
find_library(zstd_LIBRARIES
|
||||
NAMES zstd
|
||||
HINTS ${zstd_ROOT_DIR}/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(zstd DEFAULT_MSG ZSTD_LIBRARIES ZSTD_INCLUDE_DIRS)
|
||||
find_package_handle_standard_args(zstd DEFAULT_MSG zstd_LIBRARIES zstd_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(
|
||||
ZSTD_LIBRARIES
|
||||
ZSTD_INCLUDE_DIRS)
|
||||
zstd_LIBRARIES
|
||||
zstd_INCLUDE_DIRS)
|
||||
|
||||
if(ZSTD_FOUND AND NOT (TARGET zstd::zstd))
|
||||
if(zstd_FOUND AND NOT (TARGET zstd::zstd))
|
||||
add_library (zstd::zstd UNKNOWN IMPORTED)
|
||||
set_target_properties(zstd::zstd
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${ZSTD_LIBRARIES}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${ZSTD_INCLUDE_DIRS})
|
||||
IMPORTED_LOCATION ${zstd_LIBRARIES}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${zstd_INCLUDE_DIRS})
|
||||
endif()
|
||||
+30
-33
@@ -43,13 +43,14 @@ 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 max_sequential_skip_in_iteration,
|
||||
uint64_t version_number, ReadCallback* read_callback,
|
||||
ColumnFamilyHandleImpl* cfh, bool expose_blob_index, bool allow_refresh) {
|
||||
uint64_t version_number, ReadCallback* read_callback, DBImpl* db_impl,
|
||||
ColumnFamilyData* cfd, bool expose_blob_index, bool allow_refresh) {
|
||||
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);
|
||||
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, db_impl, cfd, expose_blob_index);
|
||||
sv_number_ = version_number;
|
||||
read_options_ = read_options;
|
||||
allow_refresh_ = allow_refresh;
|
||||
@@ -64,44 +65,40 @@ void ArenaWrappedDBIter::Init(
|
||||
Status ArenaWrappedDBIter::Refresh() { return Refresh(nullptr); }
|
||||
|
||||
Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
|
||||
if (cfh_ == nullptr || !allow_refresh_) {
|
||||
if (cfd_ == nullptr || db_impl_ == nullptr || !allow_refresh_) {
|
||||
return Status::NotSupported("Creating renew iterator is not allowed.");
|
||||
}
|
||||
assert(db_iter_ != nullptr);
|
||||
auto cfd = cfh_->cfd();
|
||||
auto db_impl = cfh_->db();
|
||||
|
||||
// TODO(yiwu): For last_seq_same_as_publish_seq_==false, this is not the
|
||||
// correct behavior. Will be corrected automatically when we take a snapshot
|
||||
// here for the case of WritePreparedTxnDB.
|
||||
uint64_t cur_sv_number = cfd->GetSuperVersionNumber();
|
||||
uint64_t cur_sv_number = cfd_->GetSuperVersionNumber();
|
||||
// If we recreate a new internal iterator below (NewInternalIterator()),
|
||||
// we will pass in read_options_. We need to make sure it
|
||||
// has the right snapshot.
|
||||
read_options_.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);
|
||||
SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_);
|
||||
assert(sv->version_number >= cur_sv_number);
|
||||
SequenceNumber read_seq = GetSeqNum(db_impl, snapshot);
|
||||
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,
|
||||
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_,
|
||||
sv->version_number, read_callback_, db_impl_, cfd_, expose_blob_index_,
|
||||
allow_refresh_);
|
||||
|
||||
InternalIterator* internal_iter = db_impl->NewInternalIterator(
|
||||
read_options_, cfd, sv, &arena_, read_seq,
|
||||
InternalIterator* internal_iter = db_impl_->NewInternalIterator(
|
||||
read_options_, cfd_, sv, &arena_, read_seq,
|
||||
/* allow_unprepared_value */ true, /* db_iter */ this);
|
||||
SetIterUnderDBIter(internal_iter);
|
||||
};
|
||||
@@ -110,10 +107,10 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
|
||||
reinit_internal_iter();
|
||||
break;
|
||||
} else {
|
||||
SequenceNumber read_seq = GetSeqNum(db_impl, snapshot);
|
||||
SequenceNumber read_seq = GetSeqNum(db_impl_, snapshot);
|
||||
// Refresh range-tombstones in MemTable
|
||||
if (!read_options_.ignore_range_deletions) {
|
||||
SuperVersion* sv = cfd->GetThreadLocalSuperVersion(db_impl);
|
||||
SuperVersion* sv = cfd_->GetThreadLocalSuperVersion(db_impl_);
|
||||
TEST_SYNC_POINT_CALLBACK("ArenaWrappedDBIter::Refresh:SV", nullptr);
|
||||
auto t = sv->mem->NewRangeTombstoneIterator(
|
||||
read_options_, read_seq, false /* immutable_memtable */);
|
||||
@@ -126,28 +123,28 @@ Status ArenaWrappedDBIter::Refresh(const Snapshot* snapshot) {
|
||||
// will be freed during db_iter destruction there.
|
||||
if (memtable_range_tombstone_iter_) {
|
||||
assert(!*memtable_range_tombstone_iter_ ||
|
||||
sv_number_ != cfd->GetSuperVersionNumber());
|
||||
sv_number_ != cfd_->GetSuperVersionNumber());
|
||||
}
|
||||
delete t;
|
||||
} else { // current mutable memtable has range tombstones
|
||||
if (!memtable_range_tombstone_iter_) {
|
||||
delete t;
|
||||
db_impl->ReturnAndCleanupSuperVersion(cfd, sv);
|
||||
db_impl_->ReturnAndCleanupSuperVersion(cfd_, sv);
|
||||
// The memtable under DBIter did not have range tombstone before
|
||||
// refresh.
|
||||
reinit_internal_iter();
|
||||
break;
|
||||
} else {
|
||||
*memtable_range_tombstone_iter_ =
|
||||
std::make_unique<TruncatedRangeDelIterator>(
|
||||
std::unique_ptr<FragmentedRangeTombstoneIterator>(t),
|
||||
&cfd->internal_comparator(), nullptr, nullptr);
|
||||
delete *memtable_range_tombstone_iter_;
|
||||
*memtable_range_tombstone_iter_ = new TruncatedRangeDelIterator(
|
||||
std::unique_ptr<FragmentedRangeTombstoneIterator>(t),
|
||||
&cfd_->internal_comparator(), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
db_impl->ReturnAndCleanupSuperVersion(cfd, sv);
|
||||
db_impl_->ReturnAndCleanupSuperVersion(cfd_, sv);
|
||||
}
|
||||
// Check again if the latest super version number is changed
|
||||
uint64_t latest_sv_number = cfd->GetSuperVersionNumber();
|
||||
uint64_t latest_sv_number = cfd_->GetSuperVersionNumber();
|
||||
if (latest_sv_number != cur_sv_number) {
|
||||
// If the super version number is changed after refreshing,
|
||||
// fallback to Re-Init the InternalIterator
|
||||
@@ -166,14 +163,14 @@ ArenaWrappedDBIter* NewArenaWrappedDbIterator(
|
||||
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) {
|
||||
uint64_t version_number, ReadCallback* read_callback, DBImpl* db_impl,
|
||||
ColumnFamilyData* cfd, 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) {
|
||||
iter->StoreRefreshInfo(cfh, read_callback, expose_blob_index);
|
||||
db_impl, cfd, expose_blob_index, allow_refresh);
|
||||
if (db_impl != nullptr && cfd != nullptr && allow_refresh) {
|
||||
iter->StoreRefreshInfo(db_impl, cfd, read_callback, expose_blob_index);
|
||||
}
|
||||
|
||||
return iter;
|
||||
|
||||
+12
-12
@@ -55,8 +55,7 @@ class ArenaWrappedDBIter : public Iterator {
|
||||
db_iter_->SetIter(iter);
|
||||
}
|
||||
|
||||
void SetMemtableRangetombstoneIter(
|
||||
std::unique_ptr<TruncatedRangeDelIterator>* iter) {
|
||||
void SetMemtableRangetombstoneIter(TruncatedRangeDelIterator** iter) {
|
||||
memtable_range_tombstone_iter_ = iter;
|
||||
}
|
||||
|
||||
@@ -88,14 +87,15 @@ class ArenaWrappedDBIter : public Iterator {
|
||||
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,
|
||||
ReadCallback* read_callback, DBImpl* db_impl, ColumnFamilyData* cfd,
|
||||
bool expose_blob_index, bool allow_refresh);
|
||||
|
||||
// Store some parameters so we can refresh the iterator at a later point
|
||||
// with these same params
|
||||
void StoreRefreshInfo(ColumnFamilyHandleImpl* cfh,
|
||||
void StoreRefreshInfo(DBImpl* db_impl, ColumnFamilyData* cfd,
|
||||
ReadCallback* read_callback, bool expose_blob_index) {
|
||||
cfh_ = cfh;
|
||||
db_impl_ = db_impl;
|
||||
cfd_ = cfd;
|
||||
read_callback_ = read_callback;
|
||||
expose_blob_index_ = expose_blob_index;
|
||||
}
|
||||
@@ -104,25 +104,25 @@ class ArenaWrappedDBIter : public Iterator {
|
||||
DBIter* db_iter_ = nullptr;
|
||||
Arena arena_;
|
||||
uint64_t sv_number_;
|
||||
ColumnFamilyHandleImpl* cfh_ = nullptr;
|
||||
ColumnFamilyData* cfd_ = nullptr;
|
||||
DBImpl* db_impl_ = nullptr;
|
||||
ReadOptions read_options_;
|
||||
ReadCallback* read_callback_;
|
||||
bool expose_blob_index_ = false;
|
||||
bool allow_refresh_ = 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;
|
||||
TruncatedRangeDelIterator** memtable_range_tombstone_iter_ = nullptr;
|
||||
};
|
||||
|
||||
// Generate the arena wrapped iterator class.
|
||||
// `cfh` is used for reneweal. If left null, renewal will not
|
||||
// `db_impl` and `cfd` are used for reneweal. If left null, renewal will not
|
||||
// be supported.
|
||||
ArenaWrappedDBIter* NewArenaWrappedDbIterator(
|
||||
extern ArenaWrappedDBIter* NewArenaWrappedDbIterator(
|
||||
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);
|
||||
DBImpl* db_impl = nullptr, ColumnFamilyData* cfd = nullptr,
|
||||
bool expose_blob_index = false, bool allow_refresh = true);
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/attribute_group_iterator_impl.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
const AttributeGroups kNoAttributeGroups;
|
||||
const IteratorAttributeGroups kNoIteratorAttributeGroups;
|
||||
|
||||
void AttributeGroupIteratorImpl::AddToAttributeGroups(
|
||||
const autovector<MultiCfIteratorInfo>& items) {
|
||||
for (const auto& item : items) {
|
||||
attribute_groups_.emplace_back(item.cfh, &item.iterator->columns());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -1,83 +0,0 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "db/multi_cf_iterator_impl.h"
|
||||
#include "rocksdb/attribute_groups.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class AttributeGroupIteratorImpl : public AttributeGroupIterator {
|
||||
public:
|
||||
AttributeGroupIteratorImpl(
|
||||
const Comparator* comparator,
|
||||
const std::vector<ColumnFamilyHandle*>& column_families,
|
||||
const std::vector<Iterator*>& child_iterators)
|
||||
: impl_(
|
||||
comparator, column_families, child_iterators, [this]() { Reset(); },
|
||||
[this](const autovector<MultiCfIteratorInfo>& items) {
|
||||
AddToAttributeGroups(items);
|
||||
}) {}
|
||||
~AttributeGroupIteratorImpl() override {}
|
||||
|
||||
// No copy allowed
|
||||
AttributeGroupIteratorImpl(const AttributeGroupIteratorImpl&) = delete;
|
||||
AttributeGroupIteratorImpl& operator=(const AttributeGroupIteratorImpl&) =
|
||||
delete;
|
||||
|
||||
bool Valid() const override { return impl_.Valid(); }
|
||||
void SeekToFirst() override { impl_.SeekToFirst(); }
|
||||
void SeekToLast() override { impl_.SeekToLast(); }
|
||||
void Seek(const Slice& target) override { impl_.Seek(target); }
|
||||
void SeekForPrev(const Slice& target) override { impl_.SeekForPrev(target); }
|
||||
void Next() override { impl_.Next(); }
|
||||
void Prev() override { impl_.Prev(); }
|
||||
Slice key() const override { return impl_.key(); }
|
||||
Status status() const override { return impl_.status(); }
|
||||
|
||||
const IteratorAttributeGroups& attribute_groups() const override {
|
||||
assert(Valid());
|
||||
return attribute_groups_;
|
||||
}
|
||||
|
||||
void Reset() { attribute_groups_.clear(); }
|
||||
|
||||
private:
|
||||
MultiCfIteratorImpl impl_;
|
||||
IteratorAttributeGroups attribute_groups_;
|
||||
void AddToAttributeGroups(const autovector<MultiCfIteratorInfo>& items);
|
||||
};
|
||||
|
||||
class EmptyAttributeGroupIterator : public AttributeGroupIterator {
|
||||
public:
|
||||
explicit EmptyAttributeGroupIterator(const Status& s) : status_(s) {}
|
||||
bool Valid() const override { return false; }
|
||||
void Seek(const Slice& /*target*/) override {}
|
||||
void SeekForPrev(const Slice& /*target*/) override {}
|
||||
void SeekToFirst() override {}
|
||||
void SeekToLast() override {}
|
||||
void Next() override { assert(false); }
|
||||
void Prev() override { assert(false); }
|
||||
Slice key() const override {
|
||||
assert(false);
|
||||
return Slice();
|
||||
}
|
||||
Status status() const override { return status_; }
|
||||
|
||||
const IteratorAttributeGroups& attribute_groups() const override {
|
||||
return kNoIteratorAttributeGroups;
|
||||
}
|
||||
|
||||
private:
|
||||
Status status_;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<AttributeGroupIterator> NewAttributeGroupErrorIterator(
|
||||
const Status& status) {
|
||||
return std::make_unique<EmptyAttributeGroupIterator>(status);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -34,9 +34,9 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
VersionSet* versions, FileSystem* fs,
|
||||
const ImmutableOptions* immutable_options,
|
||||
const MutableCFOptions* mutable_cf_options, const FileOptions* file_options,
|
||||
const WriteOptions* write_options, std::string db_id,
|
||||
std::string db_session_id, int job_id, uint32_t column_family_id,
|
||||
const std::string& column_family_name, Env::WriteLifeTimeHint write_hint,
|
||||
std::string db_id, std::string db_session_id, int job_id,
|
||||
uint32_t column_family_id, const std::string& column_family_name,
|
||||
Env::IOPriority io_priority, Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
@@ -44,18 +44,18 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
std::vector<BlobFileAddition>* blob_file_additions)
|
||||
: BlobFileBuilder([versions]() { return versions->NewFileNumber(); }, fs,
|
||||
immutable_options, mutable_cf_options, file_options,
|
||||
write_options, db_id, db_session_id, job_id,
|
||||
column_family_id, column_family_name, write_hint,
|
||||
io_tracer, blob_callback, creation_reason,
|
||||
blob_file_paths, blob_file_additions) {}
|
||||
db_id, db_session_id, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, io_tracer,
|
||||
blob_callback, creation_reason, blob_file_paths,
|
||||
blob_file_additions) {}
|
||||
|
||||
BlobFileBuilder::BlobFileBuilder(
|
||||
std::function<uint64_t()> file_number_generator, FileSystem* fs,
|
||||
const ImmutableOptions* immutable_options,
|
||||
const MutableCFOptions* mutable_cf_options, const FileOptions* file_options,
|
||||
const WriteOptions* write_options, std::string db_id,
|
||||
std::string db_session_id, int job_id, uint32_t column_family_id,
|
||||
const std::string& column_family_name, Env::WriteLifeTimeHint write_hint,
|
||||
std::string db_id, std::string db_session_id, int job_id,
|
||||
uint32_t column_family_id, const std::string& column_family_name,
|
||||
Env::IOPriority io_priority, Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
@@ -69,12 +69,12 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
blob_compression_type_(mutable_cf_options->blob_compression_type),
|
||||
prepopulate_blob_cache_(mutable_cf_options->prepopulate_blob_cache),
|
||||
file_options_(file_options),
|
||||
write_options_(write_options),
|
||||
db_id_(std::move(db_id)),
|
||||
db_session_id_(std::move(db_session_id)),
|
||||
job_id_(job_id),
|
||||
column_family_id_(column_family_id),
|
||||
column_family_name_(column_family_name),
|
||||
io_priority_(io_priority),
|
||||
write_hint_(write_hint),
|
||||
io_tracer_(io_tracer),
|
||||
blob_callback_(blob_callback),
|
||||
@@ -87,7 +87,6 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
assert(fs_);
|
||||
assert(immutable_options_);
|
||||
assert(file_options_);
|
||||
assert(write_options_);
|
||||
assert(blob_file_paths_);
|
||||
assert(blob_file_paths_->empty());
|
||||
assert(blob_file_additions_);
|
||||
@@ -208,14 +207,14 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
blob_file_paths_->emplace_back(std::move(blob_file_path));
|
||||
|
||||
assert(file);
|
||||
file->SetIOPriority(write_options_->rate_limiter_priority);
|
||||
file->SetIOPriority(io_priority_);
|
||||
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(
|
||||
std::move(file), blob_file_paths_->back(), *file_options_,
|
||||
immutable_options_->clock, io_tracer_, statistics,
|
||||
Histograms::BLOB_DB_BLOB_FILE_WRITE_MICROS, immutable_options_->listeners,
|
||||
immutable_options_->listeners,
|
||||
immutable_options_->file_checksum_gen_factory.get(),
|
||||
tmp_set.Contains(FileType::kBlobFile), false));
|
||||
|
||||
@@ -232,7 +231,7 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
expiration_range);
|
||||
|
||||
{
|
||||
Status s = blob_log_writer->WriteHeader(*write_options_, header);
|
||||
Status s = blob_log_writer->WriteHeader(header);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"BlobFileBuilder::OpenBlobFileIfNeeded:WriteHeader", &s);
|
||||
@@ -297,8 +296,7 @@ Status BlobFileBuilder::WriteBlobToFile(const Slice& key, const Slice& blob,
|
||||
|
||||
uint64_t key_offset = 0;
|
||||
|
||||
Status s =
|
||||
writer_->AddRecord(*write_options_, key, blob, &key_offset, blob_offset);
|
||||
Status s = writer_->AddRecord(key, blob, &key_offset, blob_offset);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileBuilder::WriteBlobToFile:AddRecord", &s);
|
||||
|
||||
@@ -323,8 +321,7 @@ Status BlobFileBuilder::CloseBlobFile() {
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
|
||||
Status s = writer_->AppendFooter(*write_options_, footer, &checksum_method,
|
||||
&checksum_value);
|
||||
Status s = writer_->AppendFooter(footer, &checksum_method, &checksum_value);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileBuilder::WriteBlobToFile:AppendFooter", &s);
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "rocksdb/advanced_options.h"
|
||||
#include "rocksdb/compression_type.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
#include "rocksdb/types.h"
|
||||
|
||||
@@ -37,11 +36,11 @@ class BlobFileBuilder {
|
||||
BlobFileBuilder(VersionSet* versions, FileSystem* fs,
|
||||
const ImmutableOptions* immutable_options,
|
||||
const MutableCFOptions* mutable_cf_options,
|
||||
const FileOptions* file_options,
|
||||
const WriteOptions* write_options, std::string db_id,
|
||||
const FileOptions* file_options, std::string db_id,
|
||||
std::string db_session_id, int job_id,
|
||||
uint32_t column_family_id,
|
||||
const std::string& column_family_name,
|
||||
Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
@@ -52,11 +51,11 @@ class BlobFileBuilder {
|
||||
BlobFileBuilder(std::function<uint64_t()> file_number_generator,
|
||||
FileSystem* fs, const ImmutableOptions* immutable_options,
|
||||
const MutableCFOptions* mutable_cf_options,
|
||||
const FileOptions* file_options,
|
||||
const WriteOptions* write_options, std::string db_id,
|
||||
const FileOptions* file_options, std::string db_id,
|
||||
std::string db_session_id, int job_id,
|
||||
uint32_t column_family_id,
|
||||
const std::string& column_family_name,
|
||||
Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
@@ -93,12 +92,12 @@ class BlobFileBuilder {
|
||||
CompressionType blob_compression_type_;
|
||||
PrepopulateBlobCache prepopulate_blob_cache_;
|
||||
const FileOptions* file_options_;
|
||||
const WriteOptions* write_options_;
|
||||
const std::string db_id_;
|
||||
const std::string db_session_id_;
|
||||
int job_id_;
|
||||
uint32_t column_family_id_;
|
||||
std::string column_family_name_;
|
||||
Env::IOPriority io_priority_;
|
||||
Env::WriteLifeTimeHint write_hint_;
|
||||
std::shared_ptr<IOTracer> io_tracer_;
|
||||
BlobFileCompletionCallback* blob_callback_;
|
||||
|
||||
@@ -43,7 +43,6 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
mock_env_.reset(MockEnv::Create(Env::Default()));
|
||||
fs_ = mock_env_->GetFileSystem().get();
|
||||
clock_ = mock_env_->GetSystemClock().get();
|
||||
write_options_.rate_limiter_priority = Env::IO_HIGH;
|
||||
}
|
||||
|
||||
void VerifyBlobFile(uint64_t blob_file_number,
|
||||
@@ -114,7 +113,6 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
FileSystem* fs_;
|
||||
SystemClock* clock_;
|
||||
FileOptions file_options_;
|
||||
WriteOptions write_options_;
|
||||
};
|
||||
|
||||
TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
@@ -138,6 +136,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -145,8 +144,8 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -222,6 +221,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -229,8 +229,8 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -309,6 +309,7 @@ TEST_F(BlobFileBuilderTest, InlinedValues) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -316,8 +317,8 @@ TEST_F(BlobFileBuilderTest, InlinedValues) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -363,6 +364,7 @@ TEST_F(BlobFileBuilderTest, Compression) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -370,8 +372,8 @@ TEST_F(BlobFileBuilderTest, Compression) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -446,6 +448,7 @@ TEST_F(BlobFileBuilderTest, CompressionError) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -453,8 +456,8 @@ TEST_F(BlobFileBuilderTest, CompressionError) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -525,6 +528,7 @@ TEST_F(BlobFileBuilderTest, Checksum) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -532,8 +536,8 @@ TEST_F(BlobFileBuilderTest, Checksum) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -585,13 +589,11 @@ class BlobFileBuilderIOErrorTest
|
||||
BlobFileBuilderIOErrorTest() : sync_point_(GetParam()) {
|
||||
mock_env_.reset(MockEnv::Create(Env::Default()));
|
||||
fs_ = mock_env_->GetFileSystem().get();
|
||||
write_options_.rate_limiter_priority = Env::IO_HIGH;
|
||||
}
|
||||
|
||||
std::unique_ptr<Env> mock_env_;
|
||||
FileSystem* fs_;
|
||||
FileOptions file_options_;
|
||||
WriteOptions write_options_;
|
||||
std::string sync_point_;
|
||||
};
|
||||
|
||||
@@ -624,6 +626,7 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
constexpr int job_id = 1;
|
||||
constexpr uint32_t column_family_id = 123;
|
||||
constexpr char column_family_name[] = "foobar";
|
||||
constexpr Env::IOPriority io_priority = Env::IO_HIGH;
|
||||
constexpr Env::WriteLifeTimeHint write_hint = Env::WLTH_MEDIUM;
|
||||
|
||||
std::vector<std::string> blob_file_paths;
|
||||
@@ -631,8 +634,8 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, &write_options_, "" /*db_id*/, "" /*db_session_id*/,
|
||||
job_id, column_family_id, column_family_name, write_hint,
|
||||
&file_options_, "" /*db_id*/, "" /*db_session_id*/, job_id,
|
||||
column_family_id, column_family_name, io_priority, write_hint,
|
||||
nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ Status BlobFileCache::GetBlobFileReader(
|
||||
assert(blob_file_reader);
|
||||
assert(blob_file_reader->IsEmpty());
|
||||
|
||||
// NOTE: sharing same Cache with table_cache
|
||||
const Slice key = GetSliceForKey(&blob_file_number);
|
||||
|
||||
assert(cache_);
|
||||
@@ -99,13 +98,4 @@ Status BlobFileCache::GetBlobFileReader(
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void BlobFileCache::Evict(uint64_t blob_file_number) {
|
||||
// NOTE: sharing same Cache with table_cache
|
||||
const Slice key = GetSliceForKey(&blob_file_number);
|
||||
|
||||
assert(cache_);
|
||||
|
||||
cache_.get()->Erase(key);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -36,15 +36,6 @@ class BlobFileCache {
|
||||
uint64_t blob_file_number,
|
||||
CacheHandleGuard<BlobFileReader>* blob_file_reader);
|
||||
|
||||
// Called when a blob file is obsolete to ensure it is removed from the cache
|
||||
// to avoid effectively leaking the open file and assicated memory
|
||||
void Evict(uint64_t blob_file_number);
|
||||
|
||||
// Used to identify cache entries for blob files (not normally useful)
|
||||
static const Cache::CacheItemHelper* GetHelper() {
|
||||
return CacheInterface::GetBasicHelper();
|
||||
}
|
||||
|
||||
private:
|
||||
using CacheInterface =
|
||||
BasicTypedCacheInterface<BlobFileReader, CacheEntryRole::kMisc>;
|
||||
|
||||
@@ -57,7 +57,7 @@ void WriteBlobFile(uint32_t column_family_id,
|
||||
BlobLogHeader header(column_family_id, kNoCompression, has_ttl,
|
||||
expiration_range);
|
||||
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(WriteOptions(), header));
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(header));
|
||||
|
||||
constexpr char key[] = "key";
|
||||
constexpr char blob[] = "blob";
|
||||
@@ -67,8 +67,7 @@ void WriteBlobFile(uint32_t column_family_id,
|
||||
uint64_t key_offset = 0;
|
||||
uint64_t blob_offset = 0;
|
||||
|
||||
ASSERT_OK(blob_log_writer.AddRecord(WriteOptions(), key, blob, &key_offset,
|
||||
&blob_offset));
|
||||
ASSERT_OK(blob_log_writer.AddRecord(key, blob, &key_offset, &blob_offset));
|
||||
|
||||
BlobLogFooter footer;
|
||||
footer.blob_count = 1;
|
||||
@@ -77,8 +76,8 @@ void WriteBlobFile(uint32_t column_family_id,
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
|
||||
ASSERT_OK(blob_log_writer.AppendFooter(WriteOptions(), footer,
|
||||
&checksum_method, &checksum_value));
|
||||
ASSERT_OK(
|
||||
blob_log_writer.AppendFooter(footer, &checksum_method, &checksum_value));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@@ -63,7 +63,7 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
BlobLogHeader header(column_family_id, compression, has_ttl,
|
||||
expiration_range_header);
|
||||
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(WriteOptions(), header));
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(header));
|
||||
|
||||
std::vector<std::string> compressed_blobs(num);
|
||||
std::vector<Slice> blobs_to_write(num);
|
||||
@@ -91,8 +91,7 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
uint64_t key_offset = 0;
|
||||
ASSERT_OK(blob_log_writer.AddRecord(WriteOptions(), keys[i],
|
||||
blobs_to_write[i], &key_offset,
|
||||
ASSERT_OK(blob_log_writer.AddRecord(keys[i], blobs_to_write[i], &key_offset,
|
||||
&blob_offsets[i]));
|
||||
}
|
||||
|
||||
@@ -102,8 +101,8 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
ASSERT_OK(blob_log_writer.AppendFooter(WriteOptions(), footer,
|
||||
&checksum_method, &checksum_value));
|
||||
ASSERT_OK(
|
||||
blob_log_writer.AppendFooter(footer, &checksum_method, &checksum_value));
|
||||
}
|
||||
|
||||
// Creates a test blob file with a single blob in it. Note: this method
|
||||
@@ -405,7 +404,7 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
|
||||
requests_buf[0] =
|
||||
BlobReadRequest(key_refs[0], blob_offsets[0], blob_sizes[0],
|
||||
kNoCompression, nullptr, statuses_buf.data());
|
||||
kNoCompression, nullptr, &statuses_buf[0]);
|
||||
requests_buf[1] =
|
||||
BlobReadRequest(key_refs[1], blob_offsets[1], blob_sizes[1] + 1,
|
||||
kNoCompression, nullptr, &statuses_buf[1]);
|
||||
@@ -474,7 +473,7 @@ TEST_F(BlobFileReaderTest, Malformed) {
|
||||
BlobLogHeader header(column_family_id, kNoCompression, has_ttl,
|
||||
expiration_range);
|
||||
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(WriteOptions(), header));
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(header));
|
||||
}
|
||||
|
||||
constexpr HistogramImpl* blob_file_read_hist = nullptr;
|
||||
|
||||
+27
-56
@@ -33,49 +33,35 @@ BlobLogWriter::BlobLogWriter(std::unique_ptr<WritableFileWriter>&& dest,
|
||||
|
||||
BlobLogWriter::~BlobLogWriter() = default;
|
||||
|
||||
Status BlobLogWriter::Sync(const WriteOptions& write_options) {
|
||||
Status BlobLogWriter::Sync() {
|
||||
TEST_SYNC_POINT("BlobLogWriter::Sync");
|
||||
|
||||
StopWatch sync_sw(clock_, statistics_, BLOB_DB_BLOB_FILE_SYNC_MICROS);
|
||||
IOOptions opts;
|
||||
Status s = WritableFileWriter::PrepareIOOptions(write_options, opts);
|
||||
if (s.ok()) {
|
||||
s = dest_->Sync(opts, use_fsync_);
|
||||
}
|
||||
if (s.ok()) {
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_SYNCED);
|
||||
}
|
||||
Status s = dest_->Sync(use_fsync_);
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_SYNCED);
|
||||
return s;
|
||||
}
|
||||
|
||||
Status BlobLogWriter::WriteHeader(const WriteOptions& write_options,
|
||||
BlobLogHeader& header) {
|
||||
Status BlobLogWriter::WriteHeader(BlobLogHeader& header) {
|
||||
assert(block_offset_ == 0);
|
||||
assert(last_elem_type_ == kEtNone);
|
||||
std::string str;
|
||||
header.EncodeTo(&str);
|
||||
|
||||
IOOptions opts;
|
||||
Status s = WritableFileWriter::PrepareIOOptions(write_options, opts);
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(opts, Slice(str));
|
||||
}
|
||||
Status s = dest_->Append(Slice(str));
|
||||
if (s.ok()) {
|
||||
block_offset_ += str.size();
|
||||
if (do_flush_) {
|
||||
s = dest_->Flush(opts);
|
||||
s = dest_->Flush();
|
||||
}
|
||||
}
|
||||
last_elem_type_ = kEtFileHdr;
|
||||
if (s.ok()) {
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogHeader::kSize);
|
||||
}
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogHeader::kSize);
|
||||
return s;
|
||||
}
|
||||
|
||||
Status BlobLogWriter::AppendFooter(const WriteOptions& write_options,
|
||||
BlobLogFooter& footer,
|
||||
Status BlobLogWriter::AppendFooter(BlobLogFooter& footer,
|
||||
std::string* checksum_method,
|
||||
std::string* checksum_value) {
|
||||
assert(block_offset_ != 0);
|
||||
@@ -89,17 +75,14 @@ Status BlobLogWriter::AppendFooter(const WriteOptions& write_options,
|
||||
s.PermitUncheckedError();
|
||||
return Status::IOError("Seen Error. Skip closing.");
|
||||
} else {
|
||||
IOOptions opts;
|
||||
s = WritableFileWriter::PrepareIOOptions(write_options, opts);
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(opts, Slice(str));
|
||||
}
|
||||
s = dest_->Append(Slice(str));
|
||||
if (s.ok()) {
|
||||
block_offset_ += str.size();
|
||||
s = Sync(write_options);
|
||||
|
||||
s = Sync();
|
||||
|
||||
if (s.ok()) {
|
||||
s = dest_->Close(opts);
|
||||
s = dest_->Close();
|
||||
|
||||
if (s.ok()) {
|
||||
assert(!!checksum_method == !!checksum_value);
|
||||
@@ -128,15 +111,12 @@ Status BlobLogWriter::AppendFooter(const WriteOptions& write_options,
|
||||
}
|
||||
|
||||
last_elem_type_ = kEtFileFooter;
|
||||
if (s.ok()) {
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogFooter::kSize);
|
||||
}
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogFooter::kSize);
|
||||
return s;
|
||||
}
|
||||
|
||||
Status BlobLogWriter::AddRecord(const WriteOptions& write_options,
|
||||
const Slice& key, const Slice& val,
|
||||
Status BlobLogWriter::AddRecord(const Slice& key, const Slice& val,
|
||||
uint64_t expiration, uint64_t* key_offset,
|
||||
uint64_t* blob_offset) {
|
||||
assert(block_offset_ != 0);
|
||||
@@ -145,13 +125,11 @@ Status BlobLogWriter::AddRecord(const WriteOptions& write_options,
|
||||
std::string buf;
|
||||
ConstructBlobHeader(&buf, key, val, expiration);
|
||||
|
||||
Status s =
|
||||
EmitPhysicalRecord(write_options, buf, key, val, key_offset, blob_offset);
|
||||
Status s = EmitPhysicalRecord(buf, key, val, key_offset, blob_offset);
|
||||
return s;
|
||||
}
|
||||
|
||||
Status BlobLogWriter::AddRecord(const WriteOptions& write_options,
|
||||
const Slice& key, const Slice& val,
|
||||
Status BlobLogWriter::AddRecord(const Slice& key, const Slice& val,
|
||||
uint64_t* key_offset, uint64_t* blob_offset) {
|
||||
assert(block_offset_ != 0);
|
||||
assert(last_elem_type_ == kEtFileHdr || last_elem_type_ == kEtRecord);
|
||||
@@ -159,8 +137,7 @@ Status BlobLogWriter::AddRecord(const WriteOptions& write_options,
|
||||
std::string buf;
|
||||
ConstructBlobHeader(&buf, key, val, 0);
|
||||
|
||||
Status s =
|
||||
EmitPhysicalRecord(write_options, buf, key, val, key_offset, blob_offset);
|
||||
Status s = EmitPhysicalRecord(buf, key, val, key_offset, blob_offset);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -173,34 +150,28 @@ void BlobLogWriter::ConstructBlobHeader(std::string* buf, const Slice& key,
|
||||
record.EncodeHeaderTo(buf);
|
||||
}
|
||||
|
||||
Status BlobLogWriter::EmitPhysicalRecord(const WriteOptions& write_options,
|
||||
const std::string& headerbuf,
|
||||
Status BlobLogWriter::EmitPhysicalRecord(const std::string& headerbuf,
|
||||
const Slice& key, const Slice& val,
|
||||
uint64_t* key_offset,
|
||||
uint64_t* blob_offset) {
|
||||
IOOptions opts;
|
||||
Status s = WritableFileWriter::PrepareIOOptions(write_options, opts);
|
||||
StopWatch write_sw(clock_, statistics_, BLOB_DB_BLOB_FILE_WRITE_MICROS);
|
||||
Status s = dest_->Append(Slice(headerbuf));
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(opts, Slice(headerbuf));
|
||||
s = dest_->Append(key);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(opts, key);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(opts, val);
|
||||
s = dest_->Append(val);
|
||||
}
|
||||
if (do_flush_ && s.ok()) {
|
||||
s = dest_->Flush(opts);
|
||||
s = dest_->Flush();
|
||||
}
|
||||
|
||||
*key_offset = block_offset_ + BlobLogRecord::kHeaderSize;
|
||||
*blob_offset = *key_offset + key.size();
|
||||
block_offset_ = *blob_offset + val.size();
|
||||
last_elem_type_ = kEtRecord;
|
||||
if (s.ok()) {
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogRecord::kHeaderSize + key.size() + val.size());
|
||||
}
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
BlobLogRecord::kHeaderSize + key.size() + val.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,24 +43,20 @@ class BlobLogWriter {
|
||||
static void ConstructBlobHeader(std::string* buf, const Slice& key,
|
||||
const Slice& val, uint64_t expiration);
|
||||
|
||||
Status AddRecord(const WriteOptions& write_options, const Slice& key,
|
||||
const Slice& val, uint64_t* key_offset,
|
||||
Status AddRecord(const Slice& key, const Slice& val, uint64_t* key_offset,
|
||||
uint64_t* blob_offset);
|
||||
|
||||
Status AddRecord(const WriteOptions& write_options, const Slice& key,
|
||||
const Slice& val, uint64_t expiration, uint64_t* key_offset,
|
||||
uint64_t* blob_offset);
|
||||
Status AddRecord(const Slice& key, const Slice& val, uint64_t expiration,
|
||||
uint64_t* key_offset, uint64_t* blob_offset);
|
||||
|
||||
Status EmitPhysicalRecord(const WriteOptions& write_options,
|
||||
const std::string& headerbuf, const Slice& key,
|
||||
Status EmitPhysicalRecord(const std::string& headerbuf, const Slice& key,
|
||||
const Slice& val, uint64_t* key_offset,
|
||||
uint64_t* blob_offset);
|
||||
|
||||
Status AppendFooter(const WriteOptions& write_options, BlobLogFooter& footer,
|
||||
std::string* checksum_method,
|
||||
Status AppendFooter(BlobLogFooter& footer, std::string* checksum_method,
|
||||
std::string* checksum_value);
|
||||
|
||||
Status WriteHeader(const WriteOptions& write_options, BlobLogHeader& header);
|
||||
Status WriteHeader(BlobLogHeader& header);
|
||||
|
||||
WritableFileWriter* file() { return dest_.get(); }
|
||||
|
||||
@@ -68,7 +64,7 @@ class BlobLogWriter {
|
||||
|
||||
uint64_t get_log_number() const { return log_number_; }
|
||||
|
||||
Status Sync(const WriteOptions& write_options);
|
||||
Status Sync();
|
||||
|
||||
private:
|
||||
std::unique_ptr<WritableFileWriter> dest_;
|
||||
|
||||
+17
-18
@@ -65,7 +65,7 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
BlobLogHeader header(column_family_id, compression, has_ttl,
|
||||
expiration_range_header);
|
||||
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(WriteOptions(), header));
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(header));
|
||||
|
||||
std::vector<std::string> compressed_blobs(num);
|
||||
std::vector<Slice> blobs_to_write(num);
|
||||
@@ -93,8 +93,7 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
uint64_t key_offset = 0;
|
||||
ASSERT_OK(blob_log_writer.AddRecord(WriteOptions(), keys[i],
|
||||
blobs_to_write[i], &key_offset,
|
||||
ASSERT_OK(blob_log_writer.AddRecord(keys[i], blobs_to_write[i], &key_offset,
|
||||
&blob_offsets[i]));
|
||||
}
|
||||
|
||||
@@ -104,8 +103,8 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
ASSERT_OK(blob_log_writer.AppendFooter(WriteOptions(), footer,
|
||||
&checksum_method, &checksum_value));
|
||||
ASSERT_OK(
|
||||
blob_log_writer.AppendFooter(footer, &checksum_method, &checksum_value));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@@ -168,8 +167,8 @@ TEST_F(BlobSourceTest, GetBlobsFromCache) {
|
||||
|
||||
uint64_t file_size = BlobLogHeader::kSize;
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
keys.emplace_back(key_strs[i]);
|
||||
blobs.emplace_back(blob_strs[i]);
|
||||
keys.push_back({key_strs[i]});
|
||||
blobs.push_back({blob_strs[i]});
|
||||
file_size += BlobLogRecord::kHeaderSize + keys[i].size() + blobs[i].size();
|
||||
}
|
||||
file_size += BlobLogFooter::kSize;
|
||||
@@ -482,8 +481,8 @@ TEST_F(BlobSourceTest, GetCompressedBlobs) {
|
||||
std::vector<Slice> blobs;
|
||||
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
keys.emplace_back(key_strs[i]);
|
||||
blobs.emplace_back(blob_strs[i]);
|
||||
keys.push_back({key_strs[i]});
|
||||
blobs.push_back({blob_strs[i]});
|
||||
}
|
||||
|
||||
std::vector<uint64_t> blob_offsets(keys.size());
|
||||
@@ -610,8 +609,8 @@ TEST_F(BlobSourceTest, MultiGetBlobsFromMultiFiles) {
|
||||
uint64_t file_size = BlobLogHeader::kSize;
|
||||
uint64_t blob_value_bytes = 0;
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
keys.emplace_back(key_strs[i]);
|
||||
blobs.emplace_back(blob_strs[i]);
|
||||
keys.push_back({key_strs[i]});
|
||||
blobs.push_back({blob_strs[i]});
|
||||
blob_value_bytes += blobs[i].size();
|
||||
file_size += BlobLogRecord::kHeaderSize + keys[i].size() + blobs[i].size();
|
||||
}
|
||||
@@ -802,8 +801,8 @@ TEST_F(BlobSourceTest, MultiGetBlobsFromCache) {
|
||||
|
||||
uint64_t file_size = BlobLogHeader::kSize;
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
keys.emplace_back(key_strs[i]);
|
||||
blobs.emplace_back(blob_strs[i]);
|
||||
keys.push_back({key_strs[i]});
|
||||
blobs.push_back({blob_strs[i]});
|
||||
file_size += BlobLogRecord::kHeaderSize + keys[i].size() + blobs[i].size();
|
||||
}
|
||||
file_size += BlobLogFooter::kSize;
|
||||
@@ -1164,7 +1163,7 @@ TEST_F(BlobSecondaryCacheTest, GetBlobsFromSecondaryCache) {
|
||||
ASSERT_OK(blob_source.GetBlob(read_options, keys[0], file_number,
|
||||
blob_offsets[0], file_size, blob_sizes[0],
|
||||
kNoCompression, nullptr /* prefetch_buffer */,
|
||||
values.data(), nullptr /* bytes_read */));
|
||||
&values[0], nullptr /* bytes_read */));
|
||||
// Release cache handle
|
||||
values[0].Reset();
|
||||
|
||||
@@ -1183,7 +1182,7 @@ TEST_F(BlobSecondaryCacheTest, GetBlobsFromSecondaryCache) {
|
||||
ASSERT_OK(blob_source.GetBlob(read_options, keys[0], file_number,
|
||||
blob_offsets[0], file_size, blob_sizes[0],
|
||||
kNoCompression, nullptr /* prefetch_buffer */,
|
||||
values.data(), nullptr /* bytes_read */));
|
||||
&values[0], nullptr /* bytes_read */));
|
||||
ASSERT_EQ(values[0], blobs[0]);
|
||||
ASSERT_TRUE(
|
||||
blob_source.TEST_BlobInCache(file_number, file_size, blob_offsets[0]));
|
||||
@@ -1263,7 +1262,7 @@ TEST_F(BlobSecondaryCacheTest, GetBlobsFromSecondaryCache) {
|
||||
ASSERT_OK(blob_source.GetBlob(
|
||||
read_options, keys[0], file_number, blob_offsets[0], file_size,
|
||||
blob_sizes[0], kNoCompression, nullptr /* prefetch_buffer */,
|
||||
values.data(), nullptr /* bytes_read */));
|
||||
&values[0], nullptr /* bytes_read */));
|
||||
ASSERT_EQ(values[0], blobs[0]);
|
||||
|
||||
// Release cache handle
|
||||
@@ -1365,8 +1364,8 @@ class BlobSourceCacheReservationTest : public DBTestBase {
|
||||
|
||||
blob_file_size_ = BlobLogHeader::kSize;
|
||||
for (size_t i = 0; i < kNumBlobs; ++i) {
|
||||
keys_.emplace_back(key_strs_[i]);
|
||||
blobs_.emplace_back(blob_strs_[i]);
|
||||
keys_.push_back({key_strs_[i]});
|
||||
blobs_.push_back({blob_strs_[i]});
|
||||
blob_file_size_ +=
|
||||
BlobLogRecord::kHeaderSize + keys_[i].size() + blobs_[i].size();
|
||||
}
|
||||
|
||||
+31
-106
@@ -418,8 +418,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobs) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -441,8 +441,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobs) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -512,8 +512,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromCache) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -534,8 +534,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromCache) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -553,8 +553,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromCache) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -574,8 +574,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromCache) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -758,8 +758,8 @@ TEST_F(DBBlobBasicTest, MultiGetWithDirectIO) {
|
||||
//
|
||||
// [offset=0, len=12288]
|
||||
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
@@ -829,8 +829,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromMultipleFiles) {
|
||||
{
|
||||
std::array<PinnableSlice, kNumKeys> values;
|
||||
std::array<Status, kNumKeys> statuses;
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
for (size_t i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
@@ -843,8 +843,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromMultipleFiles) {
|
||||
{
|
||||
std::array<PinnableSlice, kNumKeys> values;
|
||||
std::array<Status, kNumKeys> statuses;
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
for (size_t i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_TRUE(statuses[i].IsIncomplete());
|
||||
@@ -858,8 +858,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromMultipleFiles) {
|
||||
{
|
||||
std::array<PinnableSlice, kNumKeys> values;
|
||||
std::array<Status, kNumKeys> statuses;
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
for (size_t i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
@@ -872,8 +872,8 @@ TEST_F(DBBlobBasicTest, MultiGetBlobsFromMultipleFiles) {
|
||||
{
|
||||
std::array<PinnableSlice, kNumKeys> values;
|
||||
std::array<Status, kNumKeys> statuses;
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), kNumKeys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
for (size_t i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
@@ -1182,30 +1182,6 @@ TEST_F(DBBlobBasicTest, GetMergeBlobWithPut) {
|
||||
ASSERT_EQ(Get("Key1"), "v1,v2,v3");
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, GetMergeBlobFromMemoryTier) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put(Key(0), "v1"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Merge(Key(0), "v2"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Regular `Get()` loads data block to cache.
|
||||
std::string value;
|
||||
ASSERT_OK(db_->Get(ReadOptions(), Key(0), &value));
|
||||
ASSERT_EQ("v1,v2", value);
|
||||
|
||||
// Base value blob is still uncached, so an in-memory read will fail.
|
||||
ReadOptions read_options;
|
||||
read_options.read_tier = kBlockCacheTier;
|
||||
ASSERT_TRUE(db_->Get(read_options, Key(0), &value).IsIncomplete());
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, MultiGetMergeBlobWithPut) {
|
||||
constexpr size_t num_keys = 3;
|
||||
|
||||
@@ -1230,8 +1206,8 @@ TEST_F(DBBlobBasicTest, MultiGetMergeBlobWithPut) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], "v0_0,v0_1,v0_2");
|
||||
@@ -1494,8 +1470,8 @@ TEST_P(DBBlobBasicIOErrorMultiGetTest, MultiGetBlobs_IOError) {
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
@@ -1551,57 +1527,6 @@ TEST_P(DBBlobBasicIOErrorMultiGetTest, MultipleBlobFiles) {
|
||||
ASSERT_TRUE(statuses[1].IsIOError());
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, MultiGetFindTable_IOError) {
|
||||
// Repro test for a specific bug where `MultiGet()` would fail to open a table
|
||||
// in `FindTable()` and then proceed to return raw blob handles for the other
|
||||
// keys.
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
// Force no table cache so every read will preload the SST file.
|
||||
dbfull()->TEST_table_cache()->SetCapacity(0);
|
||||
|
||||
constexpr size_t num_keys = 2;
|
||||
|
||||
constexpr char key1[] = "key1";
|
||||
constexpr char value1[] = "blob1";
|
||||
|
||||
ASSERT_OK(Put(key1, value1));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr char key2[] = "key2";
|
||||
constexpr char value2[] = "blob2";
|
||||
|
||||
ASSERT_OK(Put(key2, value2));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::atomic<int> num_files_opened = 0;
|
||||
// This test would be more realistic if we injected an `IOError` from the
|
||||
// `FileSystem`
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"TableCache::MultiGet:FindTable", [&](void* status) {
|
||||
num_files_opened++;
|
||||
if (num_files_opened == 2) {
|
||||
Status* s = static_cast<Status*>(status);
|
||||
*s = Status::IOError();
|
||||
}
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::array<Slice, num_keys> keys{{key1, key2}};
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
|
||||
ASSERT_TRUE(statuses[0].IsIOError());
|
||||
ASSERT_OK(statuses[1]);
|
||||
ASSERT_EQ(value2, values[1]);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ReadBlobCompactionFilter : public CompactionFilter {
|
||||
@@ -1895,7 +1820,7 @@ TEST_F(DBBlobBasicTest, GetEntityBlob) {
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGetEntity(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), results.data(), statuses.data());
|
||||
&keys[0], &results[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(results[0].columns(), expected_columns);
|
||||
@@ -1992,8 +1917,8 @@ TEST_F(DBBlobWithTimestampTest, MultiGetBlobs) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
db_->MultiGet(read_options, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_value);
|
||||
@@ -2076,8 +2001,8 @@ TEST_F(DBBlobWithTimestampTest, MultiGetMergeBlobWithPut) {
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
db_->MultiGet(read_opts, db_->DefaultColumnFamily(), num_keys, keys.data(),
|
||||
values.data(), statuses.data());
|
||||
db_->MultiGet(read_opts, db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], "v0_0,v0_1,v0_2");
|
||||
|
||||
@@ -45,10 +45,10 @@ class DBBlobIndexTest : public DBTestBase {
|
||||
DBBlobIndexTest() : DBTestBase("db_blob_index_test", /*env_do_fsync=*/true) {}
|
||||
|
||||
ColumnFamilyHandle* cfh() { return dbfull()->DefaultColumnFamily(); }
|
||||
ColumnFamilyHandleImpl* cfh_impl() {
|
||||
return static_cast_with_check<ColumnFamilyHandleImpl>(cfh());
|
||||
|
||||
ColumnFamilyData* cfd() {
|
||||
return static_cast_with_check<ColumnFamilyHandleImpl>(cfh())->cfd();
|
||||
}
|
||||
ColumnFamilyData* cfd() { return cfh_impl()->cfd(); }
|
||||
|
||||
Status PutBlobIndex(WriteBatch* batch, const Slice& key,
|
||||
const Slice& blob_index) {
|
||||
@@ -96,9 +96,11 @@ class DBBlobIndexTest : public DBTestBase {
|
||||
}
|
||||
|
||||
ArenaWrappedDBIter* GetBlobIterator() {
|
||||
ColumnFamilyData* column_family = cfd();
|
||||
DBImpl* db_impl = dbfull();
|
||||
return db_impl->NewIteratorImpl(
|
||||
ReadOptions(), cfh_impl(), cfd()->GetReferencedSuperVersion(db_impl),
|
||||
ReadOptions(), column_family,
|
||||
column_family->GetReferencedSuperVersion(db_impl),
|
||||
db_impl->GetLatestSequenceNumber(), nullptr /*read_callback*/,
|
||||
true /*expose_blob_index*/);
|
||||
}
|
||||
@@ -323,7 +325,8 @@ TEST_F(DBBlobIndexTest, Iterate) {
|
||||
|
||||
auto check_is_blob = [&](bool is_blob) {
|
||||
return [is_blob](Iterator* iterator) {
|
||||
ASSERT_EQ(is_blob, static_cast<ArenaWrappedDBIter*>(iterator)->IsBlob());
|
||||
ASSERT_EQ(is_blob,
|
||||
reinterpret_cast<ArenaWrappedDBIter*>(iterator)->IsBlob());
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@ FilePrefetchBuffer* PrefetchBufferCollection::GetOrCreatePrefetchBuffer(
|
||||
uint64_t file_number) {
|
||||
auto& prefetch_buffer = prefetch_buffers_[file_number];
|
||||
if (!prefetch_buffer) {
|
||||
ReadaheadParams readahead_params;
|
||||
readahead_params.initial_readahead_size = readahead_size_;
|
||||
readahead_params.max_readahead_size = readahead_size_;
|
||||
prefetch_buffer.reset(new FilePrefetchBuffer(readahead_params));
|
||||
prefetch_buffer.reset(
|
||||
new FilePrefetchBuffer(readahead_size_, readahead_size_));
|
||||
}
|
||||
|
||||
return prefetch_buffer.get();
|
||||
|
||||
+46
-91
@@ -32,11 +32,9 @@
|
||||
#include "options/options_helper.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/file_system.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "seqno_to_time_mapping.h"
|
||||
#include "table/block_based/block_based_table_builder.h"
|
||||
#include "table/format.h"
|
||||
#include "table/internal_iterator.h"
|
||||
@@ -59,20 +57,21 @@ TableBuilder* NewTableBuilder(const TableBuilderOptions& tboptions,
|
||||
Status BuildTable(
|
||||
const std::string& dbname, VersionSet* versions,
|
||||
const ImmutableDBOptions& db_options, const TableBuilderOptions& tboptions,
|
||||
const FileOptions& file_options, TableCache* table_cache,
|
||||
InternalIterator* iter,
|
||||
const FileOptions& file_options, const ReadOptions& read_options,
|
||||
TableCache* table_cache, InternalIterator* iter,
|
||||
std::vector<std::unique_ptr<FragmentedRangeTombstoneIterator>>
|
||||
range_del_iters,
|
||||
FileMetaData* meta, std::vector<BlobFileAddition>* blob_file_additions,
|
||||
std::vector<SequenceNumber> snapshots, SequenceNumber earliest_snapshot,
|
||||
std::vector<SequenceNumber> snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
SequenceNumber job_snapshot, SnapshotChecker* snapshot_checker,
|
||||
bool paranoid_file_checks, InternalStats* internal_stats,
|
||||
IOStatus* io_status, const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCreationReason blob_creation_reason,
|
||||
UnownedPtr<const SeqnoToTimeMapping> seqno_to_time_mapping,
|
||||
EventLogger* event_logger, int job_id, TableProperties* table_properties,
|
||||
Env::WriteLifeTimeHint write_hint, const std::string* full_history_ts_low,
|
||||
const SeqnoToTimeMapping& seqno_to_time_mapping, EventLogger* event_logger,
|
||||
int job_id, const Env::IOPriority io_priority,
|
||||
TableProperties* table_properties, Env::WriteLifeTimeHint write_hint,
|
||||
const std::string* full_history_ts_low,
|
||||
BlobFileCompletionCallback* blob_callback, Version* version,
|
||||
uint64_t* num_input_entries, uint64_t* memtable_payload_bytes,
|
||||
uint64_t* memtable_garbage_bytes) {
|
||||
@@ -83,8 +82,11 @@ Status BuildTable(
|
||||
auto& ioptions = tboptions.ioptions;
|
||||
// Reports the IOStats for flush for every following bytes.
|
||||
const size_t kReportFlushIOStatsEvery = 1048576;
|
||||
OutputValidator output_validator(tboptions.internal_comparator,
|
||||
/*enable_hash=*/paranoid_file_checks);
|
||||
OutputValidator output_validator(
|
||||
tboptions.internal_comparator,
|
||||
/*enable_order_check=*/
|
||||
mutable_cf_options.check_flush_compaction_key_order,
|
||||
/*enable_hash=*/paranoid_file_checks);
|
||||
Status s;
|
||||
meta->fd.file_size = 0;
|
||||
iter->SeekToFirst();
|
||||
@@ -162,11 +164,11 @@ Status BuildTable(
|
||||
|
||||
table_file_created = true;
|
||||
FileTypeSet tmp_set = ioptions.checksum_handoff_file_types;
|
||||
file->SetIOPriority(tboptions.write_options.rate_limiter_priority);
|
||||
file->SetIOPriority(io_priority);
|
||||
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,
|
||||
ioptions.stats, ioptions.listeners,
|
||||
ioptions.file_checksum_gen_factory.get(),
|
||||
tmp_set.Contains(FileType::kTableFile), false));
|
||||
|
||||
@@ -186,16 +188,15 @@ Status BuildTable(
|
||||
blob_file_additions)
|
||||
? new BlobFileBuilder(
|
||||
versions, fs, &ioptions, &mutable_cf_options, &file_options,
|
||||
&(tboptions.write_options), tboptions.db_id,
|
||||
tboptions.db_session_id, job_id, tboptions.column_family_id,
|
||||
tboptions.column_family_name, write_hint, io_tracer,
|
||||
blob_callback, blob_creation_reason, &blob_file_paths,
|
||||
blob_file_additions)
|
||||
tboptions.db_id, tboptions.db_session_id, job_id,
|
||||
tboptions.column_family_id, tboptions.column_family_name,
|
||||
io_priority, write_hint, io_tracer, blob_callback,
|
||||
blob_creation_reason, &blob_file_paths, blob_file_additions)
|
||||
: nullptr);
|
||||
|
||||
const std::atomic<bool> kManualCompactionCanceledFalse{false};
|
||||
CompactionIterator c_iter(
|
||||
iter, ucmp, &merge, kMaxSequenceNumber, &snapshots, earliest_snapshot,
|
||||
iter, ucmp, &merge, kMaxSequenceNumber, &snapshots,
|
||||
earliest_write_conflict_snapshot, job_snapshot, snapshot_checker, env,
|
||||
ShouldReportDetailedTime(env, ioptions.stats),
|
||||
true /* internal key corruption is not ok */, range_del_agg.get(),
|
||||
@@ -207,74 +208,43 @@ Status BuildTable(
|
||||
/*shutting_down=*/nullptr, db_options.info_log, full_history_ts_low);
|
||||
|
||||
const size_t ts_sz = ucmp->timestamp_size();
|
||||
const bool logical_strip_timestamp =
|
||||
const bool strip_timestamp =
|
||||
ts_sz > 0 && !ioptions.persist_user_defined_timestamps;
|
||||
|
||||
SequenceNumber smallest_preferred_seqno = kMaxSequenceNumber;
|
||||
std::string key_after_flush_buf;
|
||||
std::string value_buf;
|
||||
c_iter.SeekToFirst();
|
||||
for (; c_iter.Valid(); c_iter.Next()) {
|
||||
const Slice& key = c_iter.key();
|
||||
const Slice& value = c_iter.value();
|
||||
ParsedInternalKey ikey = c_iter.ikey();
|
||||
key_after_flush_buf.assign(key.data(), key.size());
|
||||
Slice key_after_flush = key_after_flush_buf;
|
||||
Slice value_after_flush = value;
|
||||
|
||||
const ParsedInternalKey& ikey = c_iter.ikey();
|
||||
Slice key_after_flush = key;
|
||||
// If user defined timestamps will be stripped from user key after flush,
|
||||
// the in memory version of the key act logically the same as one with a
|
||||
// minimum timestamp. We update the timestamp here so file boundary and
|
||||
// output validator, block builder all see the effect of the stripping.
|
||||
if (logical_strip_timestamp) {
|
||||
if (strip_timestamp) {
|
||||
key_after_flush_buf.clear();
|
||||
ReplaceInternalKeyWithMinTimestamp(&key_after_flush_buf, key, ts_sz);
|
||||
key_after_flush = key_after_flush_buf;
|
||||
}
|
||||
|
||||
if (ikey.type == kTypeValuePreferredSeqno) {
|
||||
auto [unpacked_value, unix_write_time] =
|
||||
ParsePackedValueWithWriteTime(value);
|
||||
SequenceNumber preferred_seqno =
|
||||
seqno_to_time_mapping
|
||||
? seqno_to_time_mapping->GetProximalSeqnoBeforeTime(
|
||||
unix_write_time)
|
||||
: kMaxSequenceNumber;
|
||||
if (preferred_seqno < ikey.sequence) {
|
||||
value_after_flush =
|
||||
PackValueAndSeqno(unpacked_value, preferred_seqno, &value_buf);
|
||||
smallest_preferred_seqno =
|
||||
std::min(smallest_preferred_seqno, preferred_seqno);
|
||||
} else {
|
||||
// Cannot get a useful preferred seqno, convert it to a kTypeValue.
|
||||
UpdateInternalKey(&key_after_flush_buf, ikey.sequence, kTypeValue);
|
||||
ikey = ParsedInternalKey(ikey.user_key, ikey.sequence, kTypeValue);
|
||||
key_after_flush = key_after_flush_buf;
|
||||
value_after_flush = ParsePackedValueForValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a rolling 64-bit hash of the key and values
|
||||
// Note :
|
||||
// Here "key" integrates 'sequence_number'+'kType'+'user key'.
|
||||
s = output_validator.Add(key_after_flush, value_after_flush);
|
||||
s = output_validator.Add(key_after_flush, value);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
builder->Add(key_after_flush, value_after_flush);
|
||||
builder->Add(key_after_flush, value);
|
||||
|
||||
s = meta->UpdateBoundaries(key_after_flush, value_after_flush,
|
||||
ikey.sequence, ikey.type);
|
||||
s = meta->UpdateBoundaries(key_after_flush, value, ikey.sequence,
|
||||
ikey.type);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(noetzli): Update stats after flush, too.
|
||||
// TODO(hx235): Replace `rate_limiter_priority` with `io_activity` for
|
||||
// flush IO in repair when we have an `Env::IOActivity` enum for it
|
||||
if ((tboptions.write_options.io_activity == Env::IOActivity::kFlush ||
|
||||
tboptions.write_options.io_activity == Env::IOActivity::kDBOpen ||
|
||||
tboptions.write_options.rate_limiter_priority == Env::IO_HIGH) &&
|
||||
if (io_priority == Env::IO_HIGH &&
|
||||
IOSTATS(bytes_written) >= kReportFlushIOStatsEvery) {
|
||||
ThreadStatusUtil::SetThreadOperationProperty(
|
||||
ThreadStatus::FLUSH_BYTES_WRITTEN, IOSTATS(bytes_written));
|
||||
@@ -291,12 +261,9 @@ Status BuildTable(
|
||||
Slice last_tombstone_start_user_key{};
|
||||
for (range_del_it->SeekToFirst(); range_del_it->Valid();
|
||||
range_del_it->Next()) {
|
||||
// When user timestamp should not be persisted, we logically strip a
|
||||
// range tombstone's start and end key's timestamp (replace it with min
|
||||
// timestamp) before passing them along to table builder and to update
|
||||
// file boundaries.
|
||||
auto tombstone = range_del_it->Tombstone(logical_strip_timestamp);
|
||||
std::pair<InternalKey, Slice> kv = tombstone.Serialize();
|
||||
auto tombstone = range_del_it->Tombstone();
|
||||
auto kv = tombstone.Serialize();
|
||||
// TODO(yuzhangyu): handle range deletion for UDT in memtables only.
|
||||
builder->Add(kv.first.Encode(), kv.second);
|
||||
InternalKey tombstone_end = tombstone.SerializeEndKey();
|
||||
meta->UpdateBoundariesForRange(kv.first, tombstone_end, tombstone.seq_,
|
||||
@@ -308,7 +275,7 @@ Status BuildTable(
|
||||
SizeApproximationOptions approx_opts;
|
||||
approx_opts.files_size_error_margin = 0.1;
|
||||
meta->compensated_range_deletion_size += versions->ApproximateSize(
|
||||
approx_opts, tboptions.read_options, version, kv.first.Encode(),
|
||||
approx_opts, read_options, version, kv.first.Encode(),
|
||||
tombstone_end.Encode(), 0 /* start_level */, -1 /* end_level */,
|
||||
TableReaderCaller::kFlush);
|
||||
}
|
||||
@@ -327,17 +294,12 @@ Status BuildTable(
|
||||
if (!s.ok() || empty) {
|
||||
builder->Abandon();
|
||||
} else {
|
||||
SeqnoToTimeMapping relevant_mapping;
|
||||
if (seqno_to_time_mapping) {
|
||||
relevant_mapping.CopyFromSeqnoRange(
|
||||
*seqno_to_time_mapping,
|
||||
std::min(meta->fd.smallest_seqno, smallest_preferred_seqno),
|
||||
meta->fd.largest_seqno);
|
||||
relevant_mapping.SetCapacity(kMaxSeqnoTimePairsPerSST);
|
||||
relevant_mapping.Enforce(tboptions.file_creation_time);
|
||||
}
|
||||
std::string seqno_to_time_mapping_str;
|
||||
seqno_to_time_mapping.Encode(
|
||||
seqno_to_time_mapping_str, meta->fd.smallest_seqno,
|
||||
meta->fd.largest_seqno, meta->file_creation_time);
|
||||
builder->SetSeqnoTimeTableProperties(
|
||||
relevant_mapping,
|
||||
seqno_to_time_mapping_str,
|
||||
ioptions.compaction_style == CompactionStyle::kCompactionStyleFIFO
|
||||
? meta->file_creation_time
|
||||
: meta->oldest_ancester_time);
|
||||
@@ -384,16 +346,13 @@ Status BuildTable(
|
||||
|
||||
// Finish and check for file errors
|
||||
TEST_SYNC_POINT("BuildTable:BeforeSyncTable");
|
||||
IOOptions opts;
|
||||
*io_status =
|
||||
WritableFileWriter::PrepareIOOptions(tboptions.write_options, opts);
|
||||
if (s.ok() && io_status->ok() && !empty) {
|
||||
if (s.ok() && !empty) {
|
||||
StopWatch sw(ioptions.clock, ioptions.stats, TABLE_SYNC_MICROS);
|
||||
*io_status = file_writer->Sync(opts, ioptions.use_fsync);
|
||||
*io_status = file_writer->Sync(ioptions.use_fsync);
|
||||
}
|
||||
TEST_SYNC_POINT("BuildTable:BeforeCloseTableFile");
|
||||
if (s.ok() && io_status->ok() && !empty) {
|
||||
*io_status = file_writer->Close(opts);
|
||||
*io_status = file_writer->Close();
|
||||
}
|
||||
if (s.ok() && io_status->ok() && !empty) {
|
||||
// Add the checksum information to file metadata.
|
||||
@@ -437,9 +396,9 @@ Status BuildTable(
|
||||
// No matter whether use_direct_io_for_flush_and_compaction is true,
|
||||
// the goal is to cache it here for further user reads.
|
||||
std::unique_ptr<InternalIterator> it(table_cache->NewIterator(
|
||||
tboptions.read_options, file_options, tboptions.internal_comparator,
|
||||
*meta, nullptr /* range_del_agg */,
|
||||
mutable_cf_options.prefix_extractor, nullptr,
|
||||
read_options, file_options, tboptions.internal_comparator, *meta,
|
||||
nullptr /* range_del_agg */, mutable_cf_options.prefix_extractor,
|
||||
nullptr,
|
||||
(internal_stats == nullptr) ? nullptr
|
||||
: internal_stats->GetFileReadHist(0),
|
||||
TableReaderCaller::kFlush, /*arena=*/nullptr,
|
||||
@@ -452,6 +411,7 @@ Status BuildTable(
|
||||
s = it->status();
|
||||
if (s.ok() && paranoid_file_checks) {
|
||||
OutputValidator file_validator(tboptions.internal_comparator,
|
||||
/*enable_order_check=*/true,
|
||||
/*enable_hash=*/true);
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
// Generate a rolling 64-bit hash of the key and values
|
||||
@@ -476,13 +436,8 @@ Status BuildTable(
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
|
||||
if (table_file_created) {
|
||||
IOOptions opts;
|
||||
Status prepare =
|
||||
WritableFileWriter::PrepareIOOptions(tboptions.write_options, opts);
|
||||
if (prepare.ok()) {
|
||||
Status ignored = fs->DeleteFile(fname, opts, dbg);
|
||||
ignored.PermitUncheckedError();
|
||||
}
|
||||
Status ignored = fs->DeleteFile(fname, IOOptions(), dbg);
|
||||
ignored.PermitUncheckedError();
|
||||
}
|
||||
|
||||
assert(blob_file_additions || blob_file_paths.empty());
|
||||
|
||||
+7
-5
@@ -23,6 +23,7 @@
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/table_properties.h"
|
||||
#include "rocksdb/types.h"
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -49,22 +50,23 @@ 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.
|
||||
Status BuildTable(
|
||||
extern Status BuildTable(
|
||||
const std::string& dbname, VersionSet* versions,
|
||||
const ImmutableDBOptions& db_options, const TableBuilderOptions& tboptions,
|
||||
const FileOptions& file_options, TableCache* table_cache,
|
||||
InternalIterator* iter,
|
||||
const FileOptions& file_options, const ReadOptions& read_options,
|
||||
TableCache* table_cache, InternalIterator* iter,
|
||||
std::vector<std::unique_ptr<FragmentedRangeTombstoneIterator>>
|
||||
range_del_iters,
|
||||
FileMetaData* meta, std::vector<BlobFileAddition>* blob_file_additions,
|
||||
std::vector<SequenceNumber> snapshots, SequenceNumber earliest_snapshot,
|
||||
std::vector<SequenceNumber> snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
SequenceNumber job_snapshot, SnapshotChecker* snapshot_checker,
|
||||
bool paranoid_file_checks, InternalStats* internal_stats,
|
||||
IOStatus* io_status, const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCreationReason blob_creation_reason,
|
||||
UnownedPtr<const SeqnoToTimeMapping> seqno_to_time_mapping,
|
||||
const SeqnoToTimeMapping& seqno_to_time_mapping,
|
||||
EventLogger* event_logger = nullptr, int job_id = 0,
|
||||
const Env::IOPriority io_priority = Env::IO_HIGH,
|
||||
TableProperties* table_properties = nullptr,
|
||||
Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET,
|
||||
const std::string* full_history_ts_low = nullptr,
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include "rocksdb/utilities/write_batch_with_index.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "rocksdb/write_buffer_manager.h"
|
||||
#include "util/stderr_logger.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
using ROCKSDB_NAMESPACE::BackupEngine;
|
||||
@@ -116,7 +115,6 @@ using ROCKSDB_NAMESPACE::Snapshot;
|
||||
using ROCKSDB_NAMESPACE::SstFileMetaData;
|
||||
using ROCKSDB_NAMESPACE::SstFileWriter;
|
||||
using ROCKSDB_NAMESPACE::Status;
|
||||
using ROCKSDB_NAMESPACE::StderrLogger;
|
||||
using ROCKSDB_NAMESPACE::TablePropertiesCollectorFactory;
|
||||
using ROCKSDB_NAMESPACE::Transaction;
|
||||
using ROCKSDB_NAMESPACE::TransactionDB;
|
||||
@@ -231,7 +229,6 @@ struct rocksdb_livefiles_t {
|
||||
};
|
||||
struct rocksdb_column_family_handle_t {
|
||||
ColumnFamilyHandle* rep;
|
||||
bool immortal; /* only true for default cf */
|
||||
};
|
||||
struct rocksdb_column_family_metadata_t {
|
||||
ColumnFamilyMetaData rep;
|
||||
@@ -447,7 +444,7 @@ struct rocksdb_mergeoperator_t : public MergeOperator {
|
||||
size_t new_value_len;
|
||||
char* tmp_new_value = (*full_merge_)(
|
||||
state_, merge_in.key.data(), merge_in.key.size(), existing_value_data,
|
||||
existing_value_len, operand_pointers.data(), operand_sizes.data(),
|
||||
existing_value_len, &operand_pointers[0], &operand_sizes[0],
|
||||
static_cast<int>(n), &success, &new_value_len);
|
||||
merge_out->new_value.assign(tmp_new_value, new_value_len);
|
||||
|
||||
@@ -476,9 +473,8 @@ struct rocksdb_mergeoperator_t : public MergeOperator {
|
||||
unsigned char success;
|
||||
size_t new_value_len;
|
||||
char* tmp_new_value = (*partial_merge_)(
|
||||
state_, key.data(), key.size(), operand_pointers.data(),
|
||||
operand_sizes.data(), static_cast<int>(operand_count), &success,
|
||||
&new_value_len);
|
||||
state_, key.data(), key.size(), &operand_pointers[0], &operand_sizes[0],
|
||||
static_cast<int>(operand_count), &success, &new_value_len);
|
||||
new_value->assign(tmp_new_value, new_value_len);
|
||||
|
||||
if (delete_value_ != nullptr) {
|
||||
@@ -532,42 +528,6 @@ struct rocksdb_universal_compaction_options_t {
|
||||
ROCKSDB_NAMESPACE::CompactionOptionsUniversal* rep;
|
||||
};
|
||||
|
||||
struct rocksdb_callback_logger_t : public Logger {
|
||||
static const ssize_t STACK_BUFSZ = 512;
|
||||
rocksdb_callback_logger_t(InfoLogLevel log_level,
|
||||
void (*logv_cb)(void*, unsigned, char*, size_t),
|
||||
void* priv)
|
||||
: Logger(log_level), logv_cb_(logv_cb), priv_(priv) {}
|
||||
|
||||
using Logger::Logv;
|
||||
void Logv(const InfoLogLevel level, const char* fmt, va_list ap0) override {
|
||||
char stack_buf[STACK_BUFSZ];
|
||||
char* alloc_buf = nullptr;
|
||||
char* buf = stack_buf;
|
||||
int len = 0;
|
||||
va_list ap1;
|
||||
if (!logv_cb_) return;
|
||||
va_copy(ap1, ap0);
|
||||
len = vsnprintf(buf, STACK_BUFSZ, fmt, ap0);
|
||||
if (len <= 0)
|
||||
goto cleanup;
|
||||
else if (len >= STACK_BUFSZ) {
|
||||
buf = alloc_buf = reinterpret_cast<char*>(malloc(len + 1));
|
||||
if (!buf) goto cleanup;
|
||||
len = vsnprintf(buf, len + 1, fmt, ap1);
|
||||
if (len <= 0) goto cleanup;
|
||||
}
|
||||
logv_cb_(priv_, unsigned(level), buf, size_t(len));
|
||||
cleanup:
|
||||
va_end(ap1);
|
||||
free(alloc_buf);
|
||||
}
|
||||
|
||||
private:
|
||||
void (*logv_cb_)(void*, unsigned, char*, size_t) = nullptr;
|
||||
void* priv_ = nullptr;
|
||||
};
|
||||
|
||||
static bool SaveError(char** errptr, const Status& s) {
|
||||
assert(errptr != nullptr);
|
||||
if (s.ok()) {
|
||||
@@ -583,7 +543,6 @@ static bool SaveError(char** errptr, const Status& s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copies str to a new malloc()-ed buffer. The buffer is not NUL terminated.
|
||||
static char* CopyString(const std::string& str) {
|
||||
char* result = reinterpret_cast<char*>(malloc(sizeof(char) * str.size()));
|
||||
memcpy(result, str.data(), sizeof(char) * str.size());
|
||||
@@ -925,9 +884,9 @@ rocksdb_t* rocksdb_open_and_trim_history(
|
||||
size_t trim_tslen, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
std::string trim_ts_(trim_ts, trim_tslen);
|
||||
@@ -944,7 +903,6 @@ rocksdb_t* rocksdb_open_and_trim_history(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -959,9 +917,9 @@ rocksdb_t* rocksdb_open_column_families(
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
DB* db;
|
||||
@@ -975,7 +933,6 @@ rocksdb_t* rocksdb_open_column_families(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -994,9 +951,9 @@ rocksdb_t* rocksdb_open_column_families_with_ttl(
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
ttls_vec.push_back(ttls[i]);
|
||||
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
ROCKSDB_NAMESPACE::DBWithTTL* db;
|
||||
@@ -1011,7 +968,6 @@ rocksdb_t* rocksdb_open_column_families_with_ttl(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -1027,9 +983,9 @@ rocksdb_t* rocksdb_open_for_read_only_column_families(
|
||||
unsigned char error_if_wal_file_exists, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
DB* db;
|
||||
@@ -1045,7 +1001,6 @@ rocksdb_t* rocksdb_open_for_read_only_column_families(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -1077,7 +1032,6 @@ rocksdb_t* rocksdb_open_as_secondary_column_families(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -1115,7 +1069,6 @@ rocksdb_column_family_handle_t* rocksdb_create_column_family(
|
||||
SaveError(errptr, db->rep->CreateColumnFamily(
|
||||
ColumnFamilyOptions(column_family_options->rep),
|
||||
std::string(column_family_name), &(handle->rep)));
|
||||
handle->immortal = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -1126,7 +1079,7 @@ rocksdb_column_family_handle_t** rocksdb_create_column_families(
|
||||
std::vector<ColumnFamilyHandle*> handles;
|
||||
std::vector<std::string> names;
|
||||
for (int i = 0; i != num_column_families; ++i) {
|
||||
names.emplace_back(column_family_names[i]);
|
||||
names.push_back(std::string(column_family_names[i]));
|
||||
}
|
||||
SaveError(errptr, db->rep->CreateColumnFamilies(
|
||||
ColumnFamilyOptions(column_family_options->rep), names,
|
||||
@@ -1139,7 +1092,6 @@ rocksdb_column_family_handle_t** rocksdb_create_column_families(
|
||||
for (size_t i = 0; i != handles.size(); ++i) {
|
||||
c_handles[i] = new rocksdb_column_family_handle_t;
|
||||
c_handles[i]->rep = handles[i];
|
||||
c_handles[i]->immortal = false;
|
||||
}
|
||||
|
||||
return c_handles;
|
||||
@@ -1159,7 +1111,6 @@ rocksdb_column_family_handle_t* rocksdb_create_column_family_with_ttl(
|
||||
SaveError(errptr, db_with_ttl->CreateColumnFamilyWithTtl(
|
||||
ColumnFamilyOptions(column_family_options->rep),
|
||||
std::string(column_family_name), &(handle->rep), ttl));
|
||||
handle->immortal = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -1181,19 +1132,9 @@ char* rocksdb_column_family_handle_get_name(
|
||||
return CopyString(name);
|
||||
}
|
||||
|
||||
rocksdb_column_family_handle_t* rocksdb_get_default_column_family_handle(
|
||||
rocksdb_t* db) {
|
||||
rocksdb_column_family_handle_t* handle = new rocksdb_column_family_handle_t;
|
||||
handle->rep = db->rep->DefaultColumnFamily();
|
||||
handle->immortal = true;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void rocksdb_column_family_handle_destroy(
|
||||
rocksdb_column_family_handle_t* handle) {
|
||||
if (!handle->immortal) {
|
||||
delete handle->rep;
|
||||
}
|
||||
delete handle->rep;
|
||||
delete handle;
|
||||
}
|
||||
|
||||
@@ -1429,18 +1370,6 @@ char* rocksdb_get_cf_with_ts(rocksdb_t* db,
|
||||
return result;
|
||||
}
|
||||
|
||||
char* rocksdb_get_db_identity(rocksdb_t* db, size_t* id_len) {
|
||||
std::string identity_tmp;
|
||||
Status s = db->rep->GetDbIdentity(identity_tmp);
|
||||
if (!s.ok()) {
|
||||
*id_len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*id_len = identity_tmp.size();
|
||||
return CopyString(identity_tmp);
|
||||
}
|
||||
|
||||
void rocksdb_multi_get(rocksdb_t* db, const rocksdb_readoptions_t* options,
|
||||
size_t num_keys, const char* const* keys_list,
|
||||
const size_t* keys_list_sizes, char** values_list,
|
||||
@@ -1756,11 +1685,6 @@ void rocksdb_release_snapshot(rocksdb_t* db,
|
||||
delete snapshot;
|
||||
}
|
||||
|
||||
uint64_t rocksdb_snapshot_get_sequence_number(
|
||||
const rocksdb_snapshot_t* snapshot) {
|
||||
return snapshot->rep->GetSequenceNumber();
|
||||
}
|
||||
|
||||
char* rocksdb_property_value(rocksdb_t* db, const char* propname) {
|
||||
std::string tmp;
|
||||
if (db->rep->GetProperty(Slice(propname), &tmp)) {
|
||||
@@ -1838,26 +1762,6 @@ void rocksdb_approximate_sizes_cf(
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_approximate_sizes_cf_with_flags(
|
||||
rocksdb_t* db, rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges, const char* const* range_start_key,
|
||||
const size_t* range_start_key_len, const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len, uint8_t include_flags, uint64_t* sizes,
|
||||
char** errptr) {
|
||||
Range* ranges = new Range[num_ranges];
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
|
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
|
||||
}
|
||||
Status s = db->rep->GetApproximateSizes(
|
||||
column_family->rep, ranges, num_ranges, sizes,
|
||||
static_cast<DB::SizeApproximationFlags>(include_flags));
|
||||
if (!s.ok()) {
|
||||
SaveError(errptr, s);
|
||||
}
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
void rocksdb_delete_file(rocksdb_t* db, const char* name) {
|
||||
db->rep->DeleteFile(name);
|
||||
}
|
||||
@@ -1968,8 +1872,9 @@ void rocksdb_disable_file_deletions(rocksdb_t* db, char** errptr) {
|
||||
SaveError(errptr, db->rep->DisableFileDeletions());
|
||||
}
|
||||
|
||||
void rocksdb_enable_file_deletions(rocksdb_t* db, char** errptr) {
|
||||
SaveError(errptr, db->rep->EnableFileDeletions());
|
||||
void rocksdb_enable_file_deletions(rocksdb_t* db, unsigned char force,
|
||||
char** errptr) {
|
||||
SaveError(errptr, db->rep->EnableFileDeletions(force));
|
||||
}
|
||||
|
||||
void rocksdb_destroy_db(const rocksdb_options_t* options, const char* name,
|
||||
@@ -2035,10 +1940,6 @@ void rocksdb_iter_get_error(const rocksdb_iterator_t* iter, char** errptr) {
|
||||
SaveError(errptr, iter->rep->status());
|
||||
}
|
||||
|
||||
void rocksdb_iter_refresh(const rocksdb_iterator_t* iter, char** errptr) {
|
||||
SaveError(errptr, iter->rep->Refresh());
|
||||
}
|
||||
|
||||
rocksdb_writebatch_t* rocksdb_writebatch_create() {
|
||||
return new rocksdb_writebatch_t;
|
||||
}
|
||||
@@ -2050,15 +1951,6 @@ rocksdb_writebatch_t* rocksdb_writebatch_create_from(const char* rep,
|
||||
return b;
|
||||
}
|
||||
|
||||
rocksdb_writebatch_t* rocksdb_writebatch_create_with_params(
|
||||
size_t reserved_bytes, size_t max_bytes, size_t protection_bytes_per_key,
|
||||
size_t default_cf_ts_sz) {
|
||||
rocksdb_writebatch_t* b = new rocksdb_writebatch_t;
|
||||
b->rep = WriteBatch(reserved_bytes, max_bytes, protection_bytes_per_key,
|
||||
default_cf_ts_sz);
|
||||
return b;
|
||||
}
|
||||
|
||||
void rocksdb_writebatch_destroy(rocksdb_writebatch_t* b) { delete b; }
|
||||
|
||||
void rocksdb_writebatch_clear(rocksdb_writebatch_t* b) { b->rep.Clear(); }
|
||||
@@ -2286,32 +2178,6 @@ class H : public WriteBatch::Handler {
|
||||
}
|
||||
};
|
||||
|
||||
class HCF : public WriteBatch::Handler {
|
||||
public:
|
||||
void* state_;
|
||||
void (*put_cf_)(void*, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen);
|
||||
void (*deleted_cf_)(void*, uint32_t cfid, const char* k, size_t klen);
|
||||
void (*merge_cf_)(void*, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen);
|
||||
Status PutCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value) override {
|
||||
(*put_cf_)(state_, column_family_id, key.data(), key.size(), value.data(),
|
||||
value.size());
|
||||
return Status::OK();
|
||||
}
|
||||
Status DeleteCF(uint32_t column_family_id, const Slice& key) override {
|
||||
(*deleted_cf_)(state_, column_family_id, key.data(), key.size());
|
||||
return Status::OK();
|
||||
}
|
||||
Status MergeCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value) override {
|
||||
(*merge_cf_)(state_, column_family_id, key.data(), key.size(), value.data(),
|
||||
value.size());
|
||||
return Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
void rocksdb_writebatch_iterate(rocksdb_writebatch_t* b, void* state,
|
||||
void (*put)(void*, const char* k, size_t klen,
|
||||
const char* v, size_t vlen),
|
||||
@@ -2324,21 +2190,6 @@ void rocksdb_writebatch_iterate(rocksdb_writebatch_t* b, void* state,
|
||||
b->rep.Iterate(&handler);
|
||||
}
|
||||
|
||||
void rocksdb_writebatch_iterate_cf(
|
||||
rocksdb_writebatch_t* b, void* state,
|
||||
void (*put_cf)(void*, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen),
|
||||
void (*deleted_cf)(void*, uint32_t cfid, const char* k, size_t klen),
|
||||
void (*merge_cf)(void*, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen)) {
|
||||
HCF handler;
|
||||
handler.state_ = state;
|
||||
handler.put_cf_ = put_cf;
|
||||
handler.deleted_cf_ = deleted_cf;
|
||||
handler.merge_cf_ = merge_cf;
|
||||
b->rep.Iterate(&handler);
|
||||
}
|
||||
|
||||
const char* rocksdb_writebatch_data(rocksdb_writebatch_t* b, size_t* size) {
|
||||
*size = b->rep.GetDataSize();
|
||||
return b->rep.Data().c_str();
|
||||
@@ -2365,35 +2216,6 @@ rocksdb_writebatch_wi_t* rocksdb_writebatch_wi_create(
|
||||
return b;
|
||||
}
|
||||
|
||||
rocksdb_writebatch_wi_t* rocksdb_writebatch_wi_create_with_params(
|
||||
rocksdb_comparator_t* backup_index_comparator, size_t reserved_bytes,
|
||||
unsigned char overwrite_key, size_t max_bytes,
|
||||
size_t protection_bytes_per_key) {
|
||||
rocksdb_writebatch_wi_t* b = new rocksdb_writebatch_wi_t;
|
||||
b->rep = new WriteBatchWithIndex(backup_index_comparator, reserved_bytes,
|
||||
overwrite_key, max_bytes,
|
||||
protection_bytes_per_key);
|
||||
return b;
|
||||
}
|
||||
|
||||
void rocksdb_writebatch_update_timestamps(
|
||||
rocksdb_writebatch_t* wb, const char* ts, size_t tslen, void* state,
|
||||
size_t (*get_ts_size)(void*, uint32_t), char** errptr) {
|
||||
SaveError(errptr, wb->rep.UpdateTimestamps(
|
||||
Slice(ts, tslen), [&get_ts_size, &state](uint32_t cf) {
|
||||
return (*get_ts_size)(state, cf);
|
||||
}));
|
||||
}
|
||||
|
||||
void rocksdb_writebatch_wi_update_timestamps(
|
||||
rocksdb_writebatch_wi_t* wb, const char* ts, size_t tslen, void* state,
|
||||
size_t (*get_ts_size)(void*, uint32_t), char** errptr) {
|
||||
SaveError(errptr, wb->rep->GetWriteBatch()->UpdateTimestamps(
|
||||
Slice(ts, tslen), [&get_ts_size, &state](uint32_t cf) {
|
||||
return (*get_ts_size)(state, cf);
|
||||
}));
|
||||
}
|
||||
|
||||
void rocksdb_writebatch_wi_destroy(rocksdb_writebatch_wi_t* b) {
|
||||
if (b->rep) {
|
||||
delete b->rep;
|
||||
@@ -2916,24 +2738,6 @@ void rocksdb_options_set_block_based_table_factory(
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_top_level_index_pinning_tier(
|
||||
rocksdb_block_based_table_options_t* options, int v) {
|
||||
options->rep.metadata_cache_options.top_level_index_pinning =
|
||||
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_partition_pinning_tier(
|
||||
rocksdb_block_based_table_options_t* options, int v) {
|
||||
options->rep.metadata_cache_options.partition_pinning =
|
||||
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_unpartitioned_pinning_tier(
|
||||
rocksdb_block_based_table_options_t* options, int v) {
|
||||
options->rep.metadata_cache_options.unpartitioned_pinning =
|
||||
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
|
||||
}
|
||||
|
||||
rocksdb_cuckoo_table_options_t* rocksdb_cuckoo_options_create() {
|
||||
return new rocksdb_cuckoo_table_options_t;
|
||||
}
|
||||
@@ -2978,9 +2782,7 @@ void rocksdb_options_set_cuckoo_table_factory(
|
||||
void rocksdb_set_options(rocksdb_t* db, int count, const char* const keys[],
|
||||
const char* const values[], char** errptr) {
|
||||
std::unordered_map<std::string, std::string> options_map;
|
||||
for (int i = 0; i < count; i++) {
|
||||
options_map[keys[i]] = values[i];
|
||||
}
|
||||
for (int i = 0; i < count; i++) options_map[keys[i]] = values[i];
|
||||
SaveError(errptr, db->rep->SetOptions(options_map));
|
||||
}
|
||||
|
||||
@@ -2989,9 +2791,7 @@ void rocksdb_set_options_cf(rocksdb_t* db,
|
||||
const char* const keys[],
|
||||
const char* const values[], char** errptr) {
|
||||
std::unordered_map<std::string, std::string> options_map;
|
||||
for (int i = 0; i < count; i++) {
|
||||
options_map[keys[i]] = values[i];
|
||||
}
|
||||
for (int i = 0; i < count; i++) options_map[keys[i]] = values[i];
|
||||
SaveError(errptr, db->rep->SetOptions(handle->rep, options_map));
|
||||
}
|
||||
|
||||
@@ -3119,32 +2919,6 @@ void rocksdb_options_set_cf_paths(rocksdb_options_t* opt,
|
||||
opt->rep.cf_paths = cf_paths;
|
||||
}
|
||||
|
||||
rocksdb_logger_t* rocksdb_logger_create_stderr_logger(int log_level,
|
||||
const char* prefix) {
|
||||
rocksdb_logger_t* logger = new rocksdb_logger_t;
|
||||
|
||||
if (prefix) {
|
||||
logger->rep = std::make_shared<StderrLogger>(
|
||||
static_cast<InfoLogLevel>(log_level), prefix);
|
||||
} else {
|
||||
logger->rep =
|
||||
std::make_shared<StderrLogger>(static_cast<InfoLogLevel>(log_level));
|
||||
}
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
rocksdb_logger_t* rocksdb_logger_create_callback_logger(
|
||||
int log_level, void (*callback)(void*, unsigned, char*, size_t),
|
||||
void* priv) {
|
||||
rocksdb_logger_t* logger = new rocksdb_logger_t;
|
||||
logger->rep = std::make_shared<rocksdb_callback_logger_t>(
|
||||
static_cast<InfoLogLevel>(log_level), callback, priv);
|
||||
return logger;
|
||||
}
|
||||
|
||||
void rocksdb_logger_destroy(rocksdb_logger_t* logger) { delete logger; }
|
||||
|
||||
void rocksdb_options_set_env(rocksdb_options_t* opt, rocksdb_env_t* env) {
|
||||
opt->rep.env = (env ? env->rep : nullptr);
|
||||
}
|
||||
@@ -3155,12 +2929,6 @@ void rocksdb_options_set_info_log(rocksdb_options_t* opt, rocksdb_logger_t* l) {
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb_logger_t* rocksdb_options_get_info_log(rocksdb_options_t* opt) {
|
||||
rocksdb_logger_t* info_log = new rocksdb_logger_t;
|
||||
info_log->rep = opt->rep.info_log;
|
||||
return info_log;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_info_log_level(rocksdb_options_t* opt, int v) {
|
||||
opt->rep.info_log_level = static_cast<InfoLogLevel>(v);
|
||||
}
|
||||
@@ -3281,14 +3049,6 @@ void rocksdb_options_set_max_bytes_for_level_multiplier_additional(
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_options_set_ttl(rocksdb_options_t* opt, uint64_t seconds) {
|
||||
opt->rep.ttl = seconds;
|
||||
}
|
||||
|
||||
uint64_t rocksdb_options_get_ttl(rocksdb_options_t* opt) {
|
||||
return opt->rep.ttl;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_periodic_compaction_seconds(rocksdb_options_t* opt,
|
||||
uint64_t seconds) {
|
||||
opt->rep.periodic_compaction_seconds = seconds;
|
||||
@@ -3351,7 +3111,7 @@ void rocksdb_options_set_enable_blob_files(rocksdb_options_t* opt,
|
||||
unsigned char val) {
|
||||
opt->rep.enable_blob_files = val;
|
||||
}
|
||||
ROCKSDB_LIBRARY_API unsigned char rocksdb_options_get_enable_blob_files(
|
||||
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_options_get_enable_blob_files(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.enable_blob_files;
|
||||
}
|
||||
@@ -3723,6 +3483,35 @@ unsigned char rocksdb_options_get_advise_random_on_open(
|
||||
return opt->rep.advise_random_on_open;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_access_hint_on_compaction_start(rocksdb_options_t* opt,
|
||||
int v) {
|
||||
switch (v) {
|
||||
case 0:
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::NONE;
|
||||
break;
|
||||
case 1:
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::NORMAL;
|
||||
break;
|
||||
case 2:
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::SEQUENTIAL;
|
||||
break;
|
||||
case 3:
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::WILLNEED;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
int rocksdb_options_get_access_hint_on_compaction_start(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.access_hint_on_compaction_start;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_use_adaptive_mutex(rocksdb_options_t* opt,
|
||||
unsigned char v) {
|
||||
opt->rep.use_adaptive_mutex = v;
|
||||
@@ -4065,27 +3854,6 @@ void rocksdb_options_set_plain_table_factory(
|
||||
opt->rep.table_factory.reset(factory);
|
||||
}
|
||||
|
||||
unsigned char rocksdb_options_get_write_dbid_to_manifest(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.write_dbid_to_manifest;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_write_dbid_to_manifest(
|
||||
rocksdb_options_t* opt, unsigned char write_dbid_to_manifest) {
|
||||
opt->rep.write_dbid_to_manifest = write_dbid_to_manifest;
|
||||
}
|
||||
|
||||
unsigned char rocksdb_options_get_track_and_verify_wals_in_manifest(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.track_and_verify_wals_in_manifest;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_track_and_verify_wals_in_manifest(
|
||||
rocksdb_options_t* opt, unsigned char track_and_verify_wals_in_manifest) {
|
||||
opt->rep.track_and_verify_wals_in_manifest =
|
||||
track_and_verify_wals_in_manifest;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_max_successive_merges(rocksdb_options_t* opt,
|
||||
size_t v) {
|
||||
opt->rep.max_successive_merges = v;
|
||||
@@ -4149,14 +3917,6 @@ void rocksdb_options_set_fifo_compaction_options(
|
||||
opt->rep.compaction_options_fifo = fifo->rep;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compaction_pri(rocksdb_options_t* opt, int pri) {
|
||||
opt->rep.compaction_pri = static_cast<ROCKSDB_NAMESPACE::CompactionPri>(pri);
|
||||
}
|
||||
|
||||
int rocksdb_options_get_compaction_pri(rocksdb_options_t* opt) {
|
||||
return opt->rep.compaction_pri;
|
||||
}
|
||||
|
||||
char* rocksdb_options_statistics_get_string(rocksdb_options_t* opt) {
|
||||
ROCKSDB_NAMESPACE::Statistics* statistics = opt->rep.statistics.get();
|
||||
if (statistics) {
|
||||
@@ -4237,16 +3997,6 @@ rocksdb_ratelimiter_t* rocksdb_ratelimiter_create_auto_tuned(
|
||||
return rate_limiter;
|
||||
}
|
||||
|
||||
rocksdb_ratelimiter_t* rocksdb_ratelimiter_create_with_mode(
|
||||
int64_t rate_bytes_per_sec, int64_t refill_period_us, int32_t fairness,
|
||||
int mode, bool auto_tuned) {
|
||||
rocksdb_ratelimiter_t* rate_limiter = new rocksdb_ratelimiter_t;
|
||||
rate_limiter->rep.reset(
|
||||
NewGenericRateLimiter(rate_bytes_per_sec, refill_period_us, fairness,
|
||||
static_cast<RateLimiter::Mode>(mode), auto_tuned));
|
||||
return rate_limiter;
|
||||
}
|
||||
|
||||
void rocksdb_ratelimiter_destroy(rocksdb_ratelimiter_t* limiter) {
|
||||
delete limiter;
|
||||
}
|
||||
@@ -4465,8 +4215,13 @@ void rocksdb_perfcontext_destroy(rocksdb_perfcontext_t* context) {
|
||||
|
||||
/*
|
||||
TODO:
|
||||
DB::OpenForReadOnly
|
||||
DB::KeyMayExist
|
||||
DB::GetOptions
|
||||
DB::GetSortedWalFiles
|
||||
DB::GetLatestSequenceNumber
|
||||
DB::GetUpdatesSince
|
||||
DB::GetDbIdentity
|
||||
DB::RunManualCompaction
|
||||
custom cache
|
||||
table_properties_collectors
|
||||
@@ -4838,7 +4593,7 @@ void rocksdb_readoptions_set_io_timeout(rocksdb_readoptions_t* opt,
|
||||
opt->rep.io_timeout = std::chrono::microseconds(microseconds);
|
||||
}
|
||||
|
||||
ROCKSDB_LIBRARY_API uint64_t
|
||||
extern ROCKSDB_LIBRARY_API uint64_t
|
||||
rocksdb_readoptions_get_io_timeout(rocksdb_readoptions_t* opt) {
|
||||
return opt->rep.io_timeout.count();
|
||||
}
|
||||
@@ -5287,9 +5042,7 @@ void rocksdb_env_lower_high_priority_thread_pool_cpu_priority(
|
||||
}
|
||||
|
||||
void rocksdb_env_destroy(rocksdb_env_t* env) {
|
||||
if (!env->is_default) {
|
||||
delete env->rep;
|
||||
}
|
||||
if (!env->is_default) delete env->rep;
|
||||
delete env;
|
||||
}
|
||||
|
||||
@@ -5673,7 +5426,9 @@ uint64_t rocksdb_livefiles_deletions(const rocksdb_livefiles_t* lf, int index) {
|
||||
return lf->rep[index].num_deletions;
|
||||
}
|
||||
|
||||
void rocksdb_livefiles_destroy(const rocksdb_livefiles_t* lf) { delete lf; }
|
||||
extern void rocksdb_livefiles_destroy(const rocksdb_livefiles_t* lf) {
|
||||
delete lf;
|
||||
}
|
||||
|
||||
void rocksdb_get_options_from_string(const rocksdb_options_t* base_options,
|
||||
const char* opts_str,
|
||||
@@ -5753,7 +5508,7 @@ size_t rocksdb_column_family_metadata_get_level_count(
|
||||
rocksdb_level_metadata_t* rocksdb_column_family_metadata_get_level_metadata(
|
||||
rocksdb_column_family_metadata_t* cf_meta, size_t i) {
|
||||
if (i >= cf_meta->rep.levels.size()) {
|
||||
return nullptr;
|
||||
return NULL;
|
||||
}
|
||||
rocksdb_level_metadata_t* level_meta =
|
||||
(rocksdb_level_metadata_t*)malloc(sizeof(rocksdb_level_metadata_t));
|
||||
@@ -5943,7 +5698,6 @@ rocksdb_column_family_handle_t* rocksdb_transactiondb_create_column_family(
|
||||
SaveError(errptr, txn_db->rep->CreateColumnFamily(
|
||||
ColumnFamilyOptions(column_family_options->rep),
|
||||
std::string(column_family_name), &(handle->rep)));
|
||||
handle->immortal = false;
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -5969,9 +5723,9 @@ rocksdb_transactiondb_t* rocksdb_transactiondb_open_column_families(
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
TransactionDB* txn_db;
|
||||
@@ -5986,7 +5740,6 @@ rocksdb_transactiondb_t* rocksdb_transactiondb_open_column_families(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_transactiondb_t* result = new rocksdb_transactiondb_t;
|
||||
@@ -6764,9 +6517,9 @@ rocksdb_optimistictransactiondb_open_column_families(
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.emplace_back(
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
std::string(column_family_names[i]),
|
||||
ColumnFamilyOptions(column_family_options[i]->rep));
|
||||
ColumnFamilyOptions(column_family_options[i]->rep)));
|
||||
}
|
||||
|
||||
OptimisticTransactionDB* otxn_db;
|
||||
@@ -6781,7 +6534,6 @@ rocksdb_optimistictransactiondb_open_column_families(
|
||||
rocksdb_column_family_handle_t* c_handle =
|
||||
new rocksdb_column_family_handle_t;
|
||||
c_handle->rep = handles[i];
|
||||
c_handle->immortal = false;
|
||||
column_family_handles[i] = c_handle;
|
||||
}
|
||||
rocksdb_optimistictransactiondb_t* result =
|
||||
|
||||
+18
-245
@@ -50,13 +50,12 @@ static void StartPhase(const char* name) {
|
||||
#endif
|
||||
static const char* GetTempDir(void) {
|
||||
const char* ret = getenv("TEST_TMPDIR");
|
||||
if (ret == NULL || ret[0] == '\0') {
|
||||
if (ret == NULL || ret[0] == '\0')
|
||||
#ifdef OS_WIN
|
||||
ret = getenv("TEMP");
|
||||
#else
|
||||
ret = "/tmp";
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
@@ -199,79 +198,6 @@ static void CheckDel(void* ptr, const char* k, size_t klen) {
|
||||
(*state)++;
|
||||
}
|
||||
|
||||
// Callback from rocksdb_writebatch_iterate_cf()
|
||||
static void CheckPutCF(void* ptr, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen) {
|
||||
int* state = (int*)ptr;
|
||||
switch (*state) {
|
||||
case 0:
|
||||
CheckEqual("bar", k, klen);
|
||||
CheckEqual("b", v, vlen);
|
||||
CheckCondition(cfid == 1);
|
||||
break;
|
||||
case 1:
|
||||
CheckEqual("box", k, klen);
|
||||
CheckEqual("c", v, vlen);
|
||||
CheckCondition(cfid == 1);
|
||||
break;
|
||||
case 4:
|
||||
CheckEqual("foo", k, klen);
|
||||
CheckEqual("f", v, vlen);
|
||||
CheckCondition(cfid == 0);
|
||||
break;
|
||||
case 6:
|
||||
CheckEqual("baz", k, klen);
|
||||
CheckEqual("a", v, vlen);
|
||||
CheckCondition(cfid == 0);
|
||||
break;
|
||||
default:
|
||||
CheckCondition(false);
|
||||
break;
|
||||
}
|
||||
(*state)++;
|
||||
}
|
||||
|
||||
// Callback from rocksdb_writebatch_iterate_cf()
|
||||
static void CheckDelCF(void* ptr, uint32_t cfid, const char* k, size_t klen) {
|
||||
int* state = (int*)ptr;
|
||||
switch (*state) {
|
||||
case 2:
|
||||
CheckEqual("bar", k, klen);
|
||||
CheckCondition(cfid == 1);
|
||||
break;
|
||||
case 5:
|
||||
CheckEqual("foo", k, klen);
|
||||
CheckCondition(cfid == 0);
|
||||
break;
|
||||
default:
|
||||
CheckCondition(false);
|
||||
break;
|
||||
}
|
||||
(*state)++;
|
||||
}
|
||||
|
||||
// Callback from rocksdb_writebatch_iterate_cf()
|
||||
static void CheckMergeCF(void* ptr, uint32_t cfid, const char* k, size_t klen,
|
||||
const char* v, size_t vlen) {
|
||||
int* state = (int*)ptr;
|
||||
switch (*state) {
|
||||
case 3:
|
||||
CheckEqual("box", k, klen);
|
||||
CheckEqual("cc", v, vlen);
|
||||
CheckCondition(cfid == 1);
|
||||
break;
|
||||
case 7:
|
||||
CheckEqual("baz", k, klen);
|
||||
CheckEqual("aa", v, vlen);
|
||||
CheckCondition(cfid == 0);
|
||||
break;
|
||||
default:
|
||||
CheckCondition(false);
|
||||
break;
|
||||
}
|
||||
(*state)++;
|
||||
}
|
||||
|
||||
static void CmpDestroy(void* arg) { (void)arg; }
|
||||
|
||||
static int CmpCompare(void* arg, const char* a, size_t alen, const char* b,
|
||||
@@ -280,11 +206,10 @@ static int CmpCompare(void* arg, const char* a, size_t alen, const char* b,
|
||||
size_t n = (alen < blen) ? alen : blen;
|
||||
int r = memcmp(a, b, n);
|
||||
if (r == 0) {
|
||||
if (alen < blen) {
|
||||
if (alen < blen)
|
||||
r = -1;
|
||||
} else if (alen > blen) {
|
||||
else if (alen > blen)
|
||||
r = +1;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -777,10 +702,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_block_based_options_set_block_cache(table_options, cache);
|
||||
rocksdb_block_based_options_set_data_block_index_type(table_options, 1);
|
||||
rocksdb_block_based_options_set_data_block_hash_ratio(table_options, 0.75);
|
||||
rocksdb_block_based_options_set_top_level_index_pinning_tier(table_options,
|
||||
1);
|
||||
rocksdb_block_based_options_set_partition_pinning_tier(table_options, 2);
|
||||
rocksdb_block_based_options_set_unpartitioned_pinning_tier(table_options, 3);
|
||||
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||||
|
||||
rocksdb_options_set_compression(options, rocksdb_no_compression);
|
||||
@@ -797,11 +718,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_set_ratelimiter(options, rate_limiter);
|
||||
rocksdb_ratelimiter_destroy(rate_limiter);
|
||||
|
||||
rate_limiter = rocksdb_ratelimiter_create_with_mode(1000 * 1024 * 1024,
|
||||
100 * 1000, 10, 0, true);
|
||||
rocksdb_options_set_ratelimiter(options, rate_limiter);
|
||||
rocksdb_ratelimiter_destroy(rate_limiter);
|
||||
|
||||
roptions = rocksdb_readoptions_create();
|
||||
rocksdb_readoptions_set_verify_checksums(roptions, 1);
|
||||
rocksdb_readoptions_set_fill_cache(roptions, 1);
|
||||
@@ -871,11 +787,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_delete(db, woptions, "foo", 3, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
// get the identity before the backup
|
||||
size_t before_db_id_len = 0;
|
||||
char* before_db_id = rocksdb_get_db_identity(db, &before_db_id_len);
|
||||
CheckCondition(before_db_id_len == 36);
|
||||
|
||||
rocksdb_close(db);
|
||||
|
||||
rocksdb_destroy_db(options, dbname, &err);
|
||||
@@ -896,14 +807,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
CheckGet(db, roptions, "foo", "hello");
|
||||
|
||||
// the db_identity after the backup is different
|
||||
size_t after_db_id_len = 0;
|
||||
char* after_db_id = rocksdb_get_db_identity(db, &after_db_id_len);
|
||||
CheckCondition(after_db_id_len == 36);
|
||||
CheckCondition(memcmp(after_db_id, before_db_id, after_db_id_len) != 0);
|
||||
Free(&before_db_id);
|
||||
Free(&after_db_id);
|
||||
|
||||
rocksdb_backup_engine_close(be);
|
||||
}
|
||||
|
||||
@@ -919,14 +822,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_checkpoint_create(checkpoint, dbcheckpointname, 0, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_checkpoint_object_destroy(checkpoint);
|
||||
checkpoint = NULL;
|
||||
|
||||
// get the identity before the checkpoint
|
||||
size_t before_db_id_len = 0;
|
||||
char* before_db_id = rocksdb_get_db_identity(db, &before_db_id_len);
|
||||
CheckCondition(before_db_id_len == 36);
|
||||
|
||||
// start a new database from the checkpoint
|
||||
rocksdb_close(db);
|
||||
rocksdb_options_set_error_if_exists(options, 0);
|
||||
@@ -935,13 +830,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
CheckGet(db, roptions, "foo", "hello");
|
||||
|
||||
// the db_identity after the checkpoint is different
|
||||
size_t after_db_id_len = 0;
|
||||
char* after_db_id = rocksdb_get_db_identity(db, &after_db_id_len);
|
||||
CheckCondition(after_db_id_len == 36);
|
||||
CheckCondition(memcmp(after_db_id, before_db_id, after_db_id_len) != 0);
|
||||
Free(&before_db_id);
|
||||
Free(&after_db_id);
|
||||
rocksdb_checkpoint_object_destroy(checkpoint);
|
||||
|
||||
rocksdb_close(db);
|
||||
rocksdb_destroy_db(options, dbcheckpointname, &err);
|
||||
@@ -952,73 +841,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_set_error_if_exists(options, 1);
|
||||
}
|
||||
|
||||
StartPhase("checkpoint_db_id_in_manifest");
|
||||
{
|
||||
// create new DB with set_write_dbid_to_manifest=true
|
||||
// db_identity is now the same across checkpoints
|
||||
rocksdb_close(db);
|
||||
db = NULL;
|
||||
|
||||
rocksdb_options_t* options_dbid_in_manifest = rocksdb_options_create();
|
||||
rocksdb_options_set_create_if_missing(options_dbid_in_manifest, 1);
|
||||
|
||||
unsigned char write_to_manifest =
|
||||
rocksdb_options_get_write_dbid_to_manifest(options_dbid_in_manifest);
|
||||
CheckCondition(!write_to_manifest);
|
||||
rocksdb_options_set_write_dbid_to_manifest(options_dbid_in_manifest, true);
|
||||
CheckCondition(!write_to_manifest);
|
||||
write_to_manifest =
|
||||
rocksdb_options_get_write_dbid_to_manifest(options_dbid_in_manifest);
|
||||
CheckCondition(write_to_manifest);
|
||||
|
||||
db = rocksdb_open(options_dbid_in_manifest, dbbackupname, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_checkpoint_t* checkpoint =
|
||||
rocksdb_checkpoint_object_create(db, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_checkpoint_create(checkpoint, dbcheckpointname, 0, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_checkpoint_object_destroy(checkpoint);
|
||||
checkpoint = NULL;
|
||||
|
||||
// get the identity before the backup
|
||||
size_t before_db_id_len = 0;
|
||||
char* before_db_id = rocksdb_get_db_identity(db, &before_db_id_len);
|
||||
CheckCondition(before_db_id_len == 36);
|
||||
|
||||
// open the checkpoint
|
||||
rocksdb_close(db);
|
||||
rocksdb_destroy_db(options_dbid_in_manifest, dbbackupname, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_options_set_error_if_exists(options_dbid_in_manifest, 0);
|
||||
db = rocksdb_open(options_dbid_in_manifest, dbcheckpointname, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
// the db_identity after the checkpoint is the same
|
||||
size_t after_db_id_len = 0;
|
||||
char* after_db_id = rocksdb_get_db_identity(db, &after_db_id_len);
|
||||
CheckCondition(after_db_id_len == 36);
|
||||
CheckCondition(memcmp(after_db_id, before_db_id, after_db_id_len) == 0);
|
||||
Free(&before_db_id);
|
||||
Free(&after_db_id);
|
||||
|
||||
rocksdb_close(db);
|
||||
rocksdb_destroy_db(options_dbid_in_manifest, dbcheckpointname, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_options_destroy(options_dbid_in_manifest);
|
||||
options_dbid_in_manifest = NULL;
|
||||
|
||||
// re-open the default database
|
||||
rocksdb_options_set_error_if_exists(options, 0);
|
||||
db = rocksdb_open(options, dbname, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_options_set_error_if_exists(options, 1);
|
||||
}
|
||||
|
||||
StartPhase("compactall");
|
||||
rocksdb_compact_range(db, NULL, 0, NULL, 0);
|
||||
CheckGet(db, roptions, "foo", "hello");
|
||||
@@ -1056,8 +878,9 @@ int main(int argc, char** argv) {
|
||||
StartPhase("addfile");
|
||||
{
|
||||
rocksdb_envoptions_t* env_opt = rocksdb_envoptions_create();
|
||||
rocksdb_options_t* io_options = rocksdb_options_create();
|
||||
rocksdb_sstfilewriter_t* writer =
|
||||
rocksdb_sstfilewriter_create(env_opt, options);
|
||||
rocksdb_sstfilewriter_create(env_opt, io_options);
|
||||
|
||||
remove(sstfilename);
|
||||
rocksdb_sstfilewriter_open(writer, sstfilename, &err);
|
||||
@@ -1116,6 +939,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
rocksdb_ingestexternalfileoptions_destroy(ing_opt);
|
||||
rocksdb_sstfilewriter_destroy(writer);
|
||||
rocksdb_options_destroy(io_options);
|
||||
rocksdb_envoptions_destroy(env_opt);
|
||||
|
||||
// Delete all keys we just ingested
|
||||
@@ -1489,8 +1313,6 @@ int main(int argc, char** argv) {
|
||||
policy = rocksdb_filterpolicy_create_ribbon_hybrid(8.0, 1);
|
||||
}
|
||||
rocksdb_block_based_options_set_filter_policy(table_options, policy);
|
||||
rocksdb_block_based_options_set_optimize_filters_for_memory(table_options,
|
||||
0);
|
||||
|
||||
// Create new database
|
||||
rocksdb_close(db);
|
||||
@@ -1761,21 +1583,6 @@ int main(int argc, char** argv) {
|
||||
CheckPinGetCF(db, roptions, handles[1], "bar", NULL);
|
||||
CheckPinGetCF(db, roptions, handles[1], "box", "c");
|
||||
CheckPinGetCF(db, roptions, handles[1], "buff", "rocksdb");
|
||||
rocksdb_writebatch_clear(wb);
|
||||
// Test WriteBatch iteration with Column Family
|
||||
int pos = 0;
|
||||
rocksdb_writebatch_put_cf(wb, handles[1], "bar", 3, "b", 1);
|
||||
rocksdb_writebatch_put_cf(wb, handles[1], "box", 3, "c", 1);
|
||||
rocksdb_writebatch_delete_cf(wb, handles[1], "bar", 3);
|
||||
rocksdb_writebatch_merge_cf(wb, handles[1], "box", 3, "cc", 2);
|
||||
rocksdb_writebatch_put(wb, "foo", 3, "f", 1);
|
||||
rocksdb_writebatch_delete(wb, "foo", 3);
|
||||
rocksdb_writebatch_put(wb, "baz", 3, "a", 1);
|
||||
rocksdb_writebatch_merge(wb, "baz", 3, "aa", 2);
|
||||
rocksdb_writebatch_iterate_cf(wb, &pos, CheckPutCF, CheckDelCF,
|
||||
CheckMergeCF);
|
||||
CheckCondition(pos == 8);
|
||||
rocksdb_writebatch_clear(wb);
|
||||
rocksdb_writebatch_destroy(wb);
|
||||
|
||||
rocksdb_flush_wal(db, 1, &err);
|
||||
@@ -2118,9 +1925,6 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(100000 ==
|
||||
rocksdb_options_get_periodic_compaction_seconds(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));
|
||||
|
||||
@@ -2227,6 +2031,9 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_set_advise_random_on_open(o, 1);
|
||||
CheckCondition(1 == rocksdb_options_get_advise_random_on_open(o));
|
||||
|
||||
rocksdb_options_set_access_hint_on_compaction_start(o, 3);
|
||||
CheckCondition(3 == rocksdb_options_get_access_hint_on_compaction_start(o));
|
||||
|
||||
rocksdb_options_set_use_adaptive_mutex(o, 1);
|
||||
CheckCondition(1 == rocksdb_options_get_use_adaptive_mutex(o));
|
||||
|
||||
@@ -2297,9 +2104,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_set_compaction_style(o, 2);
|
||||
CheckCondition(2 == rocksdb_options_get_compaction_style(o));
|
||||
|
||||
rocksdb_options_set_compaction_pri(o, 4);
|
||||
CheckCondition(4 == rocksdb_options_get_compaction_pri(o));
|
||||
|
||||
rocksdb_options_set_atomic_flush(o, 1);
|
||||
CheckCondition(1 == rocksdb_options_get_atomic_flush(o));
|
||||
|
||||
@@ -2322,12 +2126,6 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(rocksdb_statistics_level_all ==
|
||||
rocksdb_options_get_statistics_level(o));
|
||||
|
||||
CheckCondition(0 ==
|
||||
rocksdb_options_get_track_and_verify_wals_in_manifest(o));
|
||||
rocksdb_options_set_track_and_verify_wals_in_manifest(o, 42);
|
||||
CheckCondition(1 ==
|
||||
rocksdb_options_get_track_and_verify_wals_in_manifest(o));
|
||||
|
||||
/* Blob Options */
|
||||
rocksdb_options_set_enable_blob_files(o, 1);
|
||||
CheckCondition(1 == rocksdb_options_get_enable_blob_files(o));
|
||||
@@ -2430,6 +2228,8 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(18 == rocksdb_options_get_stats_dump_period_sec(copy));
|
||||
CheckCondition(5 == rocksdb_options_get_stats_persist_period_sec(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_advise_random_on_open(copy));
|
||||
CheckCondition(3 ==
|
||||
rocksdb_options_get_access_hint_on_compaction_start(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_use_adaptive_mutex(copy));
|
||||
CheckCondition(19 == rocksdb_options_get_bytes_per_sync(copy));
|
||||
CheckCondition(20 == rocksdb_options_get_wal_bytes_per_sync(copy));
|
||||
@@ -2561,10 +2361,6 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(100000 ==
|
||||
rocksdb_options_get_periodic_compaction_seconds(o));
|
||||
|
||||
rocksdb_options_set_ttl(copy, 8000);
|
||||
CheckCondition(8000 == rocksdb_options_get_ttl(copy));
|
||||
CheckCondition(5000 == rocksdb_options_get_ttl(o));
|
||||
|
||||
rocksdb_options_set_skip_stats_update_on_db_open(copy, 0);
|
||||
CheckCondition(0 == rocksdb_options_get_skip_stats_update_on_db_open(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_skip_stats_update_on_db_open(o));
|
||||
@@ -2712,6 +2508,11 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(0 == rocksdb_options_get_advise_random_on_open(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_advise_random_on_open(o));
|
||||
|
||||
rocksdb_options_set_access_hint_on_compaction_start(copy, 2);
|
||||
CheckCondition(2 ==
|
||||
rocksdb_options_get_access_hint_on_compaction_start(copy));
|
||||
CheckCondition(3 == rocksdb_options_get_access_hint_on_compaction_start(o));
|
||||
|
||||
rocksdb_options_set_use_adaptive_mutex(copy, 0);
|
||||
CheckCondition(0 == rocksdb_options_get_use_adaptive_mutex(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_use_adaptive_mutex(o));
|
||||
@@ -2810,10 +2611,6 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(1 == rocksdb_options_get_compaction_style(copy));
|
||||
CheckCondition(2 == rocksdb_options_get_compaction_style(o));
|
||||
|
||||
rocksdb_options_set_compaction_pri(copy, 1);
|
||||
CheckCondition(1 == rocksdb_options_get_compaction_pri(copy));
|
||||
CheckCondition(4 == rocksdb_options_get_compaction_pri(o));
|
||||
|
||||
rocksdb_options_set_atomic_flush(copy, 0);
|
||||
CheckCondition(0 == rocksdb_options_get_atomic_flush(copy));
|
||||
CheckCondition(1 == rocksdb_options_get_atomic_flush(o));
|
||||
@@ -2984,30 +2781,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_memory_allocator_destroy(allocator);
|
||||
}
|
||||
|
||||
StartPhase("stderr_logger");
|
||||
{
|
||||
rocksdb_options_t* o_no_prefix = rocksdb_options_create();
|
||||
rocksdb_logger_t* no_prefix_logger =
|
||||
rocksdb_logger_create_stderr_logger(3, NULL);
|
||||
rocksdb_options_set_info_log(o_no_prefix, no_prefix_logger);
|
||||
rocksdb_logger_t* no_prefix_info_log =
|
||||
rocksdb_options_get_info_log(o_no_prefix);
|
||||
CheckCondition(no_prefix_info_log != NULL);
|
||||
rocksdb_logger_destroy(no_prefix_logger);
|
||||
rocksdb_logger_destroy(no_prefix_info_log);
|
||||
rocksdb_options_destroy(o_no_prefix);
|
||||
|
||||
rocksdb_options_t* o_prefix = rocksdb_options_create();
|
||||
rocksdb_logger_t* prefix_logger =
|
||||
rocksdb_logger_create_stderr_logger(3, "some prefix");
|
||||
rocksdb_options_set_info_log(o_prefix, prefix_logger);
|
||||
rocksdb_logger_t* prefix_info_log = rocksdb_options_get_info_log(o_prefix);
|
||||
CheckCondition(prefix_info_log != NULL);
|
||||
rocksdb_logger_destroy(prefix_logger);
|
||||
rocksdb_logger_destroy(prefix_info_log);
|
||||
rocksdb_options_destroy(o_prefix);
|
||||
}
|
||||
|
||||
StartPhase("env");
|
||||
{
|
||||
rocksdb_env_t* e;
|
||||
@@ -3914,7 +3687,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
StartPhase("statistics");
|
||||
{
|
||||
const uint32_t BYTES_WRITTEN_TICKER = 60;
|
||||
const uint32_t BYTES_WRITTEN_TICKER = 40;
|
||||
const uint32_t DB_WRITE_HIST = 1;
|
||||
|
||||
rocksdb_statistics_histogram_data_t* hist =
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/coalescing_iterator.h"
|
||||
|
||||
#include "db/wide/wide_columns_helper.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
void CoalescingIterator::Coalesce(
|
||||
const autovector<MultiCfIteratorInfo>& items) {
|
||||
assert(wide_columns_.empty());
|
||||
MinHeap heap;
|
||||
for (const auto& item : items) {
|
||||
assert(item.iterator);
|
||||
for (auto& column : item.iterator->columns()) {
|
||||
heap.push(WideColumnWithOrder{&column, item.order});
|
||||
}
|
||||
}
|
||||
if (heap.empty()) {
|
||||
return;
|
||||
}
|
||||
wide_columns_.reserve(heap.size());
|
||||
auto current = heap.top();
|
||||
heap.pop();
|
||||
while (!heap.empty()) {
|
||||
int comparison = current.column->name().compare(heap.top().column->name());
|
||||
if (comparison < 0) {
|
||||
wide_columns_.push_back(*current.column);
|
||||
} else if (comparison > 0) {
|
||||
// Shouldn't reach here.
|
||||
// Current item in the heap is greater than the top item in the min heap
|
||||
assert(false);
|
||||
}
|
||||
current = heap.top();
|
||||
heap.pop();
|
||||
}
|
||||
wide_columns_.push_back(*current.column);
|
||||
|
||||
if (WideColumnsHelper::HasDefaultColumn(wide_columns_)) {
|
||||
value_ = WideColumnsHelper::GetDefaultColumn(wide_columns_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "db/multi_cf_iterator_impl.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// EXPERIMENTAL
|
||||
class CoalescingIterator : public Iterator {
|
||||
public:
|
||||
CoalescingIterator(const Comparator* comparator,
|
||||
const std::vector<ColumnFamilyHandle*>& column_families,
|
||||
const std::vector<Iterator*>& child_iterators)
|
||||
: impl_(
|
||||
comparator, column_families, child_iterators, [this]() { Reset(); },
|
||||
[this](const autovector<MultiCfIteratorInfo>& items) {
|
||||
Coalesce(items);
|
||||
}) {}
|
||||
~CoalescingIterator() override {}
|
||||
|
||||
// No copy allowed
|
||||
CoalescingIterator(const CoalescingIterator&) = delete;
|
||||
CoalescingIterator& operator=(const CoalescingIterator&) = delete;
|
||||
|
||||
bool Valid() const override { return impl_.Valid(); }
|
||||
void SeekToFirst() override { impl_.SeekToFirst(); }
|
||||
void SeekToLast() override { impl_.SeekToLast(); }
|
||||
void Seek(const Slice& target) override { impl_.Seek(target); }
|
||||
void SeekForPrev(const Slice& target) override { impl_.SeekForPrev(target); }
|
||||
void Next() override { impl_.Next(); }
|
||||
void Prev() override { impl_.Prev(); }
|
||||
Slice key() const override { return impl_.key(); }
|
||||
Status status() const override { return impl_.status(); }
|
||||
|
||||
Slice value() const override {
|
||||
assert(Valid());
|
||||
return value_;
|
||||
}
|
||||
const WideColumns& columns() const override {
|
||||
assert(Valid());
|
||||
return wide_columns_;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
value_.clear();
|
||||
wide_columns_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
MultiCfIteratorImpl impl_;
|
||||
Slice value_;
|
||||
WideColumns wide_columns_;
|
||||
|
||||
struct WideColumnWithOrder {
|
||||
const WideColumn* column;
|
||||
int order;
|
||||
};
|
||||
|
||||
class WideColumnWithOrderComparator {
|
||||
public:
|
||||
explicit WideColumnWithOrderComparator() {}
|
||||
bool operator()(const WideColumnWithOrder& a,
|
||||
const WideColumnWithOrder& b) const {
|
||||
int c = a.column->name().compare(b.column->name());
|
||||
return c == 0 ? a.order - b.order > 0 : c > 0;
|
||||
}
|
||||
};
|
||||
|
||||
using MinHeap =
|
||||
BinaryHeap<WideColumnWithOrder, WideColumnWithOrderComparator>;
|
||||
|
||||
void Coalesce(const autovector<MultiCfIteratorInfo>& items);
|
||||
};
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+24
-86
@@ -96,16 +96,16 @@ const Comparator* ColumnFamilyHandleImpl::GetComparator() const {
|
||||
return cfd()->user_comparator();
|
||||
}
|
||||
|
||||
void GetInternalTblPropCollFactory(
|
||||
void GetIntTblPropCollectorFactory(
|
||||
const ImmutableCFOptions& ioptions,
|
||||
InternalTblPropCollFactories* internal_tbl_prop_coll_factories) {
|
||||
assert(internal_tbl_prop_coll_factories);
|
||||
IntTblPropCollectorFactories* int_tbl_prop_collector_factories) {
|
||||
assert(int_tbl_prop_collector_factories);
|
||||
|
||||
auto& collector_factories = ioptions.table_properties_collector_factories;
|
||||
for (size_t i = 0; i < ioptions.table_properties_collector_factories.size();
|
||||
++i) {
|
||||
assert(collector_factories[i]);
|
||||
internal_tbl_prop_coll_factories->emplace_back(
|
||||
int_tbl_prop_collector_factories->emplace_back(
|
||||
new UserKeyTablePropertiesCollectorFactory(collector_factories[i]));
|
||||
}
|
||||
}
|
||||
@@ -322,8 +322,8 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
}
|
||||
ROCKS_LOG_WARN(db_options.logger,
|
||||
"Adjust the value to "
|
||||
"level0_stop_writes_trigger(%d) "
|
||||
"level0_slowdown_writes_trigger(%d) "
|
||||
"level0_stop_writes_trigger(%d)"
|
||||
"level0_slowdown_writes_trigger(%d)"
|
||||
"level0_file_num_compaction_trigger(%d)",
|
||||
result.level0_stop_writes_trigger,
|
||||
result.level0_slowdown_writes_trigger,
|
||||
@@ -358,16 +358,16 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
|
||||
if (result.level_compaction_dynamic_level_bytes) {
|
||||
if (result.compaction_style != kCompactionStyleLevel) {
|
||||
ROCKS_LOG_INFO(db_options.info_log.get(),
|
||||
"level_compaction_dynamic_level_bytes only makes sense "
|
||||
ROCKS_LOG_WARN(db_options.info_log.get(),
|
||||
"level_compaction_dynamic_level_bytes only makes sense"
|
||||
"for level-based compaction");
|
||||
result.level_compaction_dynamic_level_bytes = false;
|
||||
} else if (result.cf_paths.size() > 1U) {
|
||||
// we don't yet know how to make both of this feature and multiple
|
||||
// DB path work.
|
||||
ROCKS_LOG_WARN(db_options.info_log.get(),
|
||||
"multiple cf_paths/db_paths and "
|
||||
"level_compaction_dynamic_level_bytes "
|
||||
"multiple cf_paths/db_paths and"
|
||||
"level_compaction_dynamic_level_bytes"
|
||||
"can't be used together");
|
||||
result.level_compaction_dynamic_level_bytes = false;
|
||||
}
|
||||
@@ -411,13 +411,6 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
"periodic_compaction_seconds does not support FIFO compaction. You"
|
||||
"may want to set option TTL instead.");
|
||||
}
|
||||
if (result.last_level_temperature != Temperature::kUnknown) {
|
||||
ROCKS_LOG_WARN(
|
||||
db_options.info_log.get(),
|
||||
"last_level_temperature is ignored with FIFO compaction. Consider "
|
||||
"CompactionOptionsFIFO::file_temperature_age_thresholds.");
|
||||
result.last_level_temperature = Temperature::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
// For universal compaction, `ttl` and `periodic_compaction_seconds` mean the
|
||||
@@ -477,16 +470,13 @@ void SuperVersion::Cleanup() {
|
||||
cfd->UnrefAndTryDelete();
|
||||
}
|
||||
|
||||
void SuperVersion::Init(
|
||||
ColumnFamilyData* new_cfd, MemTable* new_mem, MemTableListVersion* new_imm,
|
||||
Version* new_current,
|
||||
std::shared_ptr<const SeqnoToTimeMapping> new_seqno_to_time_mapping) {
|
||||
void SuperVersion::Init(ColumnFamilyData* new_cfd, MemTable* new_mem,
|
||||
MemTableListVersion* new_imm, Version* new_current) {
|
||||
cfd = new_cfd;
|
||||
mem = new_mem;
|
||||
imm = new_imm;
|
||||
current = new_current;
|
||||
full_history_ts_low = cfd->GetFullHistoryTsLow();
|
||||
seqno_to_time_mapping = std::move(new_seqno_to_time_mapping);
|
||||
cfd->Ref();
|
||||
mem->Ref();
|
||||
imm->Ref();
|
||||
@@ -538,7 +528,6 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
refs_(0),
|
||||
initialized_(false),
|
||||
dropped_(false),
|
||||
flush_skip_reschedule_(false),
|
||||
internal_comparator_(cf_options.comparator),
|
||||
initial_cf_options_(SanitizeOptions(db_options, cf_options)),
|
||||
ioptions_(db_options, initial_cf_options_),
|
||||
@@ -583,7 +572,7 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
Ref();
|
||||
|
||||
// Convert user defined table properties collector factories to internal ones.
|
||||
GetInternalTblPropCollFactory(ioptions_, &internal_tbl_prop_coll_factories_);
|
||||
GetIntTblPropCollectorFactory(ioptions_, &int_tbl_prop_collector_factories_);
|
||||
|
||||
// if _dummy_versions is nullptr, then this is a dummy column family.
|
||||
if (_dummy_versions != nullptr) {
|
||||
@@ -881,7 +870,7 @@ uint64_t GetPendingCompactionBytesForCompactionSpeedup(
|
||||
const VersionStorageInfo* vstorage) {
|
||||
// Compaction debt relatively large compared to the stable (bottommost) data
|
||||
// size indicates compaction fell behind.
|
||||
const uint64_t kBottommostSizeDivisor = 8;
|
||||
const uint64_t kBottommostSizeMultiplier = 8;
|
||||
// Meaningful progress toward the slowdown trigger is another good indication.
|
||||
const uint64_t kSlowdownTriggerDivisor = 4;
|
||||
|
||||
@@ -901,17 +890,10 @@ uint64_t GetPendingCompactionBytesForCompactionSpeedup(
|
||||
return slowdown_threshold;
|
||||
}
|
||||
|
||||
uint64_t size_threshold = bottommost_files_size / kBottommostSizeDivisor;
|
||||
uint64_t size_threshold =
|
||||
MultiplyCheckOverflow(bottommost_files_size, kBottommostSizeMultiplier);
|
||||
return std::min(size_threshold, slowdown_threshold);
|
||||
}
|
||||
|
||||
uint64_t GetMarkedFileCountForCompactionSpeedup() {
|
||||
// When just one file is marked, it is not clear that parallel compaction will
|
||||
// help the compaction that the user nicely requested to happen sooner. When
|
||||
// multiple files are marked, however, it is pretty clearly helpful, except
|
||||
// for the rare case in which a single compaction grabs all the marked files.
|
||||
return 2;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
std::pair<WriteStallCondition, WriteStallCause>
|
||||
@@ -1093,16 +1075,6 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
"compaction "
|
||||
"bytes %" PRIu64,
|
||||
name_.c_str(), vstorage->estimated_compaction_needed_bytes());
|
||||
} else if (uint64_t(vstorage->FilesMarkedForCompaction().size()) >=
|
||||
GetMarkedFileCountForCompactionSpeedup()) {
|
||||
write_controller_token_ =
|
||||
write_controller->GetCompactionPressureToken();
|
||||
ROCKS_LOG_INFO(
|
||||
ioptions_.logger,
|
||||
"[%s] Increasing compaction threads because we have %" PRIu64
|
||||
" files marked for compaction",
|
||||
name_.c_str(),
|
||||
uint64_t(vstorage->FilesMarkedForCompaction().size()));
|
||||
} else {
|
||||
write_controller_token_.reset();
|
||||
}
|
||||
@@ -1190,22 +1162,21 @@ bool ColumnFamilyData::RangeOverlapWithCompaction(
|
||||
}
|
||||
|
||||
Status ColumnFamilyData::RangesOverlapWithMemtables(
|
||||
const autovector<UserKeyRange>& ranges, SuperVersion* super_version,
|
||||
const autovector<Range>& ranges, SuperVersion* super_version,
|
||||
bool allow_data_in_errors, bool* overlap) {
|
||||
assert(overlap != nullptr);
|
||||
*overlap = false;
|
||||
// Create an InternalIterator over all unflushed memtables
|
||||
Arena arena;
|
||||
// TODO: plumb Env::IOActivity, Env::IOPriority
|
||||
// TODO: plumb Env::IOActivity
|
||||
ReadOptions read_opts;
|
||||
read_opts.total_order_seek = true;
|
||||
MergeIteratorBuilder merge_iter_builder(&internal_comparator_, &arena);
|
||||
merge_iter_builder.AddIterator(super_version->mem->NewIterator(
|
||||
read_opts, /*seqno_to_time_mapping=*/nullptr, &arena));
|
||||
super_version->imm->AddIterators(read_opts, /*seqno_to_time_mapping=*/nullptr,
|
||||
&merge_iter_builder,
|
||||
merge_iter_builder.AddIterator(
|
||||
super_version->mem->NewIterator(read_opts, &arena));
|
||||
super_version->imm->AddIterators(read_opts, &merge_iter_builder,
|
||||
false /* add_range_tombstone_iter */);
|
||||
ScopedArenaPtr<InternalIterator> memtable_iter(merge_iter_builder.Finish());
|
||||
ScopedArenaIterator memtable_iter(merge_iter_builder.Finish());
|
||||
|
||||
auto read_seq = super_version->current->version_set()->LastSequence();
|
||||
ReadRangeDelAggregator range_del_agg(&internal_comparator_, read_seq);
|
||||
@@ -1235,8 +1206,7 @@ Status ColumnFamilyData::RangesOverlapWithMemtables(
|
||||
|
||||
if (status.ok()) {
|
||||
if (memtable_iter->Valid() &&
|
||||
ucmp->CompareWithoutTimestamp(seek_result.user_key,
|
||||
ranges[i].limit) <= 0) {
|
||||
ucmp->Compare(seek_result.user_key, ranges[i].limit) <= 0) {
|
||||
*overlap = true;
|
||||
} else if (range_del_agg.IsRangeOverlapped(ranges[i].start,
|
||||
ranges[i].limit)) {
|
||||
@@ -1341,12 +1311,7 @@ void ColumnFamilyData::InstallSuperVersion(
|
||||
const MutableCFOptions& mutable_cf_options) {
|
||||
SuperVersion* new_superversion = sv_context->new_superversion.release();
|
||||
new_superversion->mutable_cf_options = mutable_cf_options;
|
||||
new_superversion->Init(this, mem_, imm_.current(), current_,
|
||||
sv_context->new_seqno_to_time_mapping
|
||||
? std::move(sv_context->new_seqno_to_time_mapping)
|
||||
: super_version_
|
||||
? super_version_->ShareSeqnoToTimeMapping()
|
||||
: nullptr);
|
||||
new_superversion->Init(this, mem_, imm_.current(), current_);
|
||||
SuperVersion* old_superversion = super_version_;
|
||||
super_version_ = new_superversion;
|
||||
if (old_superversion == nullptr || old_superversion->current != current() ||
|
||||
@@ -1529,20 +1494,6 @@ Status ColumnFamilyData::ValidateOptions(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cf_options.compaction_style == kCompactionStyleUniversal) {
|
||||
int max_read_amp = cf_options.compaction_options_universal.max_read_amp;
|
||||
if (max_read_amp < -1) {
|
||||
return Status::NotSupported(
|
||||
"CompactionOptionsUniversal::max_read_amp should be at least -1.");
|
||||
} else if (0 < max_read_amp &&
|
||||
max_read_amp < cf_options.level0_file_num_compaction_trigger) {
|
||||
return Status::NotSupported(
|
||||
"CompactionOptionsUniversal::max_read_amp limits the number of sorted"
|
||||
" runs but is smaller than the compaction trigger "
|
||||
"level0_file_num_compaction_trigger.");
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1622,19 +1573,6 @@ FSDirectory* ColumnFamilyData::GetDataDir(size_t path_id) const {
|
||||
return data_dirs_[path_id].get();
|
||||
}
|
||||
|
||||
void ColumnFamilyData::SetFlushSkipReschedule() {
|
||||
const Comparator* ucmp = user_comparator();
|
||||
const size_t ts_sz = ucmp->timestamp_size();
|
||||
if (ts_sz == 0 || ioptions_.persist_user_defined_timestamps) {
|
||||
return;
|
||||
}
|
||||
flush_skip_reschedule_.store(true);
|
||||
}
|
||||
|
||||
bool ColumnFamilyData::GetAndClearFlushSkipReschedule() {
|
||||
return flush_skip_reschedule_.exchange(false);
|
||||
}
|
||||
|
||||
bool ColumnFamilyData::ShouldPostponeFlushToRetainUDT(
|
||||
uint64_t max_memtable_id) {
|
||||
const Comparator* ucmp = user_comparator();
|
||||
|
||||
+28
-64
@@ -26,7 +26,6 @@
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "trace_replay/block_cache_tracer.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/hash_containers.h"
|
||||
#include "util/thread_local.h"
|
||||
|
||||
@@ -169,12 +168,11 @@ class ColumnFamilyHandleImpl : public ColumnFamilyHandle {
|
||||
// destroy without mutex
|
||||
virtual ~ColumnFamilyHandleImpl();
|
||||
virtual ColumnFamilyData* cfd() const { return cfd_; }
|
||||
virtual DBImpl* db() const { return db_; }
|
||||
|
||||
uint32_t GetID() const override;
|
||||
const std::string& GetName() const override;
|
||||
Status GetDescriptor(ColumnFamilyDescriptor* desc) override;
|
||||
const Comparator* GetComparator() const override;
|
||||
virtual uint32_t GetID() const override;
|
||||
virtual const std::string& GetName() const override;
|
||||
virtual Status GetDescriptor(ColumnFamilyDescriptor* desc) override;
|
||||
virtual const Comparator* GetComparator() const override;
|
||||
|
||||
private:
|
||||
ColumnFamilyData* cfd_;
|
||||
@@ -195,7 +193,7 @@ class ColumnFamilyHandleInternal : public ColumnFamilyHandleImpl {
|
||||
internal_cfd_(nullptr) {}
|
||||
|
||||
void SetCFD(ColumnFamilyData* _cfd) { internal_cfd_ = _cfd; }
|
||||
ColumnFamilyData* cfd() const override { return internal_cfd_; }
|
||||
virtual ColumnFamilyData* cfd() const override { return internal_cfd_; }
|
||||
|
||||
private:
|
||||
ColumnFamilyData* internal_cfd_;
|
||||
@@ -220,9 +218,6 @@ struct SuperVersion {
|
||||
// enable UDT feature, this is an empty string.
|
||||
std::string full_history_ts_low;
|
||||
|
||||
// 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
|
||||
SuperVersion() = default;
|
||||
~SuperVersion();
|
||||
@@ -236,23 +231,8 @@ struct SuperVersion {
|
||||
// that needs to be deleted in to_delete vector. Unrefing those
|
||||
// objects needs to be done in the mutex
|
||||
void Cleanup();
|
||||
void Init(
|
||||
ColumnFamilyData* new_cfd, MemTable* new_mem,
|
||||
MemTableListVersion* new_imm, Version* new_current,
|
||||
std::shared_ptr<const SeqnoToTimeMapping> new_seqno_to_time_mapping);
|
||||
|
||||
// Share the ownership of the seqno to time mapping object referred to in this
|
||||
// SuperVersion. To be used by the new SuperVersion to be installed after this
|
||||
// one if seqno to time mapping does not change in between these two
|
||||
// SuperVersions. Or to share the ownership of the mapping with a FlushJob.
|
||||
std::shared_ptr<const SeqnoToTimeMapping> ShareSeqnoToTimeMapping() {
|
||||
return seqno_to_time_mapping;
|
||||
}
|
||||
|
||||
// Access the seqno to time mapping object in this SuperVersion.
|
||||
UnownedPtr<const SeqnoToTimeMapping> GetSeqnoToTimeMapping() const {
|
||||
return seqno_to_time_mapping.get();
|
||||
}
|
||||
void Init(ColumnFamilyData* new_cfd, MemTable* new_mem,
|
||||
MemTableListVersion* new_imm, Version* new_current);
|
||||
|
||||
// The value of dummy is not actually used. kSVInUse takes its address as a
|
||||
// mark in the thread local storage to indicate the SuperVersion is in use
|
||||
@@ -271,21 +251,22 @@ struct SuperVersion {
|
||||
autovector<MemTable*> to_delete;
|
||||
};
|
||||
|
||||
Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options);
|
||||
extern Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options);
|
||||
|
||||
Status CheckConcurrentWritesSupported(const ColumnFamilyOptions& cf_options);
|
||||
extern Status CheckConcurrentWritesSupported(
|
||||
const ColumnFamilyOptions& cf_options);
|
||||
|
||||
Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
const ColumnFamilyOptions& cf_options);
|
||||
extern Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
const ColumnFamilyOptions& cf_options);
|
||||
|
||||
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
const ColumnFamilyOptions& src);
|
||||
extern 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
|
||||
// into internal ones in int_tbl_prop_collector_factories. Add a system internal
|
||||
// one too.
|
||||
void GetInternalTblPropCollFactory(
|
||||
extern void GetIntTblPropCollectorFactory(
|
||||
const ImmutableCFOptions& ioptions,
|
||||
InternalTblPropCollFactories* internal_tbl_prop_coll_factories);
|
||||
IntTblPropCollectorFactories* int_tbl_prop_collector_factories);
|
||||
|
||||
class ColumnFamilySet;
|
||||
|
||||
@@ -329,10 +310,6 @@ class ColumnFamilyData {
|
||||
void SetDropped();
|
||||
bool IsDropped() const { return dropped_.load(std::memory_order_relaxed); }
|
||||
|
||||
void SetFlushSkipReschedule();
|
||||
|
||||
bool GetAndClearFlushSkipReschedule();
|
||||
|
||||
// thread-safe
|
||||
int NumberLevels() const { return ioptions_.num_levels; }
|
||||
|
||||
@@ -401,7 +378,6 @@ class ColumnFamilyData {
|
||||
SequenceNumber earliest_seq);
|
||||
|
||||
TableCache* table_cache() const { return table_cache_.get(); }
|
||||
BlobFileCache* blob_file_cache() const { return blob_file_cache_.get(); }
|
||||
BlobSource* blob_source() const { return blob_source_.get(); }
|
||||
|
||||
// See documentation in compaction_picker.h
|
||||
@@ -425,7 +401,7 @@ class ColumnFamilyData {
|
||||
// duration of this function.
|
||||
//
|
||||
// Thread-safe
|
||||
Status RangesOverlapWithMemtables(const autovector<UserKeyRange>& ranges,
|
||||
Status RangesOverlapWithMemtables(const autovector<Range>& ranges,
|
||||
SuperVersion* super_version,
|
||||
bool allow_data_in_errors, bool* overlap);
|
||||
|
||||
@@ -454,8 +430,8 @@ class ColumnFamilyData {
|
||||
return internal_comparator_;
|
||||
}
|
||||
|
||||
const InternalTblPropCollFactories* internal_tbl_prop_coll_factories() const {
|
||||
return &internal_tbl_prop_coll_factories_;
|
||||
const IntTblPropCollectorFactories* int_tbl_prop_collector_factories() const {
|
||||
return &int_tbl_prop_collector_factories_;
|
||||
}
|
||||
|
||||
SuperVersion* GetSuperVersion() { return super_version_; }
|
||||
@@ -573,10 +549,6 @@ class ColumnFamilyData {
|
||||
// of its files (if missing)
|
||||
void RecoverEpochNumbers();
|
||||
|
||||
int GetUnflushedMemTableCountForWriteStallCheck() const {
|
||||
return (mem_->IsEmpty() ? 0 : 1) + imm_.NumNotFlushed();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ColumnFamilySet;
|
||||
ColumnFamilyData(uint32_t id, const std::string& name,
|
||||
@@ -601,17 +573,8 @@ class ColumnFamilyData {
|
||||
std::atomic<bool> initialized_;
|
||||
std::atomic<bool> dropped_; // true if client dropped it
|
||||
|
||||
// When user-defined timestamps in memtable only feature is enabled, this
|
||||
// flag indicates a successfully requested flush that should
|
||||
// skip being rescheduled and haven't undergone the rescheduling check yet.
|
||||
// This flag is cleared when a check skips rescheduling a FlushRequest.
|
||||
// With this flag, automatic flushes in regular cases can continue to
|
||||
// retain UDTs by getting rescheduled as usual while manual flushes and
|
||||
// error recovery flushes will proceed without getting rescheduled.
|
||||
std::atomic<bool> flush_skip_reschedule_;
|
||||
|
||||
const InternalKeyComparator internal_comparator_;
|
||||
InternalTblPropCollFactories internal_tbl_prop_coll_factories_;
|
||||
IntTblPropCollectorFactories int_tbl_prop_collector_factories_;
|
||||
|
||||
const ColumnFamilyOptions initial_cf_options_;
|
||||
const ImmutableOptions ioptions_;
|
||||
@@ -891,17 +854,17 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
|
||||
// REQUIRES: Seek() called first
|
||||
// REQUIRES: use this function of DBImpl::column_family_memtables_ should be
|
||||
// under a DB mutex OR from a write thread
|
||||
MemTable* GetMemTable() const override;
|
||||
virtual MemTable* GetMemTable() const override;
|
||||
|
||||
// Returns column family handle for the selected column family
|
||||
// REQUIRES: use this function of DBImpl::column_family_memtables_ should be
|
||||
// under a DB mutex OR from a write thread
|
||||
ColumnFamilyHandle* GetColumnFamilyHandle() override;
|
||||
virtual ColumnFamilyHandle* GetColumnFamilyHandle() override;
|
||||
|
||||
// Cannot be called while another thread is calling Seek().
|
||||
// REQUIRES: use this function of DBImpl::column_family_memtables_ should be
|
||||
// under a DB mutex OR from a write thread
|
||||
ColumnFamilyData* current() override { return current_; }
|
||||
virtual ColumnFamilyData* current() override { return current_; }
|
||||
|
||||
private:
|
||||
ColumnFamilySet* column_family_set_;
|
||||
@@ -909,11 +872,12 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
|
||||
ColumnFamilyHandleInternal handle_;
|
||||
};
|
||||
|
||||
uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
|
||||
extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
|
||||
|
||||
const Comparator* GetColumnFamilyUserComparator(
|
||||
extern const Comparator* GetColumnFamilyUserComparator(
|
||||
ColumnFamilyHandle* column_family);
|
||||
|
||||
const ImmutableOptions& GetImmutableOptions(ColumnFamilyHandle* column_family);
|
||||
extern const ImmutableOptions& GetImmutableOptions(
|
||||
ColumnFamilyHandle* column_family);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+109
-376
@@ -23,7 +23,6 @@
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/listener.h"
|
||||
#include "rocksdb/utilities/object_registry.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testharness.h"
|
||||
@@ -35,13 +34,6 @@
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
std::string EncodeAsUint64(uint64_t number) {
|
||||
std::string result;
|
||||
PutFixed64(&result, number);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static const int kValueSize = 1000;
|
||||
|
||||
@@ -278,7 +270,7 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
|
||||
void Reopen(const std::vector<ColumnFamilyOptions> options = {}) {
|
||||
std::vector<std::string> names;
|
||||
for (const auto& name : names_) {
|
||||
for (auto name : names_) {
|
||||
if (name != "") {
|
||||
names.push_back(name);
|
||||
}
|
||||
@@ -615,7 +607,7 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest) {
|
||||
// Preserve file system state up to here to simulate a crash condition.
|
||||
fault_env->SetFilesystemActive(false);
|
||||
std::vector<std::string> names;
|
||||
for (const auto& name : names_) {
|
||||
for (auto name : names_) {
|
||||
if (name != "") {
|
||||
names.push_back(name);
|
||||
}
|
||||
@@ -677,7 +669,7 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest2) {
|
||||
// Preserve file system state up to here to simulate a crash condition.
|
||||
fault_env->SetFilesystemActive(false);
|
||||
std::vector<std::string> names;
|
||||
for (const auto& name : names_) {
|
||||
for (auto name : names_) {
|
||||
if (name != "") {
|
||||
names.push_back(name);
|
||||
}
|
||||
@@ -1042,7 +1034,7 @@ TEST_P(ColumnFamilyTest, CrashAfterFlush) {
|
||||
fault_env->SetFilesystemActive(false);
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (const auto& name : names_) {
|
||||
for (auto name : names_) {
|
||||
if (name != "") {
|
||||
names.push_back(name);
|
||||
}
|
||||
@@ -2612,92 +2604,90 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit = 2000;
|
||||
mutable_cf_options.disable_auto_compactions = false;
|
||||
|
||||
auto dbmu = dbfull()->TEST_Mutex();
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(201, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(201);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(400, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(400);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25 / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(450, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(450);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(205, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(205);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(202, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(202);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(201, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(201);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(198, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(198);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(399, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(399);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(599, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(599);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(2001, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(2001);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(3001, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(3001);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(390, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(390);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(100, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(100);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2716,7 +2706,7 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->set_l0_delay_trigger_count(0);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2728,14 +2718,14 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25 / 1.25 / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(200, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(200);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25 / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->set_l0_delay_trigger_count(0);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(0, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(0);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2754,7 +2744,7 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
|
||||
ASSERT_EQ(kBaseRate, dbfull()->TEST_write_controler().delayed_write_rate());
|
||||
|
||||
vstorage->set_l0_delay_trigger_count(60);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2763,14 +2753,14 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
|
||||
|
||||
mutable_cf_options.disable_auto_compactions = false;
|
||||
vstorage->set_l0_delay_trigger_count(70);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->set_l0_delay_trigger_count(71);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(501, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(501);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2795,21 +2785,19 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit = 200;
|
||||
mutable_cf_options.hard_pending_compaction_bytes_limit = 2000;
|
||||
|
||||
auto dbmu = dbfull()->TEST_Mutex();
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(40, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(40);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(45, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(45);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
@@ -2865,55 +2853,53 @@ TEST_P(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
|
||||
MutableCFOptions mutable_cf_options1 = mutable_cf_options;
|
||||
mutable_cf_options1.soft_pending_compaction_bytes_limit = 500;
|
||||
|
||||
auto dbmu = dbfull()->TEST_Mutex();
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(50);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(201, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(201);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(!dbfull()->TEST_write_controler().NeedsDelay());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(600, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(600);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(70, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(70);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(800, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(800);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(300);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25 / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(700, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(700);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(500);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
ASSERT_EQ(kBaseRate / 1.25 / 1.25, GetDbDelayedWriteRate());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(600, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(600);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_TRUE(!IsDbWriteStopped());
|
||||
ASSERT_TRUE(dbfull()->TEST_write_controler().NeedsDelay());
|
||||
@@ -2946,31 +2932,29 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
|
||||
MutableCFOptions mutable_cf_options1 = mutable_cf_options;
|
||||
mutable_cf_options1.level0_slowdown_writes_trigger = 16;
|
||||
|
||||
auto dbmu = dbfull()->TEST_Mutex();
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(40, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(40);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(60, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(60);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(30, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(30);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(70, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(70);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(20, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(20);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(3, dbmu);
|
||||
vstorage1->TEST_set_estimated_compaction_needed_bytes(3);
|
||||
RecalculateWriteStallConditions(cfd1, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
@@ -2996,13 +2980,10 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupForCompactionDebt) {
|
||||
mutable_cf_options.soft_pending_compaction_bytes_limit =
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
|
||||
auto dbmu = dbfull()->TEST_Mutex();
|
||||
|
||||
{
|
||||
// No bottommost data, so debt ratio cannot trigger speedup.
|
||||
VersionStorageInfo* vstorage = cfd->current()->storage_info();
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(1048576 /* 1MB */,
|
||||
dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(1048576 /* 1MB */);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
}
|
||||
@@ -3015,96 +2996,18 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupForCompactionDebt) {
|
||||
// 1MB debt is way bigger than bottommost data so definitely triggers
|
||||
// speedup.
|
||||
VersionStorageInfo* vstorage = cfd->current()->storage_info();
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(1048576 /* 1MB */,
|
||||
dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(1048576 /* 1MB */);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(6, dbfull()->TEST_BGCompactionsAllowed());
|
||||
|
||||
// Eight bytes is way smaller than bottommost data so definitely does not
|
||||
// trigger speedup.
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(8, dbmu);
|
||||
vstorage->TEST_set_estimated_compaction_needed_bytes(8);
|
||||
RecalculateWriteStallConditions(cfd, mutable_cf_options);
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, CompactionSpeedupForMarkedFiles) {
|
||||
const int kParallelismLimit = 3;
|
||||
class AlwaysCompactTpc : public TablePropertiesCollector {
|
||||
public:
|
||||
Status Finish(UserCollectedProperties* /* properties */) override {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
UserCollectedProperties GetReadableProperties() const override {
|
||||
return UserCollectedProperties{};
|
||||
}
|
||||
|
||||
const char* Name() const override { return "AlwaysCompactTpc"; }
|
||||
|
||||
bool NeedCompact() const override { return true; }
|
||||
};
|
||||
|
||||
class AlwaysCompactTpcf : public TablePropertiesCollectorFactory {
|
||||
public:
|
||||
TablePropertiesCollector* CreateTablePropertiesCollector(
|
||||
TablePropertiesCollectorFactory::Context /* context */) override {
|
||||
return new AlwaysCompactTpc();
|
||||
}
|
||||
|
||||
const char* Name() const override { return "AlwaysCompactTpcf"; }
|
||||
};
|
||||
|
||||
column_family_options_.num_levels = 2;
|
||||
column_family_options_.table_properties_collector_factories.emplace_back(
|
||||
std::make_shared<AlwaysCompactTpcf>());
|
||||
db_options_.max_background_compactions = kParallelismLimit;
|
||||
Open();
|
||||
|
||||
// Make a nonempty last level. Only marked files in upper levels count.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
WaitForCompaction();
|
||||
AssertFilesPerLevel("0,1", 0 /* cf */);
|
||||
|
||||
// We should calculate the limit by obtaining the number of env background
|
||||
// threads, because the current test case will share the same env
|
||||
// with another case that may have already increased the number of
|
||||
// background threads which is larger than kParallelismLimit
|
||||
const auto limit = env_->GetBackgroundThreads(Env::Priority::LOW);
|
||||
|
||||
// Block the compaction thread pool so marked files accumulate in L0.
|
||||
std::vector<std::shared_ptr<test::SleepingBackgroundTask>> sleeping_tasks;
|
||||
for (int i = 0; i < limit; i++) {
|
||||
sleeping_tasks.emplace_back(
|
||||
std::make_shared<test::SleepingBackgroundTask>());
|
||||
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask,
|
||||
sleeping_tasks[i].get(), Env::Priority::LOW);
|
||||
sleeping_tasks[i]->WaitUntilSleeping();
|
||||
}
|
||||
|
||||
// Zero marked upper-level files. No speedup.
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
AssertFilesPerLevel("0,1", 0 /* cf */);
|
||||
|
||||
// One marked upper-level file. No speedup.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
|
||||
AssertFilesPerLevel("1,1", 0 /* cf */);
|
||||
|
||||
// Two marked upper-level files. Speedup.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "foo", "bar"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
ASSERT_EQ(kParallelismLimit, dbfull()->TEST_BGCompactionsAllowed());
|
||||
AssertFilesPerLevel("2,1", 0 /* cf */);
|
||||
|
||||
for (int i = 0; i < limit; i++) {
|
||||
sleeping_tasks[i]->WakeUp();
|
||||
sleeping_tasks[i]->WaitUntilDone();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, CreateAndDestroyOptions) {
|
||||
std::unique_ptr<ColumnFamilyOptions> cfo(new ColumnFamilyOptions());
|
||||
ColumnFamilyHandle* cfh;
|
||||
@@ -3186,8 +3089,6 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
|
||||
SpecialEnv env(Env::Default());
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
// When this option is removed, the test will need re-engineering
|
||||
db_options_.background_close_inactive_wals = true;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2));
|
||||
Open();
|
||||
@@ -3240,8 +3141,6 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
|
||||
env.SetBackgroundThreads(2, Env::HIGH);
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
// When this option is removed, the test will need re-engineering
|
||||
db_options_.background_close_inactive_wals = true;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2));
|
||||
Open();
|
||||
@@ -3299,8 +3198,6 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
env.SetBackgroundThreads(2, Env::HIGH);
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
// When this option is removed, the test will need re-engineering
|
||||
db_options_.background_close_inactive_wals = true;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(3));
|
||||
column_family_options_.level0_file_num_compaction_trigger = 2;
|
||||
@@ -3429,13 +3326,9 @@ TEST_P(ColumnFamilyTest, DISABLED_LogTruncationTest) {
|
||||
for (size_t i = 0; i < filenames.size(); i++) {
|
||||
uint64_t number;
|
||||
FileType type;
|
||||
if (!(ParseFileName(filenames[i], &number, &type))) {
|
||||
continue;
|
||||
}
|
||||
if (!(ParseFileName(filenames[i], &number, &type))) continue;
|
||||
|
||||
if (type != kWalFile) {
|
||||
continue;
|
||||
}
|
||||
if (type != kWalFile) continue;
|
||||
|
||||
logfs.push_back(filenames[i]);
|
||||
}
|
||||
@@ -3625,9 +3518,7 @@ TEST(ColumnFamilyTest, ValidateMemtableKVChecksumOption) {
|
||||
}
|
||||
|
||||
// Tests the flushing behavior of a column family to retain user-defined
|
||||
// timestamp when `persist_user_defined_timestamp` is false. The behavior of
|
||||
// auto flush is it makes some effort to retain user-defined timestamps while
|
||||
// the behavior of manual flush is that it skips retaining UDTs.
|
||||
// timestamp when `persist_user_defined_timestamp` is false.
|
||||
class ColumnFamilyRetainUDTTest : public ColumnFamilyTestBase {
|
||||
public:
|
||||
ColumnFamilyRetainUDTTest() : ColumnFamilyTestBase(kLatestFormatVersion) {}
|
||||
@@ -3645,27 +3536,6 @@ class ColumnFamilyRetainUDTTest : public ColumnFamilyTestBase {
|
||||
return db_->Put(WriteOptions(), handles_[cf], Slice(key), Slice(ts),
|
||||
Slice(value));
|
||||
}
|
||||
|
||||
std::string Get(int cf, const std::string& key, const std::string& read_ts) {
|
||||
ReadOptions ropts;
|
||||
Slice timestamp = read_ts;
|
||||
ropts.timestamp = ×tamp;
|
||||
std::string value;
|
||||
Status s = db_->Get(ropts, handles_[cf], Slice(key), &value);
|
||||
if (s.IsNotFound()) {
|
||||
return "NOT_FOUND";
|
||||
} else if (s.ok()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CheckEffectiveCutoffTime(uint64_t expected_cutoff) {
|
||||
std::string effective_full_history_ts_low;
|
||||
EXPECT_OK(
|
||||
db_->GetFullHistoryTsLow(handles_[0], &effective_full_history_ts_low));
|
||||
EXPECT_EQ(EncodeAsUint64(expected_cutoff), effective_full_history_ts_low);
|
||||
}
|
||||
};
|
||||
|
||||
class TestTsComparator : public Comparator {
|
||||
@@ -3709,9 +3579,7 @@ TEST_F(ColumnFamilyRetainUDTTest, SanityCheck) {
|
||||
Close();
|
||||
}
|
||||
|
||||
class AutoFlushRetainUDTTest : public ColumnFamilyRetainUDTTest {};
|
||||
|
||||
TEST_F(AutoFlushRetainUDTTest, FullHistoryTsLowNotSet) {
|
||||
TEST_F(ColumnFamilyRetainUDTTest, FullHistoryTsLowNotSet) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundFlush:CheckFlushRequest:cb", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
@@ -3721,22 +3589,28 @@ TEST_F(AutoFlushRetainUDTTest, FullHistoryTsLowNotSet) {
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Open();
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
// No `full_history_ts_low` explicitly set by user, auto flush is continued
|
||||
std::string write_ts;
|
||||
PutFixed64(&write_ts, 1);
|
||||
ASSERT_OK(Put(0, "foo", write_ts, "v1"));
|
||||
// No `full_history_ts_low` explicitly set by user, flush is continued
|
||||
// without checking if its UDTs expired.
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(Flush(0));
|
||||
|
||||
// After flush, `full_history_ts_low` should be automatically advanced to
|
||||
// the effective cutoff timestamp: write_ts + 1
|
||||
CheckEffectiveCutoffTime(2);
|
||||
std::string cutoff_ts;
|
||||
PutFixed64(&cutoff_ts, 2);
|
||||
std::string effective_full_history_ts_low;
|
||||
ASSERT_OK(
|
||||
db_->GetFullHistoryTsLow(handles_[0], &effective_full_history_ts_low));
|
||||
ASSERT_EQ(cutoff_ts, effective_full_history_ts_low);
|
||||
Close();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_F(AutoFlushRetainUDTTest, AllKeysExpired) {
|
||||
TEST_F(ColumnFamilyRetainUDTTest, AllKeysExpired) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundFlush:CheckFlushRequest:cb", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
@@ -3746,22 +3620,27 @@ TEST_F(AutoFlushRetainUDTTest, AllKeysExpired) {
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Open();
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(3)));
|
||||
// All keys expired w.r.t the configured `full_history_ts_low`, auto flush
|
||||
// continue without the need for a re-schedule.
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
std::string write_ts;
|
||||
PutFixed64(&write_ts, 1);
|
||||
ASSERT_OK(Put(0, "foo", write_ts, "v1"));
|
||||
std::string cutoff_ts;
|
||||
PutFixed64(&cutoff_ts, 3);
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], cutoff_ts));
|
||||
// All keys expired w.r.t the configured `full_history_ts_low`, flush continue
|
||||
// without the need for a re-schedule.
|
||||
ASSERT_OK(Flush(0));
|
||||
|
||||
// `full_history_ts_low` stays unchanged after flush.
|
||||
CheckEffectiveCutoffTime(3);
|
||||
std::string effective_full_history_ts_low;
|
||||
ASSERT_OK(
|
||||
db_->GetFullHistoryTsLow(handles_[0], &effective_full_history_ts_low));
|
||||
ASSERT_EQ(cutoff_ts, effective_full_history_ts_low);
|
||||
Close();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_F(AutoFlushRetainUDTTest, NotAllKeysExpiredFlushToAvoidWriteStall) {
|
||||
TEST_F(ColumnFamilyRetainUDTTest, NotAllKeysExpiredFlushToAvoidWriteStall) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundFlush:CheckFlushRequest:cb", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
@@ -3771,218 +3650,72 @@ TEST_F(AutoFlushRetainUDTTest, NotAllKeysExpiredFlushToAvoidWriteStall) {
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Open();
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(1)));
|
||||
std::string cutoff_ts;
|
||||
std::string write_ts;
|
||||
PutFixed64(&write_ts, 1);
|
||||
ASSERT_OK(Put(0, "foo", write_ts, "v1"));
|
||||
PutFixed64(&cutoff_ts, 1);
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], cutoff_ts));
|
||||
ASSERT_OK(db_->SetOptions(handles_[0], {{"max_write_buffer_number", "1"}}));
|
||||
// Not all keys expired, but auto flush is continued without a re-schedule
|
||||
// because of risk of write stall.
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
// Not all keys expired, but flush is continued without a re-schedule because
|
||||
// of risk of write stall.
|
||||
ASSERT_OK(Flush(0));
|
||||
|
||||
// After flush, `full_history_ts_low` should be automatically advanced to
|
||||
// the effective cutoff timestamp: write_ts + 1
|
||||
CheckEffectiveCutoffTime(2);
|
||||
std::string effective_full_history_ts_low;
|
||||
ASSERT_OK(
|
||||
db_->GetFullHistoryTsLow(handles_[0], &effective_full_history_ts_low));
|
||||
|
||||
cutoff_ts.clear();
|
||||
PutFixed64(&cutoff_ts, 2);
|
||||
ASSERT_EQ(cutoff_ts, effective_full_history_ts_low);
|
||||
Close();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_F(AutoFlushRetainUDTTest, NotAllKeysExpiredFlushRescheduled) {
|
||||
std::atomic<int> local_counter{1};
|
||||
TEST_F(ColumnFamilyRetainUDTTest, NotAllKeysExpiredFlushRescheduled) {
|
||||
std::string cutoff_ts;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::AfterRetainUDTReschedule:cb", [&](void* /*arg*/) {
|
||||
// Increasing full_history_ts_low so all keys expired after the initial
|
||||
// FlushRequest is rescheduled
|
||||
ASSERT_OK(
|
||||
db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(3)));
|
||||
cutoff_ts.clear();
|
||||
PutFixed64(&cutoff_ts, 3);
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], cutoff_ts));
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundFlush:CheckFlushRequest:cb", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
auto reschedule_count = *static_cast<int*>(arg);
|
||||
ASSERT_EQ(2, reschedule_count);
|
||||
local_counter.fetch_add(1);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Open();
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(1)));
|
||||
std::string write_ts;
|
||||
PutFixed64(&write_ts, 1);
|
||||
ASSERT_OK(Put(0, "foo", write_ts, "v1"));
|
||||
PutFixed64(&cutoff_ts, 1);
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], cutoff_ts));
|
||||
// Not all keys expired, and there is no risk of write stall. Flush is
|
||||
// rescheduled. The actual flush happens after `full_history_ts_low` is
|
||||
// increased to mark all keys expired.
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
// Make sure callback is not skipped.
|
||||
ASSERT_EQ(2, local_counter);
|
||||
ASSERT_OK(Flush(0));
|
||||
|
||||
CheckEffectiveCutoffTime(3);
|
||||
std::string effective_full_history_ts_low;
|
||||
ASSERT_OK(
|
||||
db_->GetFullHistoryTsLow(handles_[0], &effective_full_history_ts_low));
|
||||
// `full_history_ts_low` stays unchanged.
|
||||
ASSERT_EQ(cutoff_ts, effective_full_history_ts_low);
|
||||
Close();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
class ManualFlushSkipRetainUDTTest : public ColumnFamilyRetainUDTTest {
|
||||
public:
|
||||
// Write an entry with timestamp that is not expired w.r.t cutoff timestamp,
|
||||
// and make sure automatic flush would be rescheduled to retain UDT.
|
||||
void CheckAutomaticFlushRetainUDT(uint64_t write_ts) {
|
||||
std::atomic<int> local_counter{1};
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::AfterRetainUDTReschedule:cb", [&](void* /*arg*/) {
|
||||
// Increasing full_history_ts_low so all keys expired after the
|
||||
// initial FlushRequest is rescheduled
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(
|
||||
handles_[0], EncodeAsUint64(write_ts + 1)));
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundFlush:CheckFlushRequest:cb", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
auto reschedule_count = *static_cast<int*>(arg);
|
||||
ASSERT_EQ(2, reschedule_count);
|
||||
local_counter.fetch_add(1);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
EXPECT_OK(Put(0, "foo", EncodeAsUint64(write_ts),
|
||||
"foo" + std::to_string(write_ts)));
|
||||
EXPECT_OK(dbfull()->TEST_SwitchWAL());
|
||||
EXPECT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
// Make sure callback is not skipped.
|
||||
EXPECT_EQ(2, local_counter);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ManualFlushSkipRetainUDTTest, ManualFlush) {
|
||||
Open();
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(0)));
|
||||
|
||||
// Manual flush proceeds without trying to retain UDT.
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
ASSERT_OK(Flush(0));
|
||||
CheckEffectiveCutoffTime(2);
|
||||
CheckAutomaticFlushRetainUDT(3);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(ManualFlushSkipRetainUDTTest, ManualCompaction) {
|
||||
Open();
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(0)));
|
||||
|
||||
// Manual compaction proceeds without trying to retain UDT.
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v2"));
|
||||
ASSERT_OK(
|
||||
db_->CompactRange(CompactRangeOptions(), handles_[0], nullptr, nullptr));
|
||||
CheckEffectiveCutoffTime(2);
|
||||
CheckAutomaticFlushRetainUDT(3);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(ManualFlushSkipRetainUDTTest, BulkLoading) {
|
||||
Open();
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(0)));
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
|
||||
// Test flush behavior in bulk loading scenarios.
|
||||
Options options(db_options_, column_family_options_);
|
||||
std::string sst_files_dir = dbname_ + "/sst_files/";
|
||||
ASSERT_OK(DestroyDir(env_, sst_files_dir));
|
||||
ASSERT_OK(env_->CreateDir(sst_files_dir));
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options);
|
||||
std::string file1 = sst_files_dir + "file1.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(file1));
|
||||
ASSERT_OK(sst_file_writer.Put("foo", EncodeAsUint64(0), "v2"));
|
||||
ExternalSstFileInfo file1_info;
|
||||
ASSERT_OK(sst_file_writer.Finish(&file1_info));
|
||||
|
||||
// Bulk loading in UDT mode doesn't support external file key range overlap
|
||||
// with DB key range.
|
||||
ASSERT_TRUE(db_->IngestExternalFile({file1}, IngestExternalFileOptions())
|
||||
.IsInvalidArgument());
|
||||
|
||||
std::string file2 = sst_files_dir + "file2.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(file2));
|
||||
ASSERT_OK(sst_file_writer.Put("bar", EncodeAsUint64(0), "val"));
|
||||
ExternalSstFileInfo file2_info;
|
||||
ASSERT_OK(sst_file_writer.Finish(&file2_info));
|
||||
// A successful bulk loading, and it doesn't trigger any flush. As a result
|
||||
// the effective cutoff timestamp is also unchanged.
|
||||
ASSERT_OK(db_->IngestExternalFile({file2}, IngestExternalFileOptions()));
|
||||
|
||||
ASSERT_EQ(Get(0, "foo", EncodeAsUint64(1)), "v1");
|
||||
ASSERT_EQ(Get(0, "bar", EncodeAsUint64(0)), "val");
|
||||
CheckEffectiveCutoffTime(0);
|
||||
CheckAutomaticFlushRetainUDT(1);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(ManualFlushSkipRetainUDTTest, AutomaticFlushQueued) {
|
||||
Open();
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(0)));
|
||||
|
||||
ASSERT_OK(Put(0, "foo", EncodeAsUint64(1), "v1"));
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
CheckEffectiveCutoffTime(0);
|
||||
|
||||
// Default `max_write_buffer_number=2` used, writing another memtable can get
|
||||
// automatic flush to proceed because of memory pressure. Not doing that so
|
||||
// we can test automatic flush gets to proceed because of an ongoing manual
|
||||
// flush attempt.
|
||||
ASSERT_OK(Flush(0));
|
||||
CheckEffectiveCutoffTime(2);
|
||||
CheckAutomaticFlushRetainUDT(3);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(ManualFlushSkipRetainUDTTest, ConcurrentManualFlushes) {
|
||||
Open();
|
||||
ASSERT_OK(db_->IncreaseFullHistoryTsLow(handles_[0], EncodeAsUint64(0)));
|
||||
|
||||
std::vector<ROCKSDB_NAMESPACE::port::Thread> manual_flush_tds;
|
||||
std::atomic<int> next_ts{0};
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
|
||||
auto manual_flush = [&](int write_ts) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait(lock,
|
||||
[&write_ts, &next_ts] { return write_ts == next_ts.load(); });
|
||||
ASSERT_OK(Put(0, "foo" + std::to_string(write_ts),
|
||||
EncodeAsUint64(write_ts),
|
||||
"val_" + std::to_string(write_ts)));
|
||||
next_ts.fetch_add(1);
|
||||
cv.notify_all();
|
||||
}
|
||||
if (write_ts % 2 == 0) {
|
||||
ASSERT_OK(Flush(0));
|
||||
} else {
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), handles_[0], nullptr,
|
||||
nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
for (int write_ts = 0; write_ts < 10; write_ts++) {
|
||||
manual_flush_tds.emplace_back(manual_flush, write_ts);
|
||||
}
|
||||
|
||||
for (auto& td : manual_flush_tds) {
|
||||
td.join();
|
||||
}
|
||||
|
||||
CheckEffectiveCutoffTime(10);
|
||||
CheckAutomaticFlushRetainUDT(11);
|
||||
Close();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -34,8 +34,8 @@ class CompactFilesTest : public testing::Test {
|
||||
// A class which remembers the name of each flushed file.
|
||||
class FlushedFileCollector : public EventListener {
|
||||
public:
|
||||
FlushedFileCollector() = default;
|
||||
~FlushedFileCollector() override = default;
|
||||
FlushedFileCollector() {}
|
||||
~FlushedFileCollector() override {}
|
||||
|
||||
void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@@ -45,7 +45,7 @@ class FlushedFileCollector : public EventListener {
|
||||
std::vector<std::string> GetFlushedFiles() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<std::string> result;
|
||||
for (const auto& fname : flushed_files_) {
|
||||
for (auto fname : flushed_files_) {
|
||||
result.push_back(fname);
|
||||
}
|
||||
return result;
|
||||
@@ -159,9 +159,7 @@ TEST_F(CompactFilesTest, MultipleLevel) {
|
||||
// Compact files except the file in L3
|
||||
std::vector<std::string> files;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
if (i == 3) {
|
||||
continue;
|
||||
}
|
||||
if (i == 3) continue;
|
||||
for (auto& file : meta.levels[i].files) {
|
||||
files.push_back(file.db_path + "/" + file.name);
|
||||
}
|
||||
@@ -230,7 +228,7 @@ TEST_F(CompactFilesTest, ObsoleteFiles) {
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForCompact());
|
||||
|
||||
// verify all compaction input files are deleted
|
||||
for (const auto& fname : l0_files) {
|
||||
for (auto fname : l0_files) {
|
||||
ASSERT_EQ(Status::NotFound(), env_->FileExists(fname));
|
||||
}
|
||||
delete db;
|
||||
@@ -441,50 +439,6 @@ TEST_F(CompactFilesTest, SentinelCompressionType) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactFilesTest, CompressionWithBlockAlign) {
|
||||
Options options;
|
||||
options.compression = CompressionType::kNoCompression;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
|
||||
std::shared_ptr<FlushedFileCollector> collector =
|
||||
std::make_shared<FlushedFileCollector>();
|
||||
options.listeners.push_back(collector);
|
||||
|
||||
{
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.block_align = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
}
|
||||
|
||||
std::unique_ptr<DB> db;
|
||||
{
|
||||
DB* _db = nullptr;
|
||||
ASSERT_OK(DB::Open(options, db_name_, &_db));
|
||||
db.reset(_db);
|
||||
}
|
||||
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Ensure background work is fully finished including listener callbacks
|
||||
// before accessing listener state.
|
||||
ASSERT_OK(
|
||||
static_cast_with_check<DBImpl>(db.get())->TEST_WaitForBackgroundWork());
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
ASSERT_EQ(1, l0_files.size());
|
||||
|
||||
// We can run this test even without Snappy support because we expect the
|
||||
// `CompactFiles()` to fail before actually invoking Snappy compression.
|
||||
CompactionOptions compaction_opts;
|
||||
compaction_opts.compression = CompressionType::kSnappyCompression;
|
||||
ASSERT_TRUE(db->CompactFiles(compaction_opts, l0_files, 1 /* output_level */)
|
||||
.IsInvalidArgument());
|
||||
|
||||
compaction_opts.compression = CompressionType::kDisableCompressionOption;
|
||||
ASSERT_OK(db->CompactFiles(compaction_opts, l0_files, 1 /* output_level */));
|
||||
}
|
||||
|
||||
TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
@@ -538,3 +492,4 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
+11
-18
@@ -13,7 +13,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "db/column_family.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "logging/logging.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
#include "rocksdb/sst_partitioner.h"
|
||||
@@ -22,6 +21,9 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
const uint64_t kRangeTombstoneSentinel =
|
||||
PackSequenceAndType(kMaxSequenceNumber, kTypeRangeDeletion);
|
||||
|
||||
int sstableKeyCompare(const Comparator* uc, const Slice& a, const Slice& b) {
|
||||
auto c = uc->CompareWithoutTimestamp(ExtractUserKey(a), ExtractUserKey(b));
|
||||
if (c != 0) {
|
||||
@@ -63,9 +65,7 @@ uint64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
|
||||
return sum;
|
||||
}
|
||||
|
||||
// TODO(hx235): consider making this function part of the construction so we
|
||||
// don't forget to call it
|
||||
void Compaction::FinalizeInputInfo(Version* _input_version) {
|
||||
void Compaction::SetInputVersion(Version* _input_version) {
|
||||
input_version_ = _input_version;
|
||||
cfd_ = input_version_->cfd();
|
||||
|
||||
@@ -162,9 +162,7 @@ std::vector<CompactionInputFiles> Compaction::PopulateWithAtomicBoundaries(
|
||||
AtomicCompactionUnitBoundary cur_boundary;
|
||||
size_t first_atomic_idx = 0;
|
||||
auto add_unit_boundary = [&](size_t to) {
|
||||
if (first_atomic_idx == to) {
|
||||
return;
|
||||
}
|
||||
if (first_atomic_idx == to) return;
|
||||
for (size_t k = first_atomic_idx; k < to; k++) {
|
||||
inputs[i].atomic_compaction_unit_boundaries.push_back(cur_boundary);
|
||||
}
|
||||
@@ -354,9 +352,11 @@ Compaction::Compaction(
|
||||
|
||||
// for the non-bottommost levels, it tries to build files match the target
|
||||
// file size, but not guaranteed. It could be 2x the size of the target size.
|
||||
max_output_file_size_ = bottommost_level_ || grandparents_.empty()
|
||||
? target_output_file_size_
|
||||
: 2 * target_output_file_size_;
|
||||
max_output_file_size_ =
|
||||
bottommost_level_ || grandparents_.empty() ||
|
||||
!_immutable_options.level_compaction_dynamic_file_size
|
||||
? target_output_file_size_
|
||||
: 2 * target_output_file_size_;
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 1; i < inputs_.size(); ++i) {
|
||||
@@ -757,9 +757,7 @@ int InputSummary(const std::vector<FileMetaData*>& files, char* output,
|
||||
AppendHumanBytes(files.at(i)->fd.GetFileSize(), sztxt, 16);
|
||||
ret = snprintf(output + write, sz, "%" PRIu64 "(%s) ",
|
||||
files.at(i)->fd.GetNumber(), sztxt);
|
||||
if (ret < 0 || ret >= sz) {
|
||||
break;
|
||||
}
|
||||
if (ret < 0 || ret >= sz) break;
|
||||
write += ret;
|
||||
}
|
||||
// if files.size() is non-zero, overwrite the last space
|
||||
@@ -866,11 +864,6 @@ bool Compaction::ShouldFormSubcompactions() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfd_->ioptions()->table_factory->Name() ==
|
||||
TableFactory::kPlainTableName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 &&
|
||||
|
||||
+10
-12
@@ -289,7 +289,14 @@ class Compaction {
|
||||
// is the sum of all input file sizes.
|
||||
uint64_t OutputFilePreallocationSize() const;
|
||||
|
||||
void FinalizeInputInfo(Version* input_version);
|
||||
// TODO(hx235): eventually we should consider `InitInputTableProperties()`'s
|
||||
// status and fail the compaction if needed
|
||||
// TODO(hx235): consider making this function part of the construction so we
|
||||
// don't forget to call it
|
||||
void FinalizeInputInfo(Version* input_version) {
|
||||
SetInputVersion(input_version);
|
||||
InitInputTableProperties().PermitUncheckedError();
|
||||
}
|
||||
|
||||
struct InputLevelSummaryBuffer {
|
||||
char buffer[128];
|
||||
@@ -326,16 +333,6 @@ class Compaction {
|
||||
int output_level, VersionStorageInfo* vstorage,
|
||||
const std::vector<CompactionInputFiles>& inputs);
|
||||
|
||||
// TODO(hx235): eventually we should consider `InitInputTableProperties()`'s
|
||||
// status and fail the compaction if needed
|
||||
//
|
||||
// May open and read table files for table property.
|
||||
// Should not be called while holding mutex_.
|
||||
const TablePropertiesCollection& GetOrInitInputTableProperties() {
|
||||
InitInputTableProperties().PermitUncheckedError();
|
||||
return input_table_properties_;
|
||||
}
|
||||
|
||||
const TablePropertiesCollection& GetInputTableProperties() const {
|
||||
return input_table_properties_;
|
||||
}
|
||||
@@ -436,6 +433,7 @@ class Compaction {
|
||||
const int output_level);
|
||||
|
||||
private:
|
||||
void SetInputVersion(Version* input_version);
|
||||
|
||||
Status InitInputTableProperties();
|
||||
|
||||
@@ -597,6 +595,6 @@ struct PerKeyPlacementContext {
|
||||
#endif /* !NDEBUG */
|
||||
|
||||
// Return sum of sizes of all files in `files`.
|
||||
uint64_t TotalFileSize(const std::vector<FileMetaData*>& files);
|
||||
extern uint64_t TotalFileSize(const std::vector<FileMetaData*>& files);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -44,13 +44,6 @@ struct CompactionIterationStats {
|
||||
uint64_t total_blob_bytes_read = 0;
|
||||
uint64_t num_blobs_relocated = 0;
|
||||
uint64_t total_blob_bytes_relocated = 0;
|
||||
|
||||
// TimedPut diagnostics
|
||||
// Total number of kTypeValuePreferredSeqno records encountered.
|
||||
uint64_t num_input_timed_put_records = 0;
|
||||
// Number of kTypeValuePreferredSeqno records we ended up swapping in
|
||||
// preferred seqno.
|
||||
uint64_t num_timed_put_swap_preferred_seqno = 0;
|
||||
};
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -25,7 +25,6 @@ namespace ROCKSDB_NAMESPACE {
|
||||
CompactionIterator::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,
|
||||
@@ -41,7 +40,7 @@ CompactionIterator::CompactionIterator(
|
||||
const SequenceNumber preserve_time_min_seqno,
|
||||
const SequenceNumber preclude_last_level_min_seqno)
|
||||
: CompactionIterator(
|
||||
input, cmp, merge_helper, last_sequence, snapshots, earliest_snapshot,
|
||||
input, cmp, merge_helper, last_sequence, snapshots,
|
||||
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,
|
||||
@@ -55,7 +54,6 @@ CompactionIterator::CompactionIterator(
|
||||
CompactionIterator::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,
|
||||
@@ -93,7 +91,9 @@ CompactionIterator::CompactionIterator(
|
||||
// snapshots_ cannot be nullptr, but we will assert later in the body of
|
||||
// the constructor.
|
||||
visible_at_tip_(snapshots_ ? snapshots_->empty() : false),
|
||||
earliest_snapshot_(earliest_snapshot),
|
||||
earliest_snapshot_(!snapshots_ || snapshots_->empty()
|
||||
? kMaxSequenceNumber
|
||||
: snapshots_->at(0)),
|
||||
info_log_(info_log),
|
||||
allow_data_in_errors_(allow_data_in_errors),
|
||||
enforce_single_del_contracts_(enforce_single_del_contracts),
|
||||
@@ -491,8 +491,6 @@ void CompactionIterator::NextFromInput() {
|
||||
if (ikey_.type == kTypeDeletion || ikey_.type == kTypeSingleDeletion ||
|
||||
ikey_.type == kTypeDeletionWithTimestamp) {
|
||||
iter_stats_.num_input_deletion_records++;
|
||||
} else if (ikey_.type == kTypeValuePreferredSeqno) {
|
||||
iter_stats_.num_input_timed_put_records++;
|
||||
}
|
||||
iter_stats_.total_input_raw_key_bytes += key_.size();
|
||||
iter_stats_.total_input_raw_value_bytes += value_.size();
|
||||
@@ -620,8 +618,7 @@ void CompactionIterator::NextFromInput() {
|
||||
// not compact out. We will keep this Put, but can drop it's data.
|
||||
// (See Optimization 3, below.)
|
||||
if (ikey_.type != kTypeValue && ikey_.type != kTypeBlobIndex &&
|
||||
ikey_.type != kTypeWideColumnEntity &&
|
||||
ikey_.type != kTypeValuePreferredSeqno) {
|
||||
ikey_.type != kTypeWideColumnEntity) {
|
||||
ROCKS_LOG_FATAL(info_log_, "Unexpected key %s for compaction output",
|
||||
ikey_.DebugString(allow_data_in_errors_, true).c_str());
|
||||
assert(false);
|
||||
@@ -635,8 +632,7 @@ void CompactionIterator::NextFromInput() {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (ikey_.type == kTypeBlobIndex || ikey_.type == kTypeWideColumnEntity ||
|
||||
ikey_.type == kTypeValuePreferredSeqno) {
|
||||
if (ikey_.type == kTypeBlobIndex || ikey_.type == kTypeWideColumnEntity) {
|
||||
ikey_.type = kTypeValue;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
}
|
||||
@@ -802,8 +798,7 @@ void CompactionIterator::NextFromInput() {
|
||||
// happened
|
||||
if (next_ikey.type != kTypeValue &&
|
||||
next_ikey.type != kTypeBlobIndex &&
|
||||
next_ikey.type != kTypeWideColumnEntity &&
|
||||
next_ikey.type != kTypeValuePreferredSeqno) {
|
||||
next_ikey.type != kTypeWideColumnEntity) {
|
||||
++iter_stats_.num_single_del_mismatch;
|
||||
}
|
||||
|
||||
@@ -973,62 +968,6 @@ void CompactionIterator::NextFromInput() {
|
||||
validity_info_.SetValid(ValidContext::kKeepDel);
|
||||
at_next_ = true;
|
||||
}
|
||||
} else if (ikey_.type == kTypeValuePreferredSeqno &&
|
||||
DefinitelyInSnapshot(ikey_.sequence, earliest_snapshot_) &&
|
||||
(bottommost_level_ ||
|
||||
(compaction_ != nullptr &&
|
||||
compaction_->KeyNotExistsBeyondOutputLevel(ikey_.user_key,
|
||||
&level_ptrs_)))) {
|
||||
// This section that attempts to swap preferred sequence number will not
|
||||
// be invoked if this is a CompactionIterator created for flush, since
|
||||
// `compaction_` will be nullptr and it's not bottommost either.
|
||||
//
|
||||
// The entries with the same user key and smaller sequence numbers are
|
||||
// all in this earliest snapshot range to be iterated. Since those entries
|
||||
// will be hidden by this entry [rule A], it's safe to swap in the
|
||||
// preferred seqno now.
|
||||
//
|
||||
// It's otherwise not safe to swap in the preferred seqno since it's
|
||||
// possible for entries in earlier snapshots to have sequence number that
|
||||
// is smaller than this entry's sequence number but bigger than this
|
||||
// entry's preferred sequence number. Swapping in the preferred sequence
|
||||
// number will break the internal key ordering invariant for this key.
|
||||
//
|
||||
// A special case involving range deletion is handled separately below.
|
||||
auto [unpacked_value, preferred_seqno] =
|
||||
ParsePackedValueWithSeqno(value_);
|
||||
assert(preferred_seqno < ikey_.sequence || ikey_.sequence == 0);
|
||||
if (range_del_agg_->ShouldDelete(
|
||||
key_, RangeDelPositioningMode::kForwardTraversal)) {
|
||||
++iter_stats_.num_record_drop_hidden;
|
||||
++iter_stats_.num_record_drop_range_del;
|
||||
AdvanceInputIter();
|
||||
} else {
|
||||
InternalKey ikey_after_swap(ikey_.user_key,
|
||||
std::min(preferred_seqno, ikey_.sequence),
|
||||
kTypeValue);
|
||||
Slice ikey_after_swap_slice(*ikey_after_swap.rep());
|
||||
if (range_del_agg_->ShouldDelete(
|
||||
ikey_after_swap_slice,
|
||||
RangeDelPositioningMode::kForwardTraversal)) {
|
||||
// A range tombstone that doesn't cover this kTypeValuePreferredSeqno
|
||||
// entry will end up covering the entry, so it's not safe to swap
|
||||
// preferred sequence number. In this case, we output the entry as is.
|
||||
validity_info_.SetValid(ValidContext::kNewUserKey);
|
||||
} 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;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
key_ = current_key_.GetInternalKey();
|
||||
ikey_.user_key = current_key_.GetUserKey();
|
||||
value_ = unpacked_value;
|
||||
validity_info_.SetValid(ValidContext::kSwapPreferredSeqno);
|
||||
}
|
||||
}
|
||||
} else if (ikey_.type == kTypeMerge) {
|
||||
if (!merge_helper_->HasOperator()) {
|
||||
status_ = Status::InvalidArgument(
|
||||
@@ -1280,21 +1219,6 @@ void CompactionIterator::DecideOutputLevel() {
|
||||
}
|
||||
#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
|
||||
@@ -1303,7 +1227,7 @@ void CompactionIterator::DecideOutputLevel() {
|
||||
// not from this compaction.
|
||||
// TODO: add statistic for declined output_to_penultimate_level
|
||||
bool safe_to_penultimate_level =
|
||||
compaction_->WithinPenultimateLevelOutputRange(ikey_for_range_check);
|
||||
compaction_->WithinPenultimateLevelOutputRange(ikey_);
|
||||
if (!safe_to_penultimate_level) {
|
||||
output_to_penultimate_level_ = false;
|
||||
// It could happen when disable/enable `last_level_temperature` while
|
||||
@@ -1315,7 +1239,7 @@ void CompactionIterator::DecideOutputLevel() {
|
||||
// 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_) {
|
||||
if (ikey_.sequence > earliest_snapshot_) {
|
||||
status_ = Status::Corruption(
|
||||
"Unsafe to store Seq later than snapshot in the last level if "
|
||||
"per_key_placement is enabled");
|
||||
|
||||
@@ -203,7 +203,6 @@ class CompactionIterator {
|
||||
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,
|
||||
@@ -223,7 +222,6 @@ class CompactionIterator {
|
||||
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,
|
||||
@@ -412,7 +410,6 @@ class CompactionIterator {
|
||||
kKeepDel = 9,
|
||||
kNewUserKey = 10,
|
||||
kRangeDeletion = 11,
|
||||
kSwapPreferredSeqno = 12,
|
||||
};
|
||||
|
||||
struct ValidityInfo {
|
||||
@@ -439,17 +436,6 @@ class CompactionIterator {
|
||||
// iterator output (or current key in the underlying iterator during
|
||||
// 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;
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
std::string ValueWithPreferredSeqno(std::string val,
|
||||
SequenceNumber preferred_seqno = 0) {
|
||||
std::string result = val;
|
||||
PutFixed64(&result, preferred_seqno);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Expects no merging attempts.
|
||||
class NoMergingMergeOp : public MergeOperator {
|
||||
@@ -296,7 +288,6 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
|
||||
iter_->SeekToFirst();
|
||||
c_iter_.reset(new CompactionIterator(
|
||||
iter_.get(), cmp_, merge_helper_.get(), last_sequence, &snapshots_,
|
||||
snapshots_.empty() ? kMaxSequenceNumber : snapshots_.at(0),
|
||||
earliest_write_conflict_snapshot, kMaxSequenceNumber,
|
||||
snapshot_checker_.get(), Env::Default(),
|
||||
false /* report_detailed_time */, false, range_del_agg_.get(),
|
||||
@@ -401,17 +392,6 @@ TEST_P(CompactionIteratorTest, CorruptionAfterSingleDeletion) {
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
// Tests compatibility of TimedPut and SingleDelete. TimedPut should act as if
|
||||
// it's a Put.
|
||||
TEST_P(CompactionIteratorTest, TimedPutAndSingleDelete) {
|
||||
InitIterators({test::KeyStr("a", 5, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 3, kTypeValuePreferredSeqno)},
|
||||
{"", "val"}, {}, {}, 5);
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_OK(c_iter_->status());
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, SimpleRangeDeletion) {
|
||||
InitIterators({test::KeyStr("morning", 5, kTypeValue),
|
||||
test::KeyStr("morning", 2, kTypeValue),
|
||||
@@ -451,31 +431,6 @@ TEST_P(CompactionIteratorTest, RangeDeletionWithSnapshots) {
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
// Tests compatibility of TimedPut and Range delete. TimedPut should act as if
|
||||
// it's a Put.
|
||||
TEST_P(CompactionIteratorTest, TimedPutAndRangeDeletion) {
|
||||
InitIterators(
|
||||
{test::KeyStr("morning", 5, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("morning", 2, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("night", 3, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("zao5"), ValueWithPreferredSeqno("zao2"),
|
||||
ValueWithPreferredSeqno("wan")},
|
||||
{test::KeyStr("ma", 4, kTypeRangeDeletion)}, {"mz"}, 5);
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("morning", 5, kTypeValuePreferredSeqno),
|
||||
c_iter_->key().ToString());
|
||||
ASSERT_EQ(ValueWithPreferredSeqno("zao5"), c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("night", 3, kTypeValuePreferredSeqno),
|
||||
c_iter_->key().ToString());
|
||||
ASSERT_EQ(ValueWithPreferredSeqno("wan"), c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_OK(c_iter_->status());
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
}
|
||||
|
||||
TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
class Filter : public CompactionFilter {
|
||||
Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
|
||||
@@ -547,11 +502,9 @@ TEST_P(CompactionIteratorTest, CompactionFilterSkipUntil) {
|
||||
test::KeyStr("f", 25, kTypeValue), test::KeyStr("g", 90, kTypeValue),
|
||||
test::KeyStr("h", 91, kTypeValue), // keep
|
||||
test::KeyStr("i", 95, kTypeMerge), // skip to "z"
|
||||
test::KeyStr("j", 99, kTypeValue),
|
||||
test::KeyStr("k", 100, kTypeValuePreferredSeqno)},
|
||||
test::KeyStr("j", 99, kTypeValue)},
|
||||
{"av50", "am45", "bv60", "bv40", "cv35", "dm70", "em71", "fm65", "fm30",
|
||||
"fv25", "gv90", "hv91", "im95", "jv99",
|
||||
ValueWithPreferredSeqno("kv100")},
|
||||
"fv25", "gv90", "hv91", "im95", "jv99"},
|
||||
{}, {}, kMaxSequenceNumber, kMaxSequenceNumber, &merge_op, &filter);
|
||||
|
||||
// Compaction should output just "a", "e" and "h" keys.
|
||||
@@ -661,87 +614,87 @@ TEST_P(CompactionIteratorTest, ShuttingDownInMerge) {
|
||||
EXPECT_EQ(2, filter.last_seen.load());
|
||||
}
|
||||
|
||||
class Filter : public CompactionFilter {
|
||||
Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
|
||||
const Slice& existing_value, std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
std::string k = key.ToString();
|
||||
std::string v = existing_value.ToString();
|
||||
|
||||
// See InitIterators() call below for the sequence of keys and their
|
||||
// filtering decisions. Here we closely assert that compaction filter is
|
||||
// called with the expected keys and only them, and with the right values.
|
||||
if (k == "a") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
EXPECT_EQ("av1", v);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "b") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "c") {
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
ADD_FAILURE();
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest.SingleMergeOperand::Filter";
|
||||
}
|
||||
};
|
||||
|
||||
class SingleMergeOp : public MergeOperator {
|
||||
public:
|
||||
bool FullMergeV2(const MergeOperationInput& merge_in,
|
||||
MergeOperationOutput* merge_out) const override {
|
||||
// See InitIterators() call below for why "c" is the only key for which
|
||||
// FullMergeV2 should be called.
|
||||
EXPECT_EQ("c", merge_in.key.ToString());
|
||||
|
||||
std::string temp_value;
|
||||
if (merge_in.existing_value != nullptr) {
|
||||
temp_value = merge_in.existing_value->ToString();
|
||||
}
|
||||
|
||||
for (auto& operand : merge_in.operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
merge_out->new_value = temp_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PartialMergeMulti(const Slice& key,
|
||||
const std::deque<Slice>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* /*logger*/) const override {
|
||||
std::string string_key = key.ToString();
|
||||
EXPECT_TRUE(string_key == "a" || string_key == "b");
|
||||
|
||||
if (string_key == "a") {
|
||||
EXPECT_EQ(1, operand_list.size());
|
||||
} else if (string_key == "b") {
|
||||
EXPECT_EQ(2, operand_list.size());
|
||||
}
|
||||
|
||||
std::string temp_value;
|
||||
for (auto& operand : operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
swap(temp_value, *new_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest SingleMergeOp";
|
||||
}
|
||||
|
||||
bool AllowSingleOperand() const override { return true; }
|
||||
};
|
||||
|
||||
TEST_P(CompactionIteratorTest, SingleMergeOperand) {
|
||||
class Filter : public CompactionFilter {
|
||||
Decision FilterV2(int /*level*/, const Slice& key, ValueType t,
|
||||
const Slice& existing_value, std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
std::string k = key.ToString();
|
||||
std::string v = existing_value.ToString();
|
||||
|
||||
// See InitIterators() call below for the sequence of keys and their
|
||||
// filtering decisions. Here we closely assert that compaction filter is
|
||||
// called with the expected keys and only them, and with the right values.
|
||||
if (k == "a") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
EXPECT_EQ("av1", v);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "b") {
|
||||
EXPECT_EQ(ValueType::kMergeOperand, t);
|
||||
return Decision::kKeep;
|
||||
} else if (k == "c") {
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
ADD_FAILURE();
|
||||
return Decision::kKeep;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest.SingleMergeOperand::Filter";
|
||||
}
|
||||
};
|
||||
|
||||
class SingleMergeOp : public MergeOperator {
|
||||
public:
|
||||
bool FullMergeV2(const MergeOperationInput& merge_in,
|
||||
MergeOperationOutput* merge_out) const override {
|
||||
// See InitIterators() call below for why "c" is the only key for which
|
||||
// FullMergeV2 should be called.
|
||||
EXPECT_EQ("c", merge_in.key.ToString());
|
||||
|
||||
std::string temp_value;
|
||||
if (merge_in.existing_value != nullptr) {
|
||||
temp_value = merge_in.existing_value->ToString();
|
||||
}
|
||||
|
||||
for (auto& operand : merge_in.operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
merge_out->new_value = temp_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PartialMergeMulti(const Slice& key,
|
||||
const std::deque<Slice>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* /*logger*/) const override {
|
||||
std::string string_key = key.ToString();
|
||||
EXPECT_TRUE(string_key == "a" || string_key == "b");
|
||||
|
||||
if (string_key == "a") {
|
||||
EXPECT_EQ(1, operand_list.size());
|
||||
} else if (string_key == "b") {
|
||||
EXPECT_EQ(2, operand_list.size());
|
||||
}
|
||||
|
||||
std::string temp_value;
|
||||
for (auto& operand : operand_list) {
|
||||
temp_value.append(operand.ToString());
|
||||
}
|
||||
swap(temp_value, *new_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "CompactionIteratorTest SingleMergeOp";
|
||||
}
|
||||
|
||||
bool AllowSingleOperand() const override { return true; }
|
||||
};
|
||||
|
||||
SingleMergeOp merge_op;
|
||||
Filter filter;
|
||||
InitIterators(
|
||||
@@ -766,24 +719,6 @@ TEST_P(CompactionIteratorTest, SingleMergeOperand) {
|
||||
ASSERT_EQ("cv1cv2", c_iter_->value().ToString());
|
||||
}
|
||||
|
||||
// Tests compatibility of TimedPut and Merge operation. When a TimedPut is
|
||||
// merged with some merge operand in compaction, it will become a regular Put
|
||||
// and lose its preferred sequence number.
|
||||
TEST_P(CompactionIteratorTest, TimedPutAndMerge) {
|
||||
SingleMergeOp merge_op;
|
||||
Filter filter;
|
||||
InitIterators({test::KeyStr("c", 90, kTypeMerge),
|
||||
test::KeyStr("c", 80, kTypeValuePreferredSeqno)},
|
||||
{"cv2", ValueWithPreferredSeqno("cv1")}, {}, {},
|
||||
kMaxSequenceNumber, kMaxSequenceNumber, &merge_op, &filter);
|
||||
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("c", 90, kTypeValue), c_iter_->key().ToString());
|
||||
ASSERT_OK(c_iter_->status());
|
||||
ASSERT_EQ("cv1cv2", c_iter_->value().ToString());
|
||||
}
|
||||
|
||||
// In bottommost level, values earlier than earliest snapshot can be output
|
||||
// with sequence = 0.
|
||||
TEST_P(CompactionIteratorTest, ZeroOutSequenceAtBottomLevel) {
|
||||
@@ -1028,22 +963,6 @@ TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Value) {
|
||||
{"v4", "v3", "v1"}, 3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_TimedPut) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest({test::KeyStr("foo", 4, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 3, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 2, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 1, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("v4"), ValueWithPreferredSeqno("v3"),
|
||||
ValueWithPreferredSeqno("v2"), ValueWithPreferredSeqno("v1")},
|
||||
{test::KeyStr("foo", 4, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 3, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 1, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("v4"), ValueWithPreferredSeqno("v3"),
|
||||
ValueWithPreferredSeqno("v1")},
|
||||
3 /*last_committed_seq*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, DedupSameSnapshot_Deletion) {
|
||||
AddSnapshot(2, 1);
|
||||
RunTest(
|
||||
@@ -1209,149 +1128,6 @@ TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
2 /* earliest_write_conflict_snapshot */);
|
||||
}
|
||||
|
||||
// Same as above but with a value with preferred seqno entry. In addition to the
|
||||
// value getting trimmed, the type of the KV is changed to kTypeValue.
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
KeepSingleDeletionForWriteConflictChecking_TimedPut) {
|
||||
AddSnapshot(2, 0);
|
||||
RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValuePreferredSeqno)},
|
||||
{"", ValueWithPreferredSeqno("v1")},
|
||||
{test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", ""}, 2 /* last_committed_seq */, nullptr /* merge_operator */,
|
||||
nullptr /* compaction_filter */, false /* bottommost_level */,
|
||||
2 /* earliest_write_conflict_snapshot */);
|
||||
}
|
||||
|
||||
// Tests when a kTypeValuePreferredSeqno entry can have its preferred sequence
|
||||
// number swapped in. The required and sufficient conditions for an entry's
|
||||
// preferred sequence number to get swapped in are:
|
||||
// 1) The entry is visible to the earliest snapshot, AND
|
||||
// 2) No more entries with the same user key on lower levels, AND
|
||||
// This is either because:
|
||||
// 2a) This is a compaction to the bottommost level, OR
|
||||
// 2b) Keys do not exist beyond output level
|
||||
// 3) The entry will not resurface a range deletion entry after swapping in the
|
||||
// preferred sequence number.
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_NotVisibleToEarliestSnapshot_NoSwapPreferredSeqno) {
|
||||
AddSnapshot(3);
|
||||
RunTest({test::KeyStr("bar", 5, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("bv2", 2)},
|
||||
{test::KeyStr("bar", 5, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("bv2", 2), "bv1"}, 5 /*last_committed_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
true /*bottommost_level*/,
|
||||
kMaxSequenceNumber /*earliest_write_conflict_snapshot*/,
|
||||
true /*key_not_exists_beyond_output_level*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_MoreEntriesInLowerLevels_NoSwapPreferredSeqno) {
|
||||
// This tests mimics more entries in lower levels with `bottommost_level` and
|
||||
// `key_not_exists_beyond_output_level` set to false.
|
||||
RunTest({test::KeyStr("bar", 5, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("bv2", 2)},
|
||||
{test::KeyStr("bar", 5, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("bv2", 2)}, 5 /*last_committed_seq*/,
|
||||
nullptr /*merge_operator*/, nullptr /*compaction_filter*/,
|
||||
false /*bottommost_level*/,
|
||||
kMaxSequenceNumber /*earliest_write_conflict_snapshot*/,
|
||||
false /*key_not_exists_beyond_output_level*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_ShouldBeCoverredByRangeDeletionBeforeSwap_NoOutput) {
|
||||
InitIterators({test::KeyStr("morning", 5, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("morning", 2, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("night", 6, kTypeValue)},
|
||||
{ValueWithPreferredSeqno("zao", 3),
|
||||
ValueWithPreferredSeqno("zao", 1), "wan"},
|
||||
{test::KeyStr("ma", 6, kTypeRangeDeletion)}, {"mz"}, 6,
|
||||
kMaxSequenceNumber /*last_committed_sequence*/,
|
||||
nullptr /*merge_op*/, nullptr /*filter*/,
|
||||
false /*bottommost_level*/,
|
||||
kMaxSequenceNumber /*earliest_write_conflict_snapshot*/,
|
||||
true /*key_not_exists_beyond_output_level*/);
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("night", 6, kTypeValue), c_iter_->key().ToString());
|
||||
ASSERT_EQ("wan", c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
ASSERT_OK(c_iter_->status());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_WillBeHiddenByRangeDeletionAfterSwap_NoSwap) {
|
||||
InitIterators({test::KeyStr("morning", 5, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("night", 6, kTypeValue)},
|
||||
{ValueWithPreferredSeqno("zao", 3), "wan"},
|
||||
{test::KeyStr("ma", 4, kTypeRangeDeletion)}, {"mz"}, 6,
|
||||
kMaxSequenceNumber /*last_committed_sequence*/,
|
||||
nullptr /*merge_op*/, nullptr /*filter*/,
|
||||
false /*bottommost_level*/,
|
||||
kMaxSequenceNumber /*earliest_write_conflict_snapshot*/,
|
||||
true /*key_not_exists_beyond_output_level*/);
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("morning", 5, kTypeValuePreferredSeqno),
|
||||
c_iter_->key().ToString());
|
||||
ASSERT_EQ(ValueWithPreferredSeqno("zao", 3), c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_TRUE(c_iter_->Valid());
|
||||
ASSERT_EQ(test::KeyStr("night", 6, kTypeValue), c_iter_->key().ToString());
|
||||
ASSERT_EQ("wan", c_iter_->value().ToString());
|
||||
c_iter_->Next();
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
ASSERT_OK(c_iter_->status());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_BottomMostLevelVisibleToEarliestSnapshot_SwapPreferredSeqno) {
|
||||
// Preferred seqno got swapped in and also zeroed out as a bottommost level
|
||||
// optimization.
|
||||
RunTest(
|
||||
{test::KeyStr("bar", 5, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("bar", 4, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 6, kTypeValue)},
|
||||
{ValueWithPreferredSeqno("bv2", 2), ValueWithPreferredSeqno("bv1", 1),
|
||||
"fv1"},
|
||||
{test::KeyStr("bar", 0, kTypeValue), test::KeyStr("foo", 0, kTypeValue)},
|
||||
{"bv2", "fv1"}, 6 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_NonBottomMostLevelVisibleToEarliestSnapshot_SwapPreferredSeqno) {
|
||||
RunTest(
|
||||
{test::KeyStr("bar", 5, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("bar", 4, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 6, kTypeValue)},
|
||||
{ValueWithPreferredSeqno("bv2", 2), ValueWithPreferredSeqno("bv1", 1),
|
||||
"fv1"},
|
||||
{test::KeyStr("bar", 2, kTypeValue), test::KeyStr("foo", 6, kTypeValue)},
|
||||
{"bv2", "fv1"}, 6 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, false /*bottommost_level*/,
|
||||
kMaxSequenceNumber /*earliest_write_conflict_snapshot*/,
|
||||
true /*key_not_exists_beyond_output_level*/);
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
TimedPut_SequenceNumberAlreadyZeroedOut_ChangeType) {
|
||||
RunTest(
|
||||
{test::KeyStr("bar", 0, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("bar", 0, kTypeValuePreferredSeqno),
|
||||
test::KeyStr("foo", 0, kTypeValue)},
|
||||
{ValueWithPreferredSeqno("bv2", 2), ValueWithPreferredSeqno("bv1", 1),
|
||||
"fv1"},
|
||||
{test::KeyStr("bar", 0, kTypeValue), test::KeyStr("foo", 0, kTypeValue)},
|
||||
{"bv2", "fv1"}, 6 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, true /*bottommost_level*/);
|
||||
}
|
||||
|
||||
// Compaction filter should keep uncommitted key as-is, and
|
||||
// * Convert the latest value to deletion, and/or
|
||||
// * if latest value is a merge, apply filter to all subsequent merges.
|
||||
@@ -1369,22 +1145,6 @@ TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Value) {
|
||||
nullptr /*merge_operator*/, compaction_filter.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_TimedPut) {
|
||||
// TODO(yuzhangyu): Add support for this type in compaction filter.
|
||||
// Type kTypeValuePreferredSeqno is not explicitly exposed in the compaction
|
||||
// filter API, so users can not operate on it through compaction filter API
|
||||
// to remove/purge/change value etc. But this type of entry can be impacted by
|
||||
// other entries' filter result, currently only kRemoveAndSkip type of result
|
||||
// can affect it.
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
RunTest({test::KeyStr("a", 2, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("v1")},
|
||||
{test::KeyStr("a", 2, kTypeValuePreferredSeqno)},
|
||||
{ValueWithPreferredSeqno("v1")}, 2 /*last_committed_seq*/,
|
||||
nullptr /*merge_operator*/, compaction_filter.get());
|
||||
}
|
||||
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_Deletion) {
|
||||
std::unique_ptr<CompactionFilter> compaction_filter(
|
||||
new FilterAllKeysCompactionFilter());
|
||||
|
||||
@@ -174,9 +174,6 @@ CompactionJob::CompactionJob(
|
||||
db_mutex_(db_mutex),
|
||||
db_error_handler_(db_error_handler),
|
||||
existing_snapshots_(std::move(existing_snapshots)),
|
||||
earliest_snapshot_(existing_snapshots_.empty()
|
||||
? kMaxSequenceNumber
|
||||
: existing_snapshots_.at(0)),
|
||||
earliest_write_conflict_snapshot_(earliest_write_conflict_snapshot),
|
||||
snapshot_checker_(snapshot_checker),
|
||||
job_context_(job_context),
|
||||
@@ -285,60 +282,68 @@ void CompactionJob::Prepare() {
|
||||
|
||||
// collect all seqno->time information from the input files which will be used
|
||||
// to encode seqno->time to the output files.
|
||||
|
||||
uint64_t preserve_time_duration =
|
||||
std::max(c->immutable_options()->preserve_internal_time_seconds,
|
||||
c->immutable_options()->preclude_last_level_data_seconds);
|
||||
|
||||
if (preserve_time_duration > 0) {
|
||||
const ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
// Setup seqno_to_time_mapping_ with relevant time range.
|
||||
seqno_to_time_mapping_.SetMaxTimeSpan(preserve_time_duration);
|
||||
// setup seqno_to_time_mapping_
|
||||
seqno_to_time_mapping_.SetMaxTimeDuration(preserve_time_duration);
|
||||
for (const auto& each_level : *c->inputs()) {
|
||||
for (const auto& fmd : each_level.files) {
|
||||
std::shared_ptr<const TableProperties> tp;
|
||||
Status s =
|
||||
cfd->current()->GetTableProperties(read_options, &tp, fmd, nullptr);
|
||||
if (s.ok()) {
|
||||
s = seqno_to_time_mapping_.DecodeFrom(tp->seqno_to_time_mapping);
|
||||
}
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_WARN(
|
||||
db_options_.info_log,
|
||||
"Problem reading or processing seqno-to-time mapping: %s",
|
||||
s.ToString().c_str());
|
||||
seqno_to_time_mapping_.Add(tp->seqno_to_time_mapping)
|
||||
.PermitUncheckedError();
|
||||
seqno_to_time_mapping_.Add(fmd->fd.smallest_seqno,
|
||||
fmd->oldest_ancester_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto status = seqno_to_time_mapping_.Sort();
|
||||
if (!status.ok()) {
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"Invalid sequence number to time mapping: Status: %s",
|
||||
status.ToString().c_str());
|
||||
}
|
||||
int64_t _current_time = 0;
|
||||
Status s = db_options_.clock->GetCurrentTime(&_current_time);
|
||||
if (!s.ok()) {
|
||||
status = db_options_.clock->GetCurrentTime(&_current_time);
|
||||
if (!status.ok()) {
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"Failed to get current time in compaction: Status: %s",
|
||||
s.ToString().c_str());
|
||||
status.ToString().c_str());
|
||||
// preserve all time information
|
||||
preserve_time_min_seqno_ = 0;
|
||||
preclude_last_level_min_seqno_ = 0;
|
||||
seqno_to_time_mapping_.Enforce();
|
||||
} else {
|
||||
seqno_to_time_mapping_.Enforce(_current_time);
|
||||
seqno_to_time_mapping_.GetCurrentTieringCutoffSeqnos(
|
||||
static_cast<uint64_t>(_current_time),
|
||||
c->immutable_options()->preserve_internal_time_seconds,
|
||||
c->immutable_options()->preclude_last_level_data_seconds,
|
||||
&preserve_time_min_seqno_, &preclude_last_level_min_seqno_);
|
||||
seqno_to_time_mapping_.TruncateOldEntries(_current_time);
|
||||
uint64_t preserve_time =
|
||||
static_cast<uint64_t>(_current_time) > preserve_time_duration
|
||||
? _current_time - preserve_time_duration
|
||||
: 0;
|
||||
// GetProximalSeqnoBeforeTime tells us the last seqno known to have been
|
||||
// written at or before the given time. + 1 to get the minimum we should
|
||||
// preserve without excluding anything that might have been written on or
|
||||
// after the given time.
|
||||
preserve_time_min_seqno_ =
|
||||
seqno_to_time_mapping_.GetProximalSeqnoBeforeTime(preserve_time) + 1;
|
||||
if (c->immutable_options()->preclude_last_level_data_seconds > 0) {
|
||||
uint64_t preclude_last_level_time =
|
||||
static_cast<uint64_t>(_current_time) >
|
||||
c->immutable_options()->preclude_last_level_data_seconds
|
||||
? _current_time -
|
||||
c->immutable_options()->preclude_last_level_data_seconds
|
||||
: 0;
|
||||
preclude_last_level_min_seqno_ =
|
||||
seqno_to_time_mapping_.GetProximalSeqnoBeforeTime(
|
||||
preclude_last_level_time) +
|
||||
1;
|
||||
}
|
||||
}
|
||||
// For accuracy of the GetProximalSeqnoBeforeTime queries above, we only
|
||||
// limit the capacity after them.
|
||||
// Here If we set capacity to the per-SST limit, we could be throwing away
|
||||
// fidelity when a compaction output file has a narrower seqno range than
|
||||
// all the inputs. If we only limit capacity for each compaction output, we
|
||||
// could be doing a lot of unnecessary recomputation in a large compaction
|
||||
// (up to quadratic in number of files). Thus, we do soemthing in the
|
||||
// middle: enforce a resonably large constant size limit substantially
|
||||
// larger than kMaxSeqnoTimePairsPerSST.
|
||||
seqno_to_time_mapping_.SetCapacity(kMaxSeqnoToTimeEntries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,9 +396,7 @@ void CompactionJob::AcquireSubcompactionResources(
|
||||
|
||||
void CompactionJob::ShrinkSubcompactionResources(uint64_t num_extra_resources) {
|
||||
// Do nothing when we have zero resources to shrink
|
||||
if (num_extra_resources == 0) {
|
||||
return;
|
||||
}
|
||||
if (num_extra_resources == 0) return;
|
||||
db_mutex_->Lock();
|
||||
// We cannot release threads more than what we reserved before
|
||||
int extra_num_subcompaction_threads_released = env_->ReleaseThreads(
|
||||
@@ -439,6 +442,14 @@ void CompactionJob::ReleaseSubcompactionResources() {
|
||||
ShrinkSubcompactionResources(extra_num_subcompaction_threads_reserved_);
|
||||
}
|
||||
|
||||
struct RangeWithSize {
|
||||
Range range;
|
||||
uint64_t size;
|
||||
|
||||
RangeWithSize(const Slice& a, const Slice& b, uint64_t s = 0)
|
||||
: range(a, b), size(s) {}
|
||||
};
|
||||
|
||||
void CompactionJob::GenSubcompactionBoundaries() {
|
||||
// The goal is to find some boundary keys so that we can evenly partition
|
||||
// the compaction input data into max_subcompactions ranges.
|
||||
@@ -465,14 +476,8 @@ void CompactionJob::GenSubcompactionBoundaries() {
|
||||
// overlap with N-1 other ranges. Since we requested a relatively large number
|
||||
// (128) of ranges from each input files, even N range overlapping would
|
||||
// cause relatively small inaccuracy.
|
||||
ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
read_options.rate_limiter_priority = GetRateLimiterPriority();
|
||||
const ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
auto* c = compact_->compaction;
|
||||
if (c->immutable_options()->table_factory->Name() ==
|
||||
TableFactory::kPlainTableName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->max_subcompactions() <= 1 &&
|
||||
!(c->immutable_options()->compaction_pri == kRoundRobin &&
|
||||
c->immutable_options()->compaction_style == kCompactionStyleLevel)) {
|
||||
@@ -578,9 +583,7 @@ void CompactionJob::GenSubcompactionBoundaries() {
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionJob::GenSubcompactionBoundaries:0",
|
||||
&num_planned_subcompactions);
|
||||
if (num_planned_subcompactions == 1) {
|
||||
return;
|
||||
}
|
||||
if (num_planned_subcompactions == 1) return;
|
||||
|
||||
// Group the ranges into subcompactions
|
||||
uint64_t target_range_size = std::max(
|
||||
@@ -626,7 +629,6 @@ Status CompactionJob::Run() {
|
||||
const size_t num_threads = compact_->sub_compact_states.size();
|
||||
assert(num_threads > 0);
|
||||
const uint64_t start_micros = db_options_.clock->NowMicros();
|
||||
compact_->compaction->GetOrInitInputTableProperties();
|
||||
|
||||
// Launch a thread for each of subcompactions 1...num_threads-1
|
||||
std::vector<port::Thread> thread_pool;
|
||||
@@ -638,7 +640,7 @@ Status CompactionJob::Run() {
|
||||
|
||||
// Always schedule the first subcompaction (whether or not there are also
|
||||
// others) in the current thread to be efficient with resources
|
||||
ProcessKeyValueCompaction(compact_->sub_compact_states.data());
|
||||
ProcessKeyValueCompaction(&compact_->sub_compact_states[0]);
|
||||
|
||||
// Wait for all other threads (if there are any) to finish execution
|
||||
for (auto& thread : thread_pool) {
|
||||
@@ -726,9 +728,8 @@ Status CompactionJob::Run() {
|
||||
// use_direct_io_for_flush_and_compaction is true, we will regard this
|
||||
// verification as user reads since the goal is to cache it here for
|
||||
// further user reads
|
||||
ReadOptions verify_table_read_options(Env::IOActivity::kCompaction);
|
||||
verify_table_read_options.rate_limiter_priority =
|
||||
GetRateLimiterPriority();
|
||||
const ReadOptions verify_table_read_options(
|
||||
Env::IOActivity::kCompaction);
|
||||
InternalIterator* iter = cfd->table_cache()->NewIterator(
|
||||
verify_table_read_options, file_options_,
|
||||
cfd->internal_comparator(), files_output[file_idx]->meta,
|
||||
@@ -749,6 +750,7 @@ Status CompactionJob::Run() {
|
||||
|
||||
if (s.ok() && paranoid_file_checks_) {
|
||||
OutputValidator validator(cfd->internal_comparator(),
|
||||
/*_enable_order_check=*/true,
|
||||
/*_enable_hash=*/true);
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
s = validator.Add(iter->key(), iter->value());
|
||||
@@ -819,27 +821,24 @@ Status CompactionJob::Run() {
|
||||
// input keys. So the number of keys it processed is not suitable for
|
||||
// verification here.
|
||||
// TODO: support verification when trim_ts_ is non-empty.
|
||||
if (!(ts_sz > 0 && !trim_ts_.empty())) {
|
||||
if (!(ts_sz > 0 && !trim_ts_.empty()) &&
|
||||
db_options_.compaction_verify_record_count) {
|
||||
assert(compaction_stats_.stats.num_input_records > 0);
|
||||
// TODO: verify the number of range deletion entries.
|
||||
uint64_t expected =
|
||||
compaction_stats_.stats.num_input_records - num_input_range_del;
|
||||
uint64_t actual = compaction_job_stats_->num_input_records;
|
||||
if (expected != actual) {
|
||||
char scratch[2345];
|
||||
compact_->compaction->Summary(scratch, sizeof(scratch));
|
||||
std::string msg =
|
||||
"Compaction number of input keys does not match "
|
||||
"number of keys processed. Expected " +
|
||||
std::to_string(expected) + " but processed " +
|
||||
std::to_string(actual) + ". Compaction summary: " + scratch;
|
||||
"Total number of input records: " + std::to_string(expected) +
|
||||
", but processed " + std::to_string(actual) + " records.";
|
||||
ROCKS_LOG_WARN(
|
||||
db_options_.info_log, "[%s] [JOB %d] Compaction with status: %s",
|
||||
db_options_.info_log, "[%s] [JOB %d] Compaction %s",
|
||||
compact_->compaction->column_family_data()->GetName().c_str(),
|
||||
job_context_->job_id, msg.c_str());
|
||||
if (db_options_.compaction_verify_record_count) {
|
||||
status = Status::Corruption(msg);
|
||||
}
|
||||
status = Status::Corruption(
|
||||
"Compaction number of input keys does not match number of keys "
|
||||
"processed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1131,9 +1130,6 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
// (b) CompactionFilter::Decision::kRemoveAndSkipUntil.
|
||||
read_options.total_order_seek = true;
|
||||
|
||||
const WriteOptions write_options(Env::IOPriority::IO_LOW,
|
||||
Env::IOActivity::kCompaction);
|
||||
|
||||
// Remove the timestamps from boundaries because boundaries created in
|
||||
// GenSubcompactionBoundaries doesn't strip away the timestamp.
|
||||
size_t ts_sz = cfd->user_comparator()->timestamp_size();
|
||||
@@ -1268,17 +1264,18 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
? new BlobFileBuilder(
|
||||
versions_, fs_.get(),
|
||||
sub_compact->compaction->immutable_options(),
|
||||
mutable_cf_options, &file_options_, &write_options, db_id_,
|
||||
db_session_id_, job_id_, cfd->GetID(), cfd->GetName(),
|
||||
mutable_cf_options, &file_options_, db_id_, db_session_id_,
|
||||
job_id_, cfd->GetID(), cfd->GetName(), Env::IOPriority::IO_LOW,
|
||||
write_hint_, io_tracer_, blob_callback_,
|
||||
BlobFileCreationReason::kCompaction, &blob_file_paths,
|
||||
sub_compact->Current().GetBlobFileAdditionsPtr())
|
||||
: nullptr);
|
||||
|
||||
TEST_SYNC_POINT("CompactionJob::Run():Inprogress");
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionJob::Run():PausingManualCompaction:1",
|
||||
static_cast<void*>(const_cast<std::atomic<bool>*>(
|
||||
&manual_compaction_canceled_)));
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionJob::Run():PausingManualCompaction:1",
|
||||
reinterpret_cast<void*>(
|
||||
const_cast<std::atomic<bool>*>(&manual_compaction_canceled_)));
|
||||
|
||||
const std::string* const full_history_ts_low =
|
||||
full_history_ts_low_.empty() ? nullptr : &full_history_ts_low_;
|
||||
@@ -1288,9 +1285,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
|
||||
auto c_iter = std::make_unique<CompactionIterator>(
|
||||
input, cfd->user_comparator(), &merge, versions_->LastSequence(),
|
||||
&existing_snapshots_, earliest_snapshot_,
|
||||
earliest_write_conflict_snapshot_, job_snapshot_seq, snapshot_checker_,
|
||||
env_, ShouldReportDetailedTime(env_, stats_),
|
||||
&existing_snapshots_, earliest_write_conflict_snapshot_, job_snapshot_seq,
|
||||
snapshot_checker_, env_, ShouldReportDetailedTime(env_, stats_),
|
||||
/*expect_valid_internal_key=*/true, range_del_agg.get(),
|
||||
blob_file_builder.get(), db_options_.allow_data_in_errors,
|
||||
db_options_.enforce_single_del_contracts, manual_compaction_canceled_,
|
||||
@@ -1327,7 +1323,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
Status status;
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionJob::ProcessKeyValueCompaction()::Processing",
|
||||
static_cast<void*>(const_cast<Compaction*>(sub_compact->compaction)));
|
||||
reinterpret_cast<void*>(
|
||||
const_cast<Compaction*>(sub_compact->compaction)));
|
||||
uint64_t last_cpu_micros = prev_cpu_micros;
|
||||
while (status.ok() && !cfd->IsDropped() && c_iter->Valid()) {
|
||||
// Invariant: c_iter.status() is guaranteed to be OK if c_iter->Valid()
|
||||
@@ -1358,9 +1355,10 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
break;
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionJob::Run():PausingManualCompaction:2",
|
||||
static_cast<void*>(const_cast<std::atomic<bool>*>(
|
||||
&manual_compaction_canceled_)));
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionJob::Run():PausingManualCompaction:2",
|
||||
reinterpret_cast<void*>(
|
||||
const_cast<std::atomic<bool>*>(&manual_compaction_canceled_)));
|
||||
c_iter->Next();
|
||||
if (c_iter->status().IsManualCompactionPaused()) {
|
||||
break;
|
||||
@@ -1712,8 +1710,6 @@ Status CompactionJob::InstallCompactionResults(
|
||||
db_mutex_->AssertHeld();
|
||||
|
||||
const ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
const WriteOptions write_options(Env::IOActivity::kCompaction);
|
||||
|
||||
auto* compaction = compact_->compaction;
|
||||
assert(compaction);
|
||||
|
||||
@@ -1796,9 +1792,8 @@ Status CompactionJob::InstallCompactionResults(
|
||||
};
|
||||
|
||||
return versions_->LogAndApply(
|
||||
compaction->column_family_data(), mutable_cf_options, read_options,
|
||||
write_options, edit, db_mutex_, db_directory_,
|
||||
/*new_descriptor_log=*/false,
|
||||
compaction->column_family_data(), mutable_cf_options, read_options, edit,
|
||||
db_mutex_, db_directory_, /*new_descriptor_log=*/false,
|
||||
/*column_family_options=*/nullptr, manifest_wcb);
|
||||
}
|
||||
|
||||
@@ -1848,14 +1843,13 @@ Status CompactionJob::OpenCompactionOutputFile(SubcompactionState* sub_compact,
|
||||
// Pass temperature of the last level files to FileSystem.
|
||||
FileOptions fo_copy = file_options_;
|
||||
Temperature temperature = sub_compact->compaction->output_temperature();
|
||||
Temperature last_level_temp =
|
||||
sub_compact->compaction->mutable_cf_options()->last_level_temperature;
|
||||
// Here last_level_temperature supersedes default_write_temperature, when
|
||||
// enabled and applicable
|
||||
if (last_level_temp != Temperature::kUnknown &&
|
||||
// only set for the last level compaction and also it's not output to
|
||||
// penultimate level (when preclude_last_level feature is enabled)
|
||||
if (temperature == Temperature::kUnknown &&
|
||||
sub_compact->compaction->is_last_level() &&
|
||||
!sub_compact->IsCurrentPenultimateLevel()) {
|
||||
temperature = last_level_temp;
|
||||
temperature =
|
||||
sub_compact->compaction->mutable_cf_options()->last_level_temperature;
|
||||
}
|
||||
fo_copy.temperature = temperature;
|
||||
|
||||
@@ -1935,6 +1929,8 @@ Status CompactionJob::OpenCompactionOutputFile(SubcompactionState* sub_compact,
|
||||
}
|
||||
|
||||
outputs.AddOutput(std::move(meta), cfd->internal_comparator(),
|
||||
sub_compact->compaction->mutable_cf_options()
|
||||
->check_flush_compaction_key_order,
|
||||
paranoid_file_checks_);
|
||||
}
|
||||
|
||||
@@ -1947,26 +1943,19 @@ Status CompactionJob::OpenCompactionOutputFile(SubcompactionState* sub_compact,
|
||||
sub_compact->compaction->immutable_options()->listeners;
|
||||
outputs.AssignFileWriter(new WritableFileWriter(
|
||||
std::move(writable_file), fname, fo_copy, db_options_.clock, io_tracer_,
|
||||
db_options_.stats, Histograms::SST_WRITE_MICROS, listeners,
|
||||
db_options_.file_checksum_gen_factory.get(),
|
||||
db_options_.stats, listeners, db_options_.file_checksum_gen_factory.get(),
|
||||
tmp_set.Contains(FileType::kTableFile), false));
|
||||
|
||||
// TODO(hx235): pass in the correct `oldest_key_time` instead of `0`
|
||||
const ReadOptions read_options(Env::IOActivity::kCompaction);
|
||||
const WriteOptions write_options(Env::IOActivity::kCompaction);
|
||||
TableBuilderOptions tboptions(
|
||||
*cfd->ioptions(), *(sub_compact->compaction->mutable_cf_options()),
|
||||
read_options, write_options, cfd->internal_comparator(),
|
||||
cfd->internal_tbl_prop_coll_factories(),
|
||||
cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(),
|
||||
sub_compact->compaction->output_compression(),
|
||||
sub_compact->compaction->output_compression_opts(), cfd->GetID(),
|
||||
cfd->GetName(), sub_compact->compaction->output_level(),
|
||||
bottommost_level_, TableFileCreationReason::kCompaction,
|
||||
0 /* oldest_key_time */, current_time, db_id_, db_session_id_,
|
||||
sub_compact->compaction->max_output_file_size(), file_number,
|
||||
preclude_last_level_min_seqno_ == kMaxSequenceNumber
|
||||
? preclude_last_level_min_seqno_
|
||||
: std::min(earliest_snapshot_, preclude_last_level_min_seqno_));
|
||||
sub_compact->compaction->max_output_file_size(), file_number);
|
||||
|
||||
outputs.NewBuilder(tboptions);
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "rocksdb/transaction_log.h"
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
#include "util/autovector.h"
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/thread_local.h"
|
||||
@@ -314,8 +315,6 @@ class CompactionJob {
|
||||
// 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.
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "table/block_based/block_based_table_factory.h"
|
||||
#include "table/mock_table.h"
|
||||
#include "table/plain/plain_table_factory.h"
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "test_util/testutil.h"
|
||||
@@ -130,7 +131,7 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
ColumnFamilyOptions cf_opts(options);
|
||||
size_t cfi = handles_.size();
|
||||
handles_.resize(cfi + cfs.size());
|
||||
for (const auto& cf : cfs) {
|
||||
for (auto cf : cfs) {
|
||||
ASSERT_OK(db_->CreateColumnFamily(cf_opts, cf, &handles_[cfi++]));
|
||||
}
|
||||
}
|
||||
@@ -159,7 +160,7 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
EXPECT_EQ(cfs.size(), options.size());
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (size_t i = 0; i < cfs.size(); ++i) {
|
||||
column_families.emplace_back(cfs[i], options[i]);
|
||||
column_families.push_back(ColumnFamilyDescriptor(cfs[i], options[i]));
|
||||
}
|
||||
DBOptions db_opts = DBOptions(options[0]);
|
||||
return DB::Open(db_opts, dbname_, column_families, &handles_, &db_);
|
||||
|
||||
@@ -217,7 +217,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
/*block_cache_tracer=*/nullptr,
|
||||
/*io_tracer=*/nullptr, /*db_id=*/"", /*db_session_id=*/"",
|
||||
/*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false)),
|
||||
/*error_handler=*/nullptr)),
|
||||
shutting_down_(false),
|
||||
mock_table_factory_(new mock::MockTableFactory()),
|
||||
error_handler_(nullptr, db_options_, &mutex_),
|
||||
@@ -295,20 +295,17 @@ class CompactionJobTestBase : public testing::Test {
|
||||
Status s = WritableFileWriter::Create(fs_, table_name, FileOptions(),
|
||||
&file_writer, nullptr);
|
||||
ASSERT_OK(s);
|
||||
const ReadOptions read_options;
|
||||
const WriteOptions write_options;
|
||||
std::unique_ptr<TableBuilder> table_builder(
|
||||
cf_options_.table_factory->NewTableBuilder(
|
||||
TableBuilderOptions(*cfd_->ioptions(), mutable_cf_options_,
|
||||
read_options, write_options,
|
||||
cfd_->internal_comparator(),
|
||||
cfd_->internal_tbl_prop_coll_factories(),
|
||||
cfd_->int_tbl_prop_collector_factories(),
|
||||
CompressionType::kNoCompression,
|
||||
CompressionOptions(), 0 /* column_family_id */,
|
||||
kDefaultColumnFamilyName, -1 /* level */),
|
||||
file_writer.get()));
|
||||
// Build table.
|
||||
for (const auto& kv : contents) {
|
||||
for (auto kv : contents) {
|
||||
std::string key;
|
||||
std::string value;
|
||||
std::tie(key, value) = kv;
|
||||
@@ -327,7 +324,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
SequenceNumber smallest_seqno = kMaxSequenceNumber;
|
||||
SequenceNumber largest_seqno = 0;
|
||||
uint64_t oldest_blob_file_number = kInvalidBlobFileNumber;
|
||||
for (const auto& kv : contents) {
|
||||
for (auto kv : contents) {
|
||||
ParsedInternalKey key;
|
||||
std::string skey;
|
||||
std::string value;
|
||||
@@ -397,7 +394,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
mutex_.Lock();
|
||||
EXPECT_OK(versions_->LogAndApply(
|
||||
versions_->GetColumnFamilySet()->GetDefault(), mutable_cf_options_,
|
||||
read_options_, write_options_, &edit, &mutex_, nullptr));
|
||||
read_options_, &edit, &mutex_, nullptr));
|
||||
mutex_.Unlock();
|
||||
}
|
||||
|
||||
@@ -550,10 +547,9 @@ class CompactionJobTestBase : public testing::Test {
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr,
|
||||
/*db_id=*/"", /*db_session_id=*/"", /*daily_offpeak_time_utc=*/"",
|
||||
/*error_handler=*/nullptr, /*read_only=*/false));
|
||||
/*error_handler=*/nullptr));
|
||||
compaction_job_stats_.Reset();
|
||||
ASSERT_OK(
|
||||
SetIdentityFile(WriteOptions(), env_, dbname_, Temperature::kUnknown));
|
||||
ASSERT_OK(SetIdentityFile(env_, dbname_));
|
||||
|
||||
VersionEdit new_db;
|
||||
new_db.SetLogNumber(0);
|
||||
@@ -572,12 +568,11 @@ class CompactionJobTestBase : public testing::Test {
|
||||
log::Writer log(std::move(file_writer), 0, false);
|
||||
std::string record;
|
||||
new_db.EncodeTo(&record);
|
||||
s = log.AddRecord(WriteOptions(), record);
|
||||
s = log.AddRecord(record);
|
||||
}
|
||||
ASSERT_OK(s);
|
||||
// Make "CURRENT" file that points to the new manifest file.
|
||||
s = SetCurrentFile(WriteOptions(), fs_.get(), dbname_, 1,
|
||||
Temperature::kUnknown, nullptr);
|
||||
s = SetCurrentFile(fs_.get(), dbname_, 1, nullptr);
|
||||
|
||||
ASSERT_OK(s);
|
||||
|
||||
@@ -741,7 +736,6 @@ class CompactionJobTestBase : public testing::Test {
|
||||
MutableCFOptions mutable_cf_options_;
|
||||
MutableDBOptions mutable_db_options_;
|
||||
const ReadOptions read_options_;
|
||||
const WriteOptions write_options_;
|
||||
std::shared_ptr<Cache> table_cache_;
|
||||
WriteController write_controller_;
|
||||
WriteBufferManager write_buffer_manager_;
|
||||
@@ -1475,7 +1469,7 @@ TEST_F(CompactionJobTest, OldestBlobFileNumber) {
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, VerifyPenultimateLevelOutput) {
|
||||
cf_options_.last_level_temperature = Temperature::kCold;
|
||||
cf_options_.bottommost_temperature = Temperature::kCold;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"Compaction::SupportsPerKeyPlacement:Enabled", [&](void* arg) {
|
||||
auto supports_per_key_placement = static_cast<bool*>(arg);
|
||||
@@ -1754,9 +1748,23 @@ TEST_F(CompactionJobTest, ResultSerialization) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, CutForMaxCompactionBytes) {
|
||||
class CompactionJobDynamicFileSizeTest
|
||||
: public CompactionJobTestBase,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
public:
|
||||
CompactionJobDynamicFileSizeTest()
|
||||
: CompactionJobTestBase(
|
||||
test::PerThreadDBPath("compaction_job_dynamic_file_size_test"),
|
||||
BytewiseComparator(), [](uint64_t /*ts*/) { return ""; },
|
||||
/*test_io_priority=*/false, TableTypeForTest::kMockTable) {}
|
||||
};
|
||||
|
||||
TEST_P(CompactionJobDynamicFileSizeTest, CutForMaxCompactionBytes) {
|
||||
// dynamic_file_size option should have no impact on cutting for max
|
||||
// compaction bytes.
|
||||
bool enable_dyanmic_file_size = GetParam();
|
||||
cf_options_.level_compaction_dynamic_file_size = enable_dyanmic_file_size;
|
||||
|
||||
NewDB();
|
||||
mutable_cf_options_.target_file_size_base = 80;
|
||||
mutable_cf_options_.max_compaction_bytes = 21;
|
||||
@@ -1830,7 +1838,10 @@ TEST_F(CompactionJobTest, CutForMaxCompactionBytes) {
|
||||
{expected_file1, expected_file2});
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, CutToSkipGrandparentFile) {
|
||||
TEST_P(CompactionJobDynamicFileSizeTest, CutToSkipGrandparentFile) {
|
||||
bool enable_dyanmic_file_size = GetParam();
|
||||
cf_options_.level_compaction_dynamic_file_size = enable_dyanmic_file_size;
|
||||
|
||||
NewDB();
|
||||
// Make sure the grandparent level file size (10) qualifies skipping.
|
||||
// Currently, it has to be > 1/8 of target file size.
|
||||
@@ -1865,15 +1876,28 @@ TEST_F(CompactionJobTest, CutToSkipGrandparentFile) {
|
||||
mock::MakeMockFile({{KeyStr("x", 4U, kTypeValue), "val"},
|
||||
{KeyStr("z", 6U, kTypeValue), "val3"}});
|
||||
|
||||
auto expected_file_disable_dynamic_file_size =
|
||||
mock::MakeMockFile({{KeyStr("a", 5U, kTypeValue), "val2"},
|
||||
{KeyStr("c", 3U, kTypeValue), "val"},
|
||||
{KeyStr("x", 4U, kTypeValue), "val"},
|
||||
{KeyStr("z", 6U, kTypeValue), "val3"}});
|
||||
|
||||
SetLastSequence(6U);
|
||||
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);
|
||||
if (enable_dyanmic_file_size) {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file1, expected_file2});
|
||||
} else {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file_disable_dynamic_file_size});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, CutToAlignGrandparentBoundary) {
|
||||
TEST_P(CompactionJobDynamicFileSizeTest, CutToAlignGrandparentBoundary) {
|
||||
bool enable_dyanmic_file_size = GetParam();
|
||||
cf_options_.level_compaction_dynamic_file_size = enable_dyanmic_file_size;
|
||||
NewDB();
|
||||
|
||||
// MockTable has 1 byte per entry by default and each file is 10 bytes.
|
||||
@@ -1940,15 +1964,40 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundary) {
|
||||
}
|
||||
expected_file2.emplace_back(KeyStr("s", 4U, kTypeValue), "val");
|
||||
|
||||
mock::KVVector expected_file_disable_dynamic_file_size1;
|
||||
for (char i = 0; i < 10; i++) {
|
||||
expected_file_disable_dynamic_file_size1.emplace_back(
|
||||
KeyStr(std::string(1, ch + i), i + 10, kTypeValue),
|
||||
"val" + std::to_string(i));
|
||||
}
|
||||
|
||||
mock::KVVector expected_file_disable_dynamic_file_size2;
|
||||
for (char i = 10; i < 12; i++) {
|
||||
expected_file_disable_dynamic_file_size2.emplace_back(
|
||||
KeyStr(std::string(1, ch + i), i + 10, kTypeValue),
|
||||
"val" + std::to_string(i));
|
||||
}
|
||||
|
||||
expected_file_disable_dynamic_file_size2.emplace_back(
|
||||
KeyStr("s", 4U, kTypeValue), "val");
|
||||
|
||||
SetLastSequence(22U);
|
||||
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);
|
||||
if (enable_dyanmic_file_size) {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file1, expected_file2});
|
||||
} else {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file_disable_dynamic_file_size1,
|
||||
expected_file_disable_dynamic_file_size2});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
|
||||
TEST_P(CompactionJobDynamicFileSizeTest, CutToAlignGrandparentBoundarySameKey) {
|
||||
bool enable_dyanmic_file_size = GetParam();
|
||||
cf_options_.level_compaction_dynamic_file_size = enable_dyanmic_file_size;
|
||||
NewDB();
|
||||
|
||||
// MockTable has 1 byte per entry by default and each file is 10 bytes.
|
||||
@@ -1985,9 +2034,13 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
|
||||
AddMockFile(file5, 2);
|
||||
|
||||
mock::KVVector expected_file1;
|
||||
mock::KVVector expected_file_disable_dynamic_file_size;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
expected_file1.emplace_back(KeyStr("a", 100 - i, kTypeValue),
|
||||
"val" + std::to_string(100 - i));
|
||||
expected_file_disable_dynamic_file_size.emplace_back(
|
||||
KeyStr("a", 100 - i, kTypeValue), "val" + std::to_string(100 - i));
|
||||
}
|
||||
|
||||
// make sure `b` is cut in a separated file (so internally it's not using
|
||||
@@ -1996,6 +2049,9 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
|
||||
auto expected_file2 =
|
||||
mock::MakeMockFile({{KeyStr("b", 90U, kTypeValue), "valb"}});
|
||||
|
||||
expected_file_disable_dynamic_file_size.emplace_back(
|
||||
KeyStr("b", 90U, kTypeValue), "valb");
|
||||
|
||||
SetLastSequence(122U);
|
||||
const std::vector<int> input_levels = {0, 1};
|
||||
auto lvl0_files = cfd_->current()->storage_info()->LevelFiles(0);
|
||||
@@ -2006,13 +2062,20 @@ TEST_F(CompactionJobTest, CutToAlignGrandparentBoundarySameKey) {
|
||||
for (int i = 80; i <= 100; i++) {
|
||||
snapshots.emplace_back(i);
|
||||
}
|
||||
if (enable_dyanmic_file_size) {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file1, expected_file2}, snapshots);
|
||||
} else {
|
||||
RunCompaction({lvl0_files, lvl1_files}, input_levels,
|
||||
{expected_file_disable_dynamic_file_size}, snapshots);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, CutForMaxCompactionBytesSameKey) {
|
||||
TEST_P(CompactionJobDynamicFileSizeTest, CutForMaxCompactionBytesSameKey) {
|
||||
// dynamic_file_size option should have no impact on cutting for max
|
||||
// compaction bytes.
|
||||
bool enable_dyanmic_file_size = GetParam();
|
||||
cf_options_.level_compaction_dynamic_file_size = enable_dyanmic_file_size;
|
||||
|
||||
NewDB();
|
||||
mutable_cf_options_.target_file_size_base = 80;
|
||||
@@ -2069,6 +2132,9 @@ TEST_F(CompactionJobTest, CutForMaxCompactionBytesSameKey) {
|
||||
{expected_file1, expected_file2, expected_file3}, snapshots);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(CompactionJobDynamicFileSizeTest,
|
||||
CompactionJobDynamicFileSizeTest, testing::Bool());
|
||||
|
||||
class CompactionJobTimestampTest : public CompactionJobTestBase {
|
||||
public:
|
||||
CompactionJobTimestampTest()
|
||||
|
||||
@@ -25,13 +25,11 @@ Status CompactionOutputs::Finish(
|
||||
assert(meta != nullptr);
|
||||
Status s = intput_status;
|
||||
if (s.ok()) {
|
||||
SeqnoToTimeMapping relevant_mapping;
|
||||
relevant_mapping.CopyFromSeqnoRange(
|
||||
seqno_to_time_mapping,
|
||||
std::min(smallest_preferred_seqno_, meta->fd.smallest_seqno),
|
||||
meta->fd.largest_seqno);
|
||||
relevant_mapping.SetCapacity(kMaxSeqnoTimePairsPerSST);
|
||||
builder_->SetSeqnoTimeTableProperties(relevant_mapping,
|
||||
std::string seqno_to_time_mapping_str;
|
||||
seqno_to_time_mapping.Encode(
|
||||
seqno_to_time_mapping_str, meta->fd.smallest_seqno,
|
||||
meta->fd.largest_seqno, meta->file_creation_time);
|
||||
builder_->SetSeqnoTimeTableProperties(seqno_to_time_mapping_str,
|
||||
meta->oldest_ancester_time);
|
||||
s = builder_->Finish();
|
||||
|
||||
@@ -64,15 +62,12 @@ IOStatus CompactionOutputs::WriterSyncClose(const Status& input_status,
|
||||
Statistics* statistics,
|
||||
bool use_fsync) {
|
||||
IOStatus io_s;
|
||||
IOOptions opts;
|
||||
io_s = WritableFileWriter::PrepareIOOptions(
|
||||
WriteOptions(Env::IOActivity::kCompaction), opts);
|
||||
if (input_status.ok() && io_s.ok()) {
|
||||
if (input_status.ok()) {
|
||||
StopWatch sw(clock, statistics, COMPACTION_OUTFILE_SYNC_MICROS);
|
||||
io_s = file_writer_->Sync(opts, use_fsync);
|
||||
io_s = file_writer_->Sync(use_fsync);
|
||||
}
|
||||
if (input_status.ok() && io_s.ok()) {
|
||||
io_s = file_writer_->Close(opts);
|
||||
io_s = file_writer_->Close();
|
||||
}
|
||||
|
||||
if (input_status.ok() && io_s.ok()) {
|
||||
@@ -322,6 +317,7 @@ bool CompactionOutputs::ShouldStopBefore(const CompactionIterator& c_iter) {
|
||||
being_grandparent_gap_ ? 2 : 3;
|
||||
if (compaction_->immutable_options()->compaction_style ==
|
||||
kCompactionStyleLevel &&
|
||||
compaction_->immutable_options()->level_compaction_dynamic_file_size &&
|
||||
num_grandparent_boundaries_crossed >=
|
||||
num_skippable_boundaries_crossed &&
|
||||
grandparent_overlapped_bytes_ - previous_overlapped_bytes >
|
||||
@@ -343,6 +339,7 @@ bool CompactionOutputs::ShouldStopBefore(const CompactionIterator& c_iter) {
|
||||
// improvement.
|
||||
if (compaction_->immutable_options()->compaction_style ==
|
||||
kCompactionStyleLevel &&
|
||||
compaction_->immutable_options()->level_compaction_dynamic_file_size &&
|
||||
current_output_file_size_ >=
|
||||
((compaction_->target_output_file_size() + 99) / 100) *
|
||||
(50 + std::min(grandparent_boundary_switched_num_ * 5,
|
||||
@@ -424,11 +421,6 @@ Status CompactionOutputs::AddToOutput(
|
||||
}
|
||||
|
||||
const ParsedInternalKey& ikey = c_iter.ikey();
|
||||
if (ikey.type == kTypeValuePreferredSeqno) {
|
||||
SequenceNumber preferred_seqno = ParsePackedValueForSeqno(value);
|
||||
smallest_preferred_seqno_ =
|
||||
std::min(smallest_preferred_seqno_, preferred_seqno);
|
||||
}
|
||||
s = current_output().meta.UpdateBoundaries(key, value, ikey.sequence,
|
||||
ikey.type);
|
||||
|
||||
|
||||
@@ -30,9 +30,11 @@ class CompactionOutputs {
|
||||
// compaction output file
|
||||
struct Output {
|
||||
Output(FileMetaData&& _meta, const InternalKeyComparator& _icmp,
|
||||
bool _enable_hash, bool _finished, uint64_t precalculated_hash)
|
||||
bool _enable_order_check, bool _enable_hash, bool _finished,
|
||||
uint64_t precalculated_hash)
|
||||
: meta(std::move(_meta)),
|
||||
validator(_icmp, _enable_hash, precalculated_hash),
|
||||
validator(_icmp, _enable_order_check, _enable_hash,
|
||||
precalculated_hash),
|
||||
finished(_finished) {}
|
||||
FileMetaData meta;
|
||||
OutputValidator validator;
|
||||
@@ -47,10 +49,10 @@ class CompactionOutputs {
|
||||
|
||||
// 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);
|
||||
bool enable_order_check, bool enable_hash,
|
||||
bool finished = false, uint64_t precalculated_hash = 0) {
|
||||
outputs_.emplace_back(std::move(meta), icmp, enable_order_check,
|
||||
enable_hash, finished, precalculated_hash);
|
||||
}
|
||||
|
||||
// Set new table builder for the current output
|
||||
@@ -297,7 +299,6 @@ class CompactionOutputs {
|
||||
std::unique_ptr<TableBuilder> builder_;
|
||||
std::unique_ptr<WritableFileWriter> file_writer_;
|
||||
uint64_t current_output_file_size_ = 0;
|
||||
SequenceNumber smallest_preferred_seqno_ = kMaxSequenceNumber;
|
||||
|
||||
// all the compaction outputs so far
|
||||
std::vector<Output> outputs_;
|
||||
|
||||
@@ -130,7 +130,7 @@ CompactionPicker::CompactionPicker(const ImmutableOptions& ioptions,
|
||||
const InternalKeyComparator* icmp)
|
||||
: ioptions_(ioptions), icmp_(icmp) {}
|
||||
|
||||
CompactionPicker::~CompactionPicker() = default;
|
||||
CompactionPicker::~CompactionPicker() {}
|
||||
|
||||
// Delete this compaction from the list of running compactions.
|
||||
void CompactionPicker::ReleaseCompactionFiles(Compaction* c, Status status) {
|
||||
@@ -340,8 +340,8 @@ Compaction* CompactionPicker::CompactFiles(
|
||||
#ifndef NDEBUG
|
||||
assert(input_files.size());
|
||||
// This compaction output should not overlap with a running compaction as
|
||||
// `SanitizeAndConvertCompactionInputFiles` should've checked earlier and db
|
||||
// mutex shouldn't have been released since.
|
||||
// `SanitizeCompactionInputFiles` should've checked earlier and db mutex
|
||||
// shouldn't have been released since.
|
||||
int start_level = Compaction::kInvalidLevel;
|
||||
for (const auto& in : input_files) {
|
||||
// input_files should already be sorted by level
|
||||
@@ -377,8 +377,7 @@ Compaction* CompactionPicker::CompactFiles(
|
||||
output_level, compact_options.output_file_size_limit,
|
||||
mutable_cf_options.max_compaction_bytes, output_path_id, compression_type,
|
||||
GetCompressionOptions(mutable_cf_options, vstorage, output_level),
|
||||
mutable_cf_options.default_write_temperature,
|
||||
compact_options.max_subcompactions,
|
||||
Temperature::kUnknown, compact_options.max_subcompactions,
|
||||
/* grandparents */ {}, true);
|
||||
RegisterCompaction(c);
|
||||
return c;
|
||||
@@ -501,6 +500,7 @@ bool CompactionPicker::SetupOtherInputs(
|
||||
// user key, while excluding other entries for the same user key. This
|
||||
// can happen when one user key spans multiple files.
|
||||
if (!output_level_inputs->empty()) {
|
||||
const uint64_t limit = mutable_cf_options.max_compaction_bytes;
|
||||
const uint64_t output_level_inputs_size =
|
||||
TotalFileSize(output_level_inputs->files);
|
||||
const uint64_t inputs_size = TotalFileSize(inputs->files);
|
||||
@@ -526,15 +526,10 @@ bool CompactionPicker::SetupOtherInputs(
|
||||
if (!ExpandInputsToCleanCut(cf_name, vstorage, &expanded_inputs)) {
|
||||
try_overlapping_inputs = false;
|
||||
}
|
||||
// It helps to reduce write amp and avoid a further separate compaction
|
||||
// to include more input level files without expanding output level files.
|
||||
// So we apply a softer limit. We still need a limit to avoid overly large
|
||||
// compactions and potential high space amp spikes.
|
||||
const uint64_t limit =
|
||||
MultiplyCheckOverflow(mutable_cf_options.max_compaction_bytes, 2.0);
|
||||
if (try_overlapping_inputs && expanded_inputs.size() > inputs->size() &&
|
||||
!AreFilesInCompaction(expanded_inputs.files) &&
|
||||
output_level_inputs_size + expanded_inputs_size < limit) {
|
||||
(mutable_cf_options.ignore_max_compaction_bytes_for_input ||
|
||||
output_level_inputs_size + expanded_inputs_size < limit) &&
|
||||
!AreFilesInCompaction(expanded_inputs.files)) {
|
||||
InternalKey new_start, new_limit;
|
||||
GetRange(expanded_inputs, &new_start, &new_limit);
|
||||
CompactionInputFiles expanded_output_level_inputs;
|
||||
@@ -556,8 +551,9 @@ bool CompactionPicker::SetupOtherInputs(
|
||||
base_index, nullptr);
|
||||
expanded_inputs_size = TotalFileSize(expanded_inputs.files);
|
||||
if (expanded_inputs.size() > inputs->size() &&
|
||||
!AreFilesInCompaction(expanded_inputs.files) &&
|
||||
(output_level_inputs_size + expanded_inputs_size) < limit) {
|
||||
(mutable_cf_options.ignore_max_compaction_bytes_for_input ||
|
||||
output_level_inputs_size + expanded_inputs_size < limit) &&
|
||||
!AreFilesInCompaction(expanded_inputs.files)) {
|
||||
expand_inputs = true;
|
||||
}
|
||||
}
|
||||
@@ -674,8 +670,7 @@ Compaction* CompactionPicker::CompactRange(
|
||||
compact_range_options.target_path_id,
|
||||
GetCompressionType(vstorage, mutable_cf_options, output_level, 1),
|
||||
GetCompressionOptions(mutable_cf_options, vstorage, output_level),
|
||||
mutable_cf_options.default_write_temperature,
|
||||
compact_range_options.max_subcompactions,
|
||||
Temperature::kUnknown, compact_range_options.max_subcompactions,
|
||||
/* grandparents */ {}, /* is manual */ true, trim_ts, /* score */ -1,
|
||||
/* deletion_compaction */ false, /* l0_files_might_overlap */ true,
|
||||
CompactionReason::kUnknown,
|
||||
@@ -863,9 +858,8 @@ Compaction* CompactionPicker::CompactRange(
|
||||
GetCompressionType(vstorage, mutable_cf_options, output_level,
|
||||
vstorage->base_level()),
|
||||
GetCompressionOptions(mutable_cf_options, vstorage, output_level),
|
||||
mutable_cf_options.default_write_temperature,
|
||||
compact_range_options.max_subcompactions, std::move(grandparents),
|
||||
/* is manual */ true, trim_ts, /* score */ -1,
|
||||
Temperature::kUnknown, compact_range_options.max_subcompactions,
|
||||
std::move(grandparents), /* is manual */ true, trim_ts, /* score */ -1,
|
||||
/* deletion_compaction */ false, /* l0_files_might_overlap */ true,
|
||||
CompactionReason::kUnknown,
|
||||
compact_range_options.blob_garbage_collection_policy,
|
||||
@@ -1040,18 +1034,19 @@ Status CompactionPicker::SanitizeCompactionInputFilesForAllLevels(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RangeOverlapWithCompaction(smallestkey, largestkey, output_level)) {
|
||||
return Status::Aborted(
|
||||
"A running compaction is writing to the same output level in an "
|
||||
"overlapping key range");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status CompactionPicker::SanitizeAndConvertCompactionInputFiles(
|
||||
Status CompactionPicker::SanitizeCompactionInputFiles(
|
||||
std::unordered_set<uint64_t>* input_files,
|
||||
const ColumnFamilyMetaData& cf_meta, const int output_level,
|
||||
const VersionStorageInfo* vstorage,
|
||||
std::vector<CompactionInputFiles>* converted_input_files) const {
|
||||
const ColumnFamilyMetaData& cf_meta, const int output_level) const {
|
||||
assert(static_cast<int>(cf_meta.levels.size()) - 1 ==
|
||||
cf_meta.levels[cf_meta.levels.size() - 1].level);
|
||||
assert(converted_input_files);
|
||||
|
||||
if (output_level >= static_cast<int>(cf_meta.levels.size())) {
|
||||
return Status::InvalidArgument(
|
||||
"Output level for column family " + cf_meta.name +
|
||||
@@ -1077,6 +1072,7 @@ Status CompactionPicker::SanitizeAndConvertCompactionInputFiles(
|
||||
|
||||
Status s = SanitizeCompactionInputFilesForAllLevels(input_files, cf_meta,
|
||||
output_level);
|
||||
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -1117,22 +1113,6 @@ Status CompactionPicker::SanitizeAndConvertCompactionInputFiles(
|
||||
}
|
||||
}
|
||||
|
||||
s = GetCompactionInputsFromFileNumbers(converted_input_files, input_files,
|
||||
vstorage, CompactionOptions());
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
assert(converted_input_files->size() > 0);
|
||||
if (output_level != 0 &&
|
||||
FilesRangeOverlapWithCompaction(
|
||||
*converted_input_files, output_level,
|
||||
Compaction::EvaluatePenultimateLevel(
|
||||
vstorage, ioptions_, (*converted_input_files)[0].level,
|
||||
output_level))) {
|
||||
return Status::Aborted(
|
||||
"A running compaction is writing to the same output level(s) in an "
|
||||
"overlapping key range");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
||||
@@ -86,20 +86,16 @@ class CompactionPicker {
|
||||
|
||||
virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const = 0;
|
||||
|
||||
// Sanitize the input set of compaction input files and convert it to
|
||||
// `std::vector<CompactionInputFiles>` in the output parameter
|
||||
// `converted_input_files`.
|
||||
// When the input parameters do not describe a valid
|
||||
// compaction, the function will try to fix the input_files by adding
|
||||
// necessary files. If it's not possible to convert an invalid input_files
|
||||
// into a valid one by adding more files, the function will return a
|
||||
// non-ok status with specific reason.
|
||||
//
|
||||
Status SanitizeAndConvertCompactionInputFiles(
|
||||
std::unordered_set<uint64_t>* input_files,
|
||||
const ColumnFamilyMetaData& cf_meta, const int output_level,
|
||||
const VersionStorageInfo* vstorage,
|
||||
std::vector<CompactionInputFiles>* converted_input_files) const;
|
||||
// Sanitize the input set of compaction input files.
|
||||
// When the input parameters do not describe a valid compaction, the
|
||||
// function will try to fix the input_files by adding necessary
|
||||
// files. If it's not possible to conver an invalid input_files
|
||||
// into a valid one by adding more files, the function will return a
|
||||
// non-ok status with specific reason.
|
||||
//
|
||||
Status SanitizeCompactionInputFiles(std::unordered_set<uint64_t>* input_files,
|
||||
const ColumnFamilyMetaData& cf_meta,
|
||||
const int output_level) const;
|
||||
|
||||
// Free up the files that participated in a compaction
|
||||
//
|
||||
@@ -113,8 +109,8 @@ class CompactionPicker {
|
||||
// object.
|
||||
//
|
||||
// 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.
|
||||
// `SanitizeCompactionInputFiles` earlier. The lock should not be released
|
||||
// between that call and this one.
|
||||
Compaction* CompactFiles(const CompactionOptions& compact_options,
|
||||
const std::vector<CompactionInputFiles>& input_files,
|
||||
int output_level, VersionStorageInfo* vstorage,
|
||||
@@ -124,7 +120,6 @@ class CompactionPicker {
|
||||
|
||||
// Converts a set of compaction input file numbers into
|
||||
// a list of CompactionInputFiles.
|
||||
// TODO(hx235): remove the unused paramter `compact_options`
|
||||
Status GetCompactionInputsFromFileNumbers(
|
||||
std::vector<CompactionInputFiles>* input_files,
|
||||
std::unordered_set<uint64_t>* input_set,
|
||||
@@ -230,8 +225,8 @@ class CompactionPicker {
|
||||
protected:
|
||||
const ImmutableOptions& ioptions_;
|
||||
|
||||
// A helper function to SanitizeAndConvertCompactionInputFiles() that
|
||||
// sanitizes "input_files" by adding necessary files.
|
||||
// A helper function to SanitizeCompactionInputFiles() that
|
||||
// sanitizes "input_files" by adding necessary files.
|
||||
virtual Status SanitizeCompactionInputFilesForAllLevels(
|
||||
std::unordered_set<uint64_t>* input_files,
|
||||
const ColumnFamilyMetaData& cf_meta, const int output_level) const;
|
||||
@@ -282,7 +277,8 @@ class NullCompactionPicker : public CompactionPicker {
|
||||
}
|
||||
|
||||
// Always returns false.
|
||||
bool NeedsCompaction(const VersionStorageInfo* /*vstorage*/) const override {
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* /*vstorage*/) const override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,8 +116,7 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, mutable_db_options,
|
||||
std::move(inputs), 0, 0, 0, 0, kNoCompression,
|
||||
mutable_cf_options.compression_opts,
|
||||
mutable_cf_options.default_write_temperature,
|
||||
mutable_cf_options.compression_opts, Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, {}, /* is manual */ false,
|
||||
/* trim_ts */ "", vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ true, /* l0_files_might_overlap */ true,
|
||||
@@ -186,8 +185,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
|
||||
{comp_inputs}, 0, 16 * 1024 * 1024 /* output file size limit */,
|
||||
0 /* max compaction bytes, not applicable */,
|
||||
0 /* output path ID */, mutable_cf_options.compression,
|
||||
mutable_cf_options.compression_opts,
|
||||
mutable_cf_options.default_write_temperature,
|
||||
mutable_cf_options.compression_opts, Temperature::kUnknown,
|
||||
0 /* max_subcompactions */, {}, /* is manual */ false,
|
||||
/* trim_ts */ "", vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ false,
|
||||
@@ -282,8 +280,7 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
|
||||
/* target_file_size */ 0,
|
||||
/* max_compaction_bytes */ 0,
|
||||
/* output_path_id */ 0, kNoCompression,
|
||||
mutable_cf_options.compression_opts,
|
||||
mutable_cf_options.default_write_temperature,
|
||||
mutable_cf_options.compression_opts, Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, {}, /* is manual */ false,
|
||||
/* trim_ts */ "", vstorage->CompactionScore(0),
|
||||
/* is deletion compaction */ true,
|
||||
@@ -417,7 +414,6 @@ Compaction* FIFOCompactionPicker::PickTemperatureChangeCompaction(
|
||||
if (inputs[0].files.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
assert(compaction_target_temp != Temperature::kLastTemperature);
|
||||
|
||||
Compaction* c = new Compaction(
|
||||
vstorage, ioptions_, mutable_cf_options, mutable_db_options,
|
||||
|
||||
@@ -18,27 +18,26 @@ class FIFOCompactionPicker : public CompactionPicker {
|
||||
const InternalKeyComparator* icmp)
|
||||
: CompactionPicker(ioptions, icmp) {}
|
||||
|
||||
Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
VersionStorageInfo* version,
|
||||
LogBuffer* log_buffer) override;
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
VersionStorageInfo* version,
|
||||
LogBuffer* log_buffer) override;
|
||||
|
||||
Compaction* CompactRange(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
VersionStorageInfo* vstorage, int input_level,
|
||||
int output_level,
|
||||
const CompactRangeOptions& compact_range_options,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict,
|
||||
uint64_t max_file_num_to_ignore,
|
||||
const std::string& trim_ts) override;
|
||||
virtual Compaction* CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options, VersionStorageInfo* vstorage,
|
||||
int input_level, int output_level,
|
||||
const CompactRangeOptions& compact_range_options,
|
||||
const InternalKey* begin, const InternalKey* end,
|
||||
InternalKey** compaction_end, bool* manual_conflict,
|
||||
uint64_t max_file_num_to_ignore, const std::string& trim_ts) override;
|
||||
|
||||
// The maximum allowed output level. Always returns 0.
|
||||
int MaxOutputLevel() const override { return 0; }
|
||||
virtual int MaxOutputLevel() const override { return 0; }
|
||||
|
||||
bool NeedsCompaction(const VersionStorageInfo* vstorage) const override;
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const override;
|
||||
|
||||
private:
|
||||
Compaction* PickTTLCompaction(const std::string& cf_name,
|
||||
|
||||
@@ -45,13 +45,6 @@ bool LevelCompactionPicker::NeedsCompaction(
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum class CompactToNextLevel {
|
||||
kNo, // compact to the same level as the input file
|
||||
kYes, // compact to the next level except the last level to the same level
|
||||
kSkipLastLevel, // compact to the next level but skip the last level
|
||||
};
|
||||
|
||||
// A class to build a leveled compaction step-by-step.
|
||||
class LevelCompactionBuilder {
|
||||
public:
|
||||
@@ -113,15 +106,6 @@ class LevelCompactionBuilder {
|
||||
// otherwise, returns false.
|
||||
bool PickIntraL0Compaction();
|
||||
|
||||
// When total L0 size is small compared to Lbase, try to pick intra-L0
|
||||
// compaction starting from the newest L0 file. This helps to prevent
|
||||
// L0->Lbase compaction with large write-amp.
|
||||
//
|
||||
// Returns true iff an intra-L0 compaction is picked.
|
||||
// `start_level_inputs_` and `output_level_` will be updated accordingly if
|
||||
// a compaction is picked.
|
||||
bool PickSizeBasedIntraL0Compaction();
|
||||
|
||||
// Return true if TrivialMove is extended. `start_index` is the index of
|
||||
// the initial file picked, which should already be in `start_level_inputs_`.
|
||||
bool TryExtendNonL0TrivialMove(int start_index,
|
||||
@@ -131,10 +115,9 @@ class LevelCompactionBuilder {
|
||||
// level_files is a vector of (level, file metadata) in ascending order of
|
||||
// level. If compact_to_next_level is true, compact the file to the next
|
||||
// level, otherwise, compact to the same level as the input file.
|
||||
// If skip_last_level is true, skip the last level.
|
||||
void PickFileToCompact(
|
||||
const autovector<std::pair<int, FileMetaData*>>& level_files,
|
||||
CompactToNextLevel compact_to_next_level);
|
||||
bool compact_to_next_level);
|
||||
|
||||
const std::string& cf_name_;
|
||||
VersionStorageInfo* vstorage_;
|
||||
@@ -166,24 +149,20 @@ class LevelCompactionBuilder {
|
||||
|
||||
void LevelCompactionBuilder::PickFileToCompact(
|
||||
const autovector<std::pair<int, FileMetaData*>>& level_files,
|
||||
CompactToNextLevel compact_to_next_level) {
|
||||
bool compact_to_next_level) {
|
||||
for (auto& level_file : level_files) {
|
||||
// If it's being compacted it has nothing to do here.
|
||||
// If this assert() fails that means that some function marked some
|
||||
// files as being_compacted, but didn't call ComputeCompactionScore()
|
||||
assert(!level_file.second->being_compacted);
|
||||
start_level_ = level_file.first;
|
||||
if ((compact_to_next_level == CompactToNextLevel::kSkipLastLevel &&
|
||||
if ((compact_to_next_level &&
|
||||
start_level_ == vstorage_->num_non_empty_levels() - 1) ||
|
||||
(start_level_ == 0 &&
|
||||
!compaction_picker_->level0_compactions_in_progress()->empty())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compact to the next level only if the file is not in the last level and
|
||||
// compact_to_next_level is kYes or kSkipLastLevel.
|
||||
if (compact_to_next_level != CompactToNextLevel::kNo &&
|
||||
(start_level_ < vstorage_->num_non_empty_levels() - 1)) {
|
||||
if (compact_to_next_level) {
|
||||
output_level_ =
|
||||
(start_level_ == 0) ? vstorage_->base_level() : start_level_ + 1;
|
||||
} else {
|
||||
@@ -269,8 +248,7 @@ void LevelCompactionBuilder::SetupInitialFiles() {
|
||||
}
|
||||
|
||||
// Bottommost Files Compaction on deleting tombstones
|
||||
PickFileToCompact(vstorage_->BottommostFilesMarkedForCompaction(),
|
||||
CompactToNextLevel::kNo);
|
||||
PickFileToCompact(vstorage_->BottommostFilesMarkedForCompaction(), false);
|
||||
if (!start_level_inputs_.empty()) {
|
||||
compaction_reason_ = CompactionReason::kBottommostFiles;
|
||||
return;
|
||||
@@ -296,26 +274,21 @@ void LevelCompactionBuilder::SetupInitialFiles() {
|
||||
}
|
||||
}
|
||||
|
||||
PickFileToCompact(vstorage_->ExpiredTtlFiles(),
|
||||
CompactToNextLevel::kSkipLastLevel);
|
||||
PickFileToCompact(vstorage_->ExpiredTtlFiles(), true);
|
||||
if (!start_level_inputs_.empty()) {
|
||||
compaction_reason_ = CompactionReason::kTtl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Periodic Compaction
|
||||
PickFileToCompact(vstorage_->FilesMarkedForPeriodicCompaction(),
|
||||
ioptions_.level_compaction_dynamic_level_bytes
|
||||
? CompactToNextLevel::kYes
|
||||
: CompactToNextLevel::kNo);
|
||||
PickFileToCompact(vstorage_->FilesMarkedForPeriodicCompaction(), false);
|
||||
if (!start_level_inputs_.empty()) {
|
||||
compaction_reason_ = CompactionReason::kPeriodicCompaction;
|
||||
return;
|
||||
}
|
||||
|
||||
// Forced blob garbage collection
|
||||
PickFileToCompact(vstorage_->FilesMarkedForForcedBlobGC(),
|
||||
CompactToNextLevel::kNo);
|
||||
PickFileToCompact(vstorage_->FilesMarkedForForcedBlobGC(), false);
|
||||
if (!start_level_inputs_.empty()) {
|
||||
compaction_reason_ = CompactionReason::kForcedBlobGC;
|
||||
return;
|
||||
@@ -355,9 +328,7 @@ void LevelCompactionBuilder::SetupOtherFilesWithRoundRobinExpansion() {
|
||||
TEST_SYNC_POINT("LevelCompactionPicker::RoundRobin");
|
||||
|
||||
// Only expand the inputs when we have selected a file in start_level_inputs_
|
||||
if (start_level_inputs_.size() == 0) {
|
||||
return;
|
||||
}
|
||||
if (start_level_inputs_.size() == 0) return;
|
||||
|
||||
uint64_t start_lvl_bytes_no_compacting = 0;
|
||||
uint64_t curr_bytes_to_compact = 0;
|
||||
@@ -553,7 +524,7 @@ Compaction* LevelCompactionBuilder::GetCompaction() {
|
||||
GetCompressionType(vstorage_, mutable_cf_options_, output_level_,
|
||||
vstorage_->base_level()),
|
||||
GetCompressionOptions(mutable_cf_options_, vstorage_, output_level_),
|
||||
mutable_cf_options_.default_write_temperature,
|
||||
Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, std::move(grandparents_), is_manual_,
|
||||
/* trim_ts */ "", start_level_score_, false /* deletion_compaction */,
|
||||
l0_files_might_overlap, compaction_reason_);
|
||||
@@ -787,9 +758,6 @@ bool LevelCompactionBuilder::PickFileToCompact() {
|
||||
// being compacted at level 0.
|
||||
if (start_level_ == 0 &&
|
||||
!compaction_picker_->level0_compactions_in_progress()->empty()) {
|
||||
if (PickSizeBasedIntraL0Compaction()) {
|
||||
return true;
|
||||
}
|
||||
TEST_SYNC_POINT("LevelCompactionPicker::PickCompactionBySize:0");
|
||||
return false;
|
||||
}
|
||||
@@ -802,9 +770,6 @@ bool LevelCompactionBuilder::PickFileToCompact() {
|
||||
if (TryPickL0TrivialMove()) {
|
||||
return true;
|
||||
}
|
||||
if (start_level_ == 0 && PickSizeBasedIntraL0Compaction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<FileMetaData*>& level_files =
|
||||
vstorage_->LevelFiles(start_level_);
|
||||
@@ -909,60 +874,6 @@ bool LevelCompactionBuilder::PickIntraL0Compaction() {
|
||||
mutable_cf_options_.max_compaction_bytes,
|
||||
&start_level_inputs_);
|
||||
}
|
||||
|
||||
bool LevelCompactionBuilder::PickSizeBasedIntraL0Compaction() {
|
||||
assert(start_level_ == 0);
|
||||
int base_level = vstorage_->base_level();
|
||||
if (base_level <= 0) {
|
||||
return false;
|
||||
}
|
||||
const std::vector<FileMetaData*>& l0_files =
|
||||
vstorage_->LevelFiles(/*level=*/0);
|
||||
size_t min_num_file =
|
||||
std::max(2, mutable_cf_options_.level0_file_num_compaction_trigger);
|
||||
if (l0_files.size() < min_num_file) {
|
||||
return false;
|
||||
}
|
||||
uint64_t l0_size = 0;
|
||||
for (const auto& file : l0_files) {
|
||||
assert(file->compensated_file_size >= file->fd.GetFileSize());
|
||||
// Compact down L0s with more deletions.
|
||||
l0_size += file->compensated_file_size;
|
||||
}
|
||||
|
||||
// Avoid L0->Lbase compactions that are inefficient for write-amp.
|
||||
const double kMultiplier =
|
||||
std::max(10.0, mutable_cf_options_.max_bytes_for_level_multiplier) * 2;
|
||||
const uint64_t min_lbase_size = MultiplyCheckOverflow(l0_size, kMultiplier);
|
||||
assert(min_lbase_size >= l0_size);
|
||||
const std::vector<FileMetaData*>& lbase_files =
|
||||
vstorage_->LevelFiles(/*level=*/base_level);
|
||||
uint64_t lbase_size = 0;
|
||||
for (const auto& file : lbase_files) {
|
||||
lbase_size += file->fd.GetFileSize();
|
||||
if (lbase_size > min_lbase_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lbase_size <= min_lbase_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start_level_inputs_.clear();
|
||||
start_level_inputs_.level = 0;
|
||||
for (const auto& file : l0_files) {
|
||||
if (file->being_compacted) {
|
||||
break;
|
||||
}
|
||||
start_level_inputs_.files.push_back(file);
|
||||
}
|
||||
if (start_level_inputs_.files.size() < min_num_file) {
|
||||
start_level_inputs_.clear();
|
||||
return false;
|
||||
}
|
||||
output_level_ = 0;
|
||||
return true /* picked an intra-L0 compaction */;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Compaction* LevelCompactionPicker::PickCompaction(
|
||||
|
||||
@@ -20,13 +20,14 @@ class LevelCompactionPicker : public CompactionPicker {
|
||||
LevelCompactionPicker(const ImmutableOptions& ioptions,
|
||||
const InternalKeyComparator* icmp)
|
||||
: CompactionPicker(ioptions, icmp) {}
|
||||
Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) override;
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const MutableDBOptions& mutable_db_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) override;
|
||||
|
||||
bool NeedsCompaction(const VersionStorageInfo* vstorage) const override;
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const override;
|
||||
};
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -77,7 +77,7 @@ class CompactionPickerTestBase : public testing::Test {
|
||||
ioptions_.level_compaction_dynamic_level_bytes = false;
|
||||
}
|
||||
|
||||
~CompactionPickerTestBase() override = default;
|
||||
~CompactionPickerTestBase() override {}
|
||||
|
||||
void NewVersionStorage(int num_levels, CompactionStyle style) {
|
||||
DeleteVersionStorage();
|
||||
@@ -214,10 +214,7 @@ class CompactionPickerTest : public CompactionPickerTestBase {
|
||||
explicit CompactionPickerTest()
|
||||
: CompactionPickerTestBase(BytewiseComparator()) {}
|
||||
|
||||
~CompactionPickerTest() override {
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
~CompactionPickerTest() override {}
|
||||
};
|
||||
|
||||
class CompactionPickerU64TsTest : public CompactionPickerTestBase {
|
||||
@@ -225,7 +222,7 @@ class CompactionPickerU64TsTest : public CompactionPickerTestBase {
|
||||
explicit CompactionPickerU64TsTest()
|
||||
: CompactionPickerTestBase(test::BytewiseComparatorWithU64TsWrapper()) {}
|
||||
|
||||
~CompactionPickerU64TsTest() override = default;
|
||||
~CompactionPickerU64TsTest() override {}
|
||||
};
|
||||
|
||||
TEST_F(CompactionPickerTest, Empty) {
|
||||
@@ -1446,12 +1443,15 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping4) {
|
||||
ioptions_.compaction_pri = kMinOverlappingRatio;
|
||||
mutable_cf_options_.max_bytes_for_level_base = 10000000;
|
||||
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
||||
mutable_cf_options_.ignore_max_compaction_bytes_for_input = false;
|
||||
|
||||
// Overlaps with file 26, 27, ratio is
|
||||
// (60000000U + 60000000U / 180000000U) = 0.67
|
||||
// file 7 and 8 over lap with the same file, but file 8 is smaller so
|
||||
// it will be picked.
|
||||
// Overlaps with file 26, 27. And the file is compensated so will be
|
||||
// picked up.
|
||||
Add(2, 6U, "150", "167", 60000000U, 0, 100, 100, 180000000U);
|
||||
Add(2, 7U, "178", "189", 60000000U); // Overlaps with file 28
|
||||
Add(2, 8U, "401", "500", 61000000U); // Overlaps with file 29
|
||||
Add(2, 7U, "168", "169", 60000000U); // Overlaps with file 27
|
||||
Add(2, 8U, "201", "300", 61000000U); // Overlaps with file 28
|
||||
|
||||
Add(3, 26U, "160", "165", 60000000U);
|
||||
// Boosted file size in output level is not considered.
|
||||
@@ -1465,7 +1465,7 @@ TEST_F(CompactionPickerTest, CompactionPriMinOverlapping4) {
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
// Picking file 6 because overlapping ratio is the biggest.
|
||||
// Picking file 8 because overlapping ratio is the biggest.
|
||||
ASSERT_EQ(6U, compaction->input(0, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
@@ -2468,60 +2468,20 @@ TEST_F(CompactionPickerTest, IsBottommostLevelTest) {
|
||||
DeleteVersionStorage();
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, CompactionLimitWhenAddFileFromInputLevel) {
|
||||
TEST_F(CompactionPickerTest, MaxCompactionBytesHit) {
|
||||
mutable_cf_options_.max_bytes_for_level_base = 1000000u;
|
||||
mutable_cf_options_.max_compaction_bytes = 800000u;
|
||||
mutable_cf_options_.ignore_max_compaction_bytes_for_input = false;
|
||||
ioptions_.level_compaction_dynamic_level_bytes = false;
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
// A compaction should be triggered and pick file 2 and 5.
|
||||
// It pulls in other compaction input file from the input level L1
|
||||
// without pulling in more output level files.
|
||||
// Files 1, 3, 4 are eligible.
|
||||
// File 6 is excluded since it overlaps with file 7.
|
||||
// It can expand input level since in this case, the limit on compaction size
|
||||
// is 2 * max_compaction_bytes.
|
||||
// It can expand because adding file 1 and 3, the compaction size will
|
||||
// exceed mutable_cf_options_.max_bytes_for_level_base.
|
||||
Add(1, 1U, "100", "150", 300000U);
|
||||
Add(1, 2U, "151", "200", 300001U, 0, 0);
|
||||
Add(1, 3U, "201", "250", 300000U, 0, 0);
|
||||
Add(1, 4U, "251", "300", 300000U, 0, 0);
|
||||
Add(1, 6U, "325", "400", 300000U, 0, 0);
|
||||
Add(2, 5U, "100", "350", 1U);
|
||||
Add(2, 7U, "375", "425", 1U);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(2U, compaction->num_input_levels());
|
||||
ASSERT_EQ(4U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(1U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
||||
ASSERT_EQ(3U, compaction->input(0, 2)->fd.GetNumber());
|
||||
ASSERT_EQ(4U, compaction->input(0, 3)->fd.GetNumber());
|
||||
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, HitCompactionLimitWhenAddFileFromInputLevel) {
|
||||
mutable_cf_options_.max_bytes_for_level_base = 1000000u;
|
||||
mutable_cf_options_.max_compaction_bytes = 800000u;
|
||||
ioptions_.level_compaction_dynamic_level_bytes = false;
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
// A compaction should be triggered and pick file 2 and 5.
|
||||
// It pulls in other compaction input file from the input level L1
|
||||
// without pulling in more output level files.
|
||||
// Files 1, 3, 4 are eligible.
|
||||
// File 6 is excluded since it overlaps with file 7.
|
||||
// It can not expand input level since total compaction size hit the limit
|
||||
// 2 * max_compaction_bytes.
|
||||
Add(1, 1U, "100", "150", 400000U);
|
||||
Add(1, 2U, "151", "200", 400001U, 0, 0);
|
||||
Add(1, 3U, "201", "250", 400000U, 0, 0);
|
||||
Add(1, 4U, "251", "300", 400000U, 0, 0);
|
||||
Add(1, 6U, "325", "400", 400000U, 0, 0);
|
||||
Add(2, 5U, "100", "350", 1U);
|
||||
Add(2, 7U, "375", "425", 1U);
|
||||
Add(2, 5U, "100", "256", 1U);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
@@ -2535,6 +2495,34 @@ TEST_F(CompactionPickerTest, HitCompactionLimitWhenAddFileFromInputLevel) {
|
||||
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, MaxCompactionBytesNotHit) {
|
||||
mutable_cf_options_.max_bytes_for_level_base = 800000u;
|
||||
mutable_cf_options_.max_compaction_bytes = 1000000u;
|
||||
mutable_cf_options_.ignore_max_compaction_bytes_for_input = false;
|
||||
ioptions_.level_compaction_dynamic_level_bytes = false;
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
// A compaction should be triggered and pick file 2 and 5.
|
||||
// and it expands to file 1 and 3 too.
|
||||
Add(1, 1U, "100", "150", 300000U);
|
||||
Add(1, 2U, "151", "200", 300001U, 0, 0);
|
||||
Add(1, 3U, "201", "250", 300000U, 0, 0);
|
||||
Add(1, 4U, "251", "300", 300000U, 0, 0);
|
||||
Add(2, 5U, "000", "251", 1U);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(2U, compaction->num_input_levels());
|
||||
ASSERT_EQ(3U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(1U, compaction->num_input_files(1));
|
||||
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
||||
ASSERT_EQ(3U, compaction->input(0, 2)->fd.GetNumber());
|
||||
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, IsTrivialMoveOn) {
|
||||
mutable_cf_options_.max_bytes_for_level_base = 10000u;
|
||||
mutable_cf_options_.max_compaction_bytes = 10001u;
|
||||
@@ -4161,290 +4149,9 @@ TEST_P(PerKeyPlacementCompactionPickerTest,
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest,
|
||||
LevelCompactionPrioritizeFilesMarkedForCompaction1) {
|
||||
int num_levels = ioptions_.num_levels;
|
||||
ioptions_.level_compaction_dynamic_level_bytes = true;
|
||||
ioptions_.compaction_pri = kMinOverlappingRatio;
|
||||
mutable_cf_options_.max_bytes_for_level_base = 200;
|
||||
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
||||
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
||||
// L5
|
||||
// F4 [100, 200] size:100, F5 [300, 400] size:100, F6 [500, 600] size:200
|
||||
// F5 is marked for compaction
|
||||
// L6
|
||||
// F1 [100, 200] size:100, F2 [300, 400] size:1000, F3 [500, 600] size:100
|
||||
//
|
||||
// First compaction should pick F5 since it's marked for compaction.
|
||||
// Second compaction should pick F6 since it has min overlap ratio.
|
||||
Add(/*level=*/num_levels - 1, /*file_number=*/1U, /*smallest=*/"100",
|
||||
/*largest=*/"200",
|
||||
/*file_size=*/100, /*path_id=*/0, /*smallest_seq=*/0,
|
||||
/*largest_seq=*/0, /*compensated_file_size=*/100,
|
||||
/*marked_for_compact=*/false);
|
||||
Add(/*level=*/num_levels - 1, /*file_number=*/2U, /*smallest=*/"300",
|
||||
/*largest=*/"400",
|
||||
/*file_size=*/1000, /*path_id=*/0, /*smallest_seq=*/0,
|
||||
/*largest_seq=*/0, /*compensated_file_size=*/1000,
|
||||
/*marked_for_compact=*/false);
|
||||
Add(/*level=*/num_levels - 1, /*file_number=*/3U, /*smallest=*/"500",
|
||||
/*largest=*/"600",
|
||||
/*file_size=*/100, /*path_id=*/0, /*smallest_seq=*/0,
|
||||
/*largest_seq=*/0, /*compensated_file_size=*/100,
|
||||
/*marked_for_compact=*/false);
|
||||
|
||||
Add(/*level=*/num_levels - 2, /*file_number=*/4U, /*smallest=*/"100",
|
||||
/*largest=*/"200",
|
||||
/*file_size=*/100, /*path_id=*/0, /*smallest_seq=*/100,
|
||||
/*largest_seq=*/200, /*compensated_file_size=*/100,
|
||||
/*marked_for_compact=*/false);
|
||||
// Marked for compaction, but with a larger overlap ratio.
|
||||
Add(/*level=*/num_levels - 2, /*file_number=*/5U, /*smallest=*/"300",
|
||||
/*largest=*/"400",
|
||||
/*file_size=*/100, /*path_id=*/0, /*smallest_seq=*/300,
|
||||
/*largest_seq=*/400, /*compensated_file_size=*/100,
|
||||
/*marked_for_compact=*/true);
|
||||
Add(/*level=*/num_levels - 2, /*file_number=*/6U, /*smallest=*/"500",
|
||||
/*largest=*/"600",
|
||||
/*file_size=*/200, /*path_id=*/0, /*smallest_seq=*/400,
|
||||
/*largest_seq=*/500, /*compensated_file_size=*/200,
|
||||
/*marked_for_compact=*/false);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction);
|
||||
ASSERT_EQ(num_levels - 2, compaction->start_level());
|
||||
ASSERT_EQ(num_levels - 1, compaction->output_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(5U, compaction->input(0, 0)->fd.GetNumber());
|
||||
|
||||
std::unique_ptr<Compaction> second_compaction(
|
||||
level_compaction_picker.PickCompaction(cf_name_, mutable_cf_options_,
|
||||
mutable_db_options_,
|
||||
vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(second_compaction);
|
||||
ASSERT_EQ(num_levels - 1, compaction->output_level());
|
||||
ASSERT_EQ(num_levels - 2, compaction->start_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(6U, second_compaction->input(0, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest,
|
||||
LevelCompactionPrioritizeFilesMarkedForCompaction2) {
|
||||
int num_levels = ioptions_.num_levels;
|
||||
ioptions_.level_compaction_dynamic_level_bytes = true;
|
||||
ioptions_.compaction_pri = kMinOverlappingRatio;
|
||||
mutable_cf_options_.max_bytes_for_level_base = 200;
|
||||
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
||||
// L4
|
||||
// F3 [100, 200] size:2000
|
||||
// L5
|
||||
// F2 [100, 200] size:2000, marked for compaction
|
||||
// L6
|
||||
// F1 [100, 200] size: 20000
|
||||
//
|
||||
// L4 should be prioritized over L5 since L4 has a higher compaction score.
|
||||
// Files marked for compaction do not affect level picking order.
|
||||
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
||||
Add(/*level=*/num_levels - 1, /*file_number=*/1U, /*smallest=*/"100",
|
||||
/*largest=*/"200",
|
||||
/*file_size=*/20000, /*path_id=*/0, /*smallest_seq=*/0,
|
||||
/*largest_seq=*/0, /*compensated_file_size=*/100,
|
||||
/*marked_for_compact=*/false);
|
||||
// Level score should be 1.
|
||||
Add(/*level=*/num_levels - 2, /*file_number=*/2U, /*smallest=*/"100",
|
||||
/*largest=*/"200",
|
||||
/*file_size=*/2000, /*path_id=*/0, /*smallest_seq=*/100,
|
||||
/*largest_seq=*/200, /*compensated_file_size=*/2000,
|
||||
/*marked_for_compact=*/true);
|
||||
// Level score should be larger than L5.
|
||||
Add(/*level=*/num_levels - 3, /*file_number=*/3U, /*smallest=*/"100",
|
||||
/*largest=*/"200",
|
||||
/*file_size=*/2000, /*path_id=*/0, /*smallest_seq=*/300,
|
||||
/*largest_seq=*/400, /*compensated_file_size=*/2000,
|
||||
/*marked_for_compact=*/false);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction);
|
||||
ASSERT_EQ(num_levels - 3, compaction->start_level());
|
||||
ASSERT_EQ(num_levels - 2, compaction->output_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PerKeyPlacementCompactionPickerTest,
|
||||
PerKeyPlacementCompactionPickerTest, ::testing::Bool());
|
||||
|
||||
TEST_F(CompactionPickerTest, IntraL0WhenL0IsSmall) {
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 4;
|
||||
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
||||
for (const uint64_t lbase_size_multiplier : {1, 10, 11, 40}) {
|
||||
SCOPED_TRACE("lbase_size_multiplier=" +
|
||||
std::to_string(lbase_size_multiplier));
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
// When L0 size is <= Lbase size / max_bytes_for_level_multiplier / 2,
|
||||
// intra-L0 compaction is picked. Otherwise, L0->L1
|
||||
// compaction is picked.
|
||||
// compensated_file_size will be used to compute total l0 size.
|
||||
Add(/*level=*/0, /*file_number=*/1U, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/10, /*path_id=*/0,
|
||||
/*smallest_seq=*/10, /*largest_seq=*/11,
|
||||
/*compensated_file_size=*/1000);
|
||||
Add(/*level=*/0, /*file_number=*/2U, /*smallest=*/"100",
|
||||
/*largest=*/"100", /*file_size=*/10, /*path_id=*/0,
|
||||
/*smallest_seq=*/20, /*largest_seq=*/21,
|
||||
/*compensated_file_size=*/1000);
|
||||
Add(/*level=*/0, /*file_number=*/3U, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/10, /*path_id=*/0,
|
||||
/*smallest_seq=*/30, /*largest_seq=*/31,
|
||||
/*compensated_file_size=*/1000);
|
||||
Add(/*level=*/0, /*file_number=*/4U, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/10, /*path_id=*/0,
|
||||
/*smallest_seq=*/40, /*largest_seq=*/41,
|
||||
/*compensated_file_size=*/1000);
|
||||
const uint64_t l0_size = 4000;
|
||||
const uint64_t lbase_size = l0_size * lbase_size_multiplier * 2;
|
||||
Add(/*level=*/1, /*file_number=*/5U, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/lbase_size, /*path_id=*/0,
|
||||
/*smallest_seq=*/0, /*largest_seq=*/0,
|
||||
/*compensated_file_size=*/lbase_size);
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
LevelCompactionPicker compaction_picker(ioptions_, &icmp_);
|
||||
std::unique_ptr<Compaction> compaction(compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(CompactionReason::kLevelL0FilesNum,
|
||||
compaction->compaction_reason());
|
||||
ASSERT_EQ(4U, compaction->num_input_files(0));
|
||||
if (lbase_size_multiplier >
|
||||
mutable_cf_options_.max_bytes_for_level_multiplier) {
|
||||
ASSERT_EQ(1U, compaction->num_input_levels());
|
||||
ASSERT_EQ(0, compaction->output_level());
|
||||
} else {
|
||||
ASSERT_EQ(2U, compaction->num_input_levels());
|
||||
ASSERT_EQ(1, compaction->output_level());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalMaxReadAmpLargeDB) {
|
||||
ioptions_.compaction_style = kCompactionStyleUniversal;
|
||||
ioptions_.num_levels = 50;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
mutable_cf_options_.compaction_options_universal.size_ratio = 10;
|
||||
mutable_cf_options_.write_buffer_size = 256 << 20;
|
||||
// Avoid space amp compaction
|
||||
mutable_cf_options_.compaction_options_universal
|
||||
.max_size_amplification_percent = 200;
|
||||
const int kMaxRuns = 8;
|
||||
for (int max_read_amp : {kMaxRuns, 0, -1}) {
|
||||
SCOPED_TRACE("max_read_amp = " + std::to_string(max_read_amp));
|
||||
if (max_read_amp == -1) {
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = kMaxRuns;
|
||||
} else {
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 4;
|
||||
}
|
||||
mutable_cf_options_.compaction_options_universal.max_read_amp =
|
||||
max_read_amp;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
uint64_t max_run_size = 20ull << 30;
|
||||
// When max_read_amp = 0, we estimate the number of levels needed based on
|
||||
// size_ratio and write_buffer_size. See more in
|
||||
// UniversalCompactionBuilder::PickCompaction().
|
||||
// With a 20GB last level, we estimate that 8 levels are needed:
|
||||
// L0 256MB
|
||||
// L1 256MB * 1.1 (size_ratio) = 282MB
|
||||
// L2 (256MB + 282MB) * 1.1 = 592MB
|
||||
// L3 1243MB
|
||||
// L4 2610MB
|
||||
// L5 5481MB
|
||||
// L6 11510MB
|
||||
// L7 24171MB > 20GB
|
||||
for (int i = 0; i <= kMaxRuns; ++i) {
|
||||
SCOPED_TRACE("i = " + std::to_string(i));
|
||||
NewVersionStorage(/*num_levels=*/50, kCompactionStyleUniversal);
|
||||
Add(/*level=*/49, /*file_number=*/10, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/max_run_size, /*path_id=*/0,
|
||||
/*smallest_seq=*/0, /*largest_seq=*/0,
|
||||
/*compensated_file_size=*/max_run_size);
|
||||
// Besides the last sorted run, we add additional `i` sorted runs
|
||||
// without triggering space-amp or size-amp compactions.
|
||||
uint64_t file_size = 1 << 20;
|
||||
for (int j = 0; j < i; ++j) {
|
||||
Add(/*level=*/j, /*file_number=*/100 - j, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/file_size, /*path_id=*/0,
|
||||
/*smallest_seq=*/100 - j, /*largest_seq=*/100 - j,
|
||||
/*compensated_file_size=*/file_size);
|
||||
// to avoid space-amp and size-amp compaction
|
||||
file_size *= 2;
|
||||
}
|
||||
UpdateVersionStorageInfo();
|
||||
// level0_file_num_compaction_trigger is still used as trigger to
|
||||
// check potential compactions
|
||||
ASSERT_EQ(
|
||||
universal_compaction_picker.NeedsCompaction(vstorage_.get()),
|
||||
i + 1 >= mutable_cf_options_.level0_file_num_compaction_trigger);
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_,
|
||||
vstorage_.get(), &log_buffer_));
|
||||
if (i == kMaxRuns) {
|
||||
// There are in total i + 1 > kMaxRuns sorted runs.
|
||||
// This triggers compaction ignoring size_ratio.
|
||||
ASSERT_NE(nullptr, compaction);
|
||||
ASSERT_EQ(CompactionReason::kUniversalSortedRunNum,
|
||||
compaction->compaction_reason());
|
||||
// First two runs are compacted
|
||||
ASSERT_EQ(0, compaction->start_level());
|
||||
ASSERT_EQ(1, compaction->output_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(1U, compaction->num_input_files(1));
|
||||
} else {
|
||||
ASSERT_EQ(nullptr, compaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalMaxReadAmpSmallDB) {
|
||||
ioptions_.compaction_style = kCompactionStyleUniversal;
|
||||
ioptions_.num_levels = 50;
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 1;
|
||||
mutable_cf_options_.compaction_options_universal.size_ratio = 10;
|
||||
mutable_cf_options_.write_buffer_size = 256 << 20;
|
||||
mutable_cf_options_.compaction_options_universal
|
||||
.max_size_amplification_percent = 200;
|
||||
const int kMaxRuns = 1;
|
||||
for (int max_read_amp : {-1, kMaxRuns, 0}) {
|
||||
SCOPED_TRACE("max_read_amp = " + std::to_string(max_read_amp));
|
||||
mutable_cf_options_.compaction_options_universal.max_read_amp =
|
||||
max_read_amp;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
NewVersionStorage(/*num_levels=*/50, kCompactionStyleUniversal);
|
||||
// max_run_size is much smaller than write_buffer_size,
|
||||
// only 1 level is needed.
|
||||
uint64_t max_run_size = 8 << 10;
|
||||
Add(/*level=*/49, /*file_number=*/10, /*smallest=*/"100",
|
||||
/*largest=*/"200", /*file_size=*/max_run_size, /*path_id=*/0,
|
||||
/*smallest_seq=*/0, /*largest_seq=*/0,
|
||||
/*compensated_file_size=*/max_run_size);
|
||||
UpdateVersionStorageInfo();
|
||||
ASSERT_TRUE(universal_compaction_picker.NeedsCompaction(vstorage_.get()));
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
&log_buffer_));
|
||||
ASSERT_EQ(nullptr, compaction);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
||||
@@ -227,7 +227,6 @@ class UniversalCompactionBuilder {
|
||||
const InternalKeyComparator* icmp_;
|
||||
double score_;
|
||||
std::vector<SortedRun> sorted_runs_;
|
||||
uint64_t max_run_size_;
|
||||
const std::string& cf_name_;
|
||||
const MutableCFOptions& mutable_cf_options_;
|
||||
const MutableDBOptions& mutable_db_options_;
|
||||
@@ -236,8 +235,7 @@ class UniversalCompactionBuilder {
|
||||
LogBuffer* log_buffer_;
|
||||
|
||||
static std::vector<UniversalCompactionBuilder::SortedRun> CalculateSortedRuns(
|
||||
const VersionStorageInfo& vstorage, int last_level,
|
||||
uint64_t* max_run_size);
|
||||
const VersionStorageInfo& vstorage, int last_level);
|
||||
|
||||
// Pick a path ID to place a newly generated file, with its estimated file
|
||||
// size.
|
||||
@@ -442,15 +440,11 @@ void UniversalCompactionBuilder::SortedRun::DumpSizeInfo(
|
||||
|
||||
std::vector<UniversalCompactionBuilder::SortedRun>
|
||||
UniversalCompactionBuilder::CalculateSortedRuns(
|
||||
const VersionStorageInfo& vstorage, int last_level,
|
||||
uint64_t* max_run_size) {
|
||||
assert(max_run_size);
|
||||
*max_run_size = 0;
|
||||
const VersionStorageInfo& vstorage, int last_level) {
|
||||
std::vector<UniversalCompactionBuilder::SortedRun> ret;
|
||||
for (FileMetaData* f : vstorage.LevelFiles(0)) {
|
||||
ret.emplace_back(0, f, f->fd.GetFileSize(), f->compensated_file_size,
|
||||
f->being_compacted);
|
||||
*max_run_size = std::max(*max_run_size, f->fd.GetFileSize());
|
||||
}
|
||||
for (int level = 1; level <= last_level; level++) {
|
||||
uint64_t total_compensated_size = 0U;
|
||||
@@ -472,7 +466,6 @@ UniversalCompactionBuilder::CalculateSortedRuns(
|
||||
ret.emplace_back(level, nullptr, total_size, total_compensated_size,
|
||||
being_compacted);
|
||||
}
|
||||
*max_run_size = std::max(*max_run_size, total_size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -484,16 +477,13 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
score_ = vstorage_->CompactionScore(kLevel0);
|
||||
int max_output_level =
|
||||
vstorage_->MaxOutputLevel(ioptions_.allow_ingest_behind);
|
||||
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;
|
||||
sorted_runs_ = CalculateSortedRuns(*vstorage_, max_output_level);
|
||||
|
||||
if (sorted_runs_.size() == 0 ||
|
||||
(vstorage_->FilesMarkedForPeriodicCompaction().empty() &&
|
||||
vstorage_->FilesMarkedForCompaction().empty() &&
|
||||
sorted_runs_.size() < (unsigned int)file_num_compaction_trigger)) {
|
||||
sorted_runs_.size() < (unsigned int)mutable_cf_options_
|
||||
.level0_file_num_compaction_trigger)) {
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: nothing to do\n",
|
||||
cf_name_.c_str());
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
@@ -515,9 +505,11 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
TEST_SYNC_POINT_CALLBACK("PostPickPeriodicCompaction", c);
|
||||
}
|
||||
|
||||
// Check for size amplification.
|
||||
if (c == nullptr &&
|
||||
sorted_runs_.size() >= static_cast<size_t>(file_num_compaction_trigger)) {
|
||||
// Check for size amplification.
|
||||
sorted_runs_.size() >=
|
||||
static_cast<size_t>(
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger)) {
|
||||
if ((c = PickCompactionToReduceSizeAmp()) != nullptr) {
|
||||
TEST_SYNC_POINT("PickCompactionToReduceSizeAmpReturnNonnullptr");
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: compacting for size amp\n",
|
||||
@@ -535,48 +527,13 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
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.
|
||||
|
||||
// If max read amplification is exceeding configured limits, then force
|
||||
// compaction without looking at filesize ratios and try to reduce
|
||||
// the number of files to fewer than level0_file_num_compaction_trigger.
|
||||
// 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
|
||||
}
|
||||
static_cast<size_t>(
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger));
|
||||
// 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++) {
|
||||
@@ -587,25 +544,17 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
|
||||
// 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 (num_sr_not_compacted >
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger) {
|
||||
unsigned int num_files =
|
||||
num_sr_not_compacted -
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger + 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_);
|
||||
"[%s] Universal: compacting for file num -- %u\n",
|
||||
cf_name_.c_str(), num_files);
|
||||
}
|
||||
} 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_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -921,7 +870,7 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSortedRuns(
|
||||
output_level, 1, enable_compression),
|
||||
GetCompressionOptions(mutable_cf_options_, vstorage_,
|
||||
output_level, enable_compression),
|
||||
mutable_cf_options_.default_write_temperature,
|
||||
Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, grandparents,
|
||||
/* is manual */ false, /* trim_ts */ "", score_,
|
||||
false /* deletion_compaction */,
|
||||
@@ -1256,7 +1205,7 @@ Compaction* UniversalCompactionBuilder::PickIncrementalForReduceSizeAmp(
|
||||
true /* enable_compression */),
|
||||
GetCompressionOptions(mutable_cf_options_, vstorage_, output_level,
|
||||
true /* enable_compression */),
|
||||
mutable_cf_options_.default_write_temperature,
|
||||
Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
/* trim_ts */ "", score_, false /* deletion_compaction */,
|
||||
/* l0_files_might_overlap */ true,
|
||||
@@ -1400,7 +1349,7 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() {
|
||||
/* max_grandparent_overlap_bytes */ GetMaxOverlappingBytes(), path_id,
|
||||
GetCompressionType(vstorage_, mutable_cf_options_, output_level, 1),
|
||||
GetCompressionOptions(mutable_cf_options_, vstorage_, output_level),
|
||||
mutable_cf_options_.default_write_temperature,
|
||||
Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, grandparents, /* is manual */ false,
|
||||
/* trim_ts */ "", score_, false /* deletion_compaction */,
|
||||
/* l0_files_might_overlap */ true,
|
||||
@@ -1493,7 +1442,7 @@ Compaction* UniversalCompactionBuilder::PickCompactionWithSortedRunRange(
|
||||
true /* enable_compression */),
|
||||
GetCompressionOptions(mutable_cf_options_, vstorage_, output_level,
|
||||
true /* enable_compression */),
|
||||
mutable_cf_options_.default_write_temperature,
|
||||
Temperature::kUnknown,
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
/* trim_ts */ "", score_, false /* deletion_compaction */,
|
||||
/* l0_files_might_overlap */ true, compaction_reason);
|
||||
|
||||
Loaded 100 of 892 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user