Compare commits

..
7 Commits
Author SHA1 Message Date
Hui Xiao fae8a27fbd Update HISTORY and version 2025-09-15 14:24:48 -07:00
Hui Xiao e12650878e Fix a race condition in FIFO size-based compaction where concurrent threads could select the same non-L0 file (#13946)
Summary:
**Context/Summary:**
Fix a race condition (illustrated below) in FIFO size-based compaction where concurrent threads could select the same non-L0 file, causing assertion failures in debug builds or "Cannot delete table file from LSM tree" errors in release builds.
```
Thread 1                           Thread 2
--------                           --------
FIFO size-based compaction
   ↓
Pick L2 file
   ↓
Mark: file.being_compacted = true (file.being_compacted was false)
   ↓
WriteManifestStart (unlock mutex) ─→ FIFO size-based compaction starts
   ↓                                   ↓
Continue manifest write...          Pick SAME L2 file
   ↓                                Mark: file.being_compacted = true  (file.being_compacted was true) ❌
   ↓                                   ↓
   ↓                                Unlock mutex, wait for manifest
   ↓                                   ↓
Lock mutex ←─────────────────────────────────┘
   ↓
Delete L2 file ✅
   ↓
Complete ─────────────────────────────→ Try delete same file ❌
                                        ↓
                                     ERROR: "file not in LSM tree"

🐛 BUG: Both threads pick the same file!
    Thread 2 doesn't properly check file.being_compacted flag
```

**Test**
New test that fails before the fix and passes after

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

Reviewed By: xingbowang

Differential Revision: D82279731

Pulled By: hx235

fbshipit-source-id: b426517f2d1b23dd7d4951157822a2d322fe1435
2025-09-15 14:07:59 -07:00
anand76 46c255cc87 Update HISTORY.md and version for 10.6.1 2025-09-06 18:09:37 -07:00
anand76 1b2aa8958b Make failure to load UDI when opening an SST a soft failure (#13921)
Summary:
If user_defined_index_factory in BlockBasedTableOptions is configured and we try to open an SST file without the corresponding UDI (either during DB open or file ingestion), ignore a failure to load the UDI by default. If fail_if_no_udi_on_open in BlockBasedTableOptions is true, then treat it as a fatal error.

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

Test Plan: Update unit tests

Reviewed By: xingbowang

Differential Revision: D81826054

Pulled By: anand1976

fbshipit-source-id: f4fe0b13ccb02b9448622af487680131e349c52b
2025-09-06 18:08:38 -07:00
Changyu Bi fa143aa4db Add option to limit max prefetching in MultiScan (#13920)
Summary:
Add a new option `MultiScanArgs::max_prefetch_size` that limits the memory usage of per file pinning of prefetched blocks. Note that this only accounts for compressed block size. This is intended to be a stopgap until we implement some kind of global prefetch manager that limits the global multiscan memory usage.

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

Test Plan: new unit test `./block_based_table_reader_test --gtest_filter="*MultiScanPrefetchSizeLimit/*"`

Reviewed By: xingbowang

Differential Revision: D81630629

Pulled By: cbi42

fbshipit-source-id: 9f66678915242fe1220620531a4b9fd22747cdea
2025-09-06 18:08:25 -07:00
anand76 6ea50e6054 Revert "Create a new API FileSystem::SyncFile for file sync (#13762)"
This reverts commit 961880b458.
2025-08-29 15:37:27 -07:00
anand76 17f7a626a8 Update HISTORY for 10.6.0 2025-08-24 19:45:47 -07:00
165 changed files with 3388 additions and 12835 deletions

No files matched your search

+1 -3
View File
@@ -3,7 +3,5 @@ runs:
using: composite
steps:
- name: Checkout folly sources
run: |
make checkout_folly
echo "GETDEPS_USE_WGET=1" >> "$GITHUB_ENV"
run: make checkout_folly
shell: bash
+27 -12
View File
@@ -10,7 +10,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -32,7 +32,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
env:
TEST_TMPDIR: "/tmp/rocksdb_test_tmp"
@@ -41,16 +41,16 @@ jobs:
- uses: "./.github/actions/pre-steps"
- run: make V=1 -j32 check
- uses: "./.github/actions/post-steps"
build-linux-clang-18-asan-ubsan-with-folly:
build-linux-clang-13-asan-ubsan-with-folly:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
env:
CC: clang-18
CXX: clang++-18
CC: clang-13
CXX: clang++-13
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
@@ -63,7 +63,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -94,7 +94,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -107,26 +107,41 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
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-18 CXX=clang++-18 USE_CLANG=1 make -j4 static_lib
run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j4 static_lib
- name: Build fuzzers
run: cd fuzz && make sst_file_writer_fuzzer db_fuzzer db_map_fuzzer
- uses: "./.github/actions/post-steps"
build-linux-gcc-11-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: LIB_MODE=static CC=gcc-11 CXX=g++-11 V=1 make -j32 all microbench
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-folly-lite-no-test:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
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 -DCMAKE_CXX_FLAGS=-DGLOG_USE_GLOG_EXPORT .. && make V=1 -j20)"
- run: "(mkdir build && cd build && cmake -DUSE_FOLLY_LITE=1 -DWITH_GFLAGS=1 .. && make V=1 -j20)"
- uses: "./.github/actions/post-steps"
+62 -49
View File
@@ -66,7 +66,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -78,7 +78,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -97,8 +97,11 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
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"
@@ -111,8 +114,11 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
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"
@@ -125,21 +131,27 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
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 EXTRA_CXXFLAGS=-DGLOG_USE_GLOG_EXPORT V=1 make -j32 all
- 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: ghcr.io/facebook/rocksdb_ubuntu:22.1
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"
@@ -152,7 +164,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -164,7 +176,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -178,7 +190,7 @@ jobs:
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -199,61 +211,68 @@ jobs:
- run: ls librocksdb.a
- run: if ./trace_analyzer --version; then false; else true; fi
- uses: "./.github/actions/post-steps"
build-linux-clang-13-no_test_run:
build-linux-clang-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 8-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
# FIXME: get back to "all microbench" targets
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 EXTRA_CXXFLAGS=-stdlib=libc++ EXTRA_LDFLAGS=-stdlib=libc++ make -j32 shared_lib
- run: make clean
# FIXME: get back to "release" target
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 EXTRA_CXXFLAGS=-stdlib=libc++ EXTRA_LDFLAGS=-stdlib=libc++ DEBUG_LEVEL=0 make -j32 shared_lib
- run: CC=clang CXX=clang++ USE_CLANG=1 PORTABLE=1 make V=1 -j16 all
- uses: "./.github/actions/post-steps"
build-linux-clang-18-no_test_run:
build-linux-clang-13-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: CC=clang-18 CXX=clang++-18 USE_CLANG=1 make -j32 all microbench
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j32 all microbench
- run: make clean
- run: CC=clang-18 CXX=clang++-18 USE_CLANG=1 DEBUG_LEVEL=0 make -j32 release
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 DEBUG_LEVEL=0 make -j32 release
- uses: "./.github/actions/post-steps"
build-linux-gcc-14-no_test_run:
build-linux-gcc-8-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: CC=gcc-14 CXX=g++-14 V=1 make -j32 all microbench
- 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"
# ======================== Linux Other Checks ======================= #
build-linux-clang18-clang-analyze:
build-linux-clang10-clang-analyze:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: CC=clang-18 CXX=clang++-18 ROCKSDB_DISABLE_ALIGNED_NEW=1 CLANG_ANALYZER="/usr/bin/clang++-18" CLANG_SCAN_BUILD=scan-build-18 USE_CLANG=1 make V=1 -j32 analyze
- 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
@@ -281,7 +300,7 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: zjay437/rocksdb:0.6
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
@@ -289,41 +308,41 @@ jobs:
- 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-clang18-asan-ubsan:
build-linux-clang10-asan-ubsan:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
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 COMPILE_WITH_UBSAN=1 CC=clang-18 CXX=clang++-18 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j40 check
- run: COMPILE_WITH_ASAN=1 COMPILE_WITH_UBSAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j40 check
- uses: "./.github/actions/post-steps"
build-linux-clang18-mini-tsan:
build-linux-clang13-mini-tsan:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
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-18 CXX=clang++-18 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
- 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: ghcr.io/facebook/rocksdb_ubuntu:22.1
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_USE_STD_SEMAPHORES -DROCKSDB_NAMESPACE=alternative_rocksdb_ns" make V=1 -j24 check
- 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:
@@ -385,13 +404,11 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: evolvedbinary/rocksjava:centos7_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.
# NOTE: replaced evolvedbinary/rocksjava:centos7_x64-be with ghcr.io/facebook/rocksdb_ubuntu:22.1
# until a more appropriate docker image with C++20 support is made.
- name: Checkout
env:
GH_TOKEN: ${{ github.token }}
@@ -408,21 +425,18 @@ jobs:
which java && java -version
which javac && javac -version
- name: Test RocksDBJava
# NOTE: replaced scl enable devtoolset-7 'make V=1 J=8 -j8 jtest'
run: make V=1 J=8 -j8 jtest
# post-steps skipped because of compatibility issues with docker image
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: ghcr.io/facebook/rocksdb_ubuntu:22.1
image: evolvedbinary/rocksjava:centos7_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.
# NOTE: replaced evolvedbinary/rocksjava:centos7_x64-be with ghcr.io/facebook/rocksdb_ubuntu:22.1
# until a more appropriate docker image with C++20 support is made.
- name: Checkout
env:
GH_TOKEN: ${{ github.token }}
@@ -439,9 +453,8 @@ jobs:
which java && java -version
which javac && javac -version
- name: Build RocksDBJava Static Library
# NOTE: replaced scl enable devtoolset-7 'make V=1 J=8 -j8 rocksdbjavastatic'
run: make V=1 J=8 -j8 rocksdbjavastatic
# post-steps skipped because of compatibility issues with docker image
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
+1 -10
View File
@@ -419,8 +419,6 @@ cpp_library_wrapper(name="rocksdb_tools_lib", srcs=[
cpp_library_wrapper(name="rocksdb_cache_bench_tools_lib", srcs=["cache/cache_bench_tool.cc"], deps=[":rocksdb_lib"], headers=[], link_whole=False, extra_test_libs=False)
cpp_library_wrapper(name="rocksdb_point_lock_bench_tools_lib", srcs=["utilities/transactions/lock/point/point_lock_bench_tool.cc"], deps=[":rocksdb_lib"], headers=[], link_whole=False, extra_test_libs=False)
rocks_cpp_library_wrapper(name="rocksdb_stress_lib", srcs=[
"db_stress_tool/batched_ops_stress.cc",
"db_stress_tool/cf_consistency_stress.cc",
@@ -431,6 +429,7 @@ rocks_cpp_library_wrapper(name="rocksdb_stress_lib", srcs=[
"db_stress_tool/db_stress_gflags.cc",
"db_stress_tool/db_stress_listener.cc",
"db_stress_tool/db_stress_shared_state.cc",
"db_stress_tool/db_stress_stat.cc",
"db_stress_tool/db_stress_test_base.cc",
"db_stress_tool/db_stress_tool.cc",
"db_stress_tool/db_stress_wide_merge_operator.cc",
@@ -452,8 +451,6 @@ cpp_binary_wrapper(name="db_bench", srcs=["tools/db_bench.cc"], deps=[":rocksdb_
cpp_binary_wrapper(name="cache_bench", srcs=["cache/cache_bench.cc"], deps=[":rocksdb_cache_bench_tools_lib"], extra_preprocessor_flags=[], extra_bench_libs=False)
cpp_binary_wrapper(name="point_lock_bench", srcs=["utilities/transactions/lock/point/point_lock_bench.cc"], deps=[":rocksdb_point_lock_bench_tools_lib"], extra_preprocessor_flags=[], extra_bench_libs=False)
cpp_binary_wrapper(name="ribbon_bench", srcs=["microbench/ribbon_bench.cc"], deps=[], extra_preprocessor_flags=[], extra_bench_libs=True)
cpp_binary_wrapper(name="db_basic_bench", srcs=["microbench/db_basic_bench.cc"], deps=[], extra_preprocessor_flags=[], extra_bench_libs=True)
@@ -5385,12 +5382,6 @@ cpp_unittest_wrapper(name="plain_table_db_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="point_lock_manager_stress_test",
srcs=["utilities/transactions/lock/point/point_lock_manager_stress_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="point_lock_manager_test",
srcs=["utilities/transactions/lock/point/point_lock_manager_test.cc"],
deps=[":rocksdb_test_lib"],
+3 -9
View File
@@ -27,7 +27,7 @@
#
# Linux:
#
# 1. Install a recent toolchain if you're on a older distro. C++20 required (GCC >= 11, Clang >= 10)
# 1. Install a recent toolchain if you're on a older distro. C++17 required (GCC >= 7, Clang >= 5)
# 2. mkdir build; cd build
# 3. cmake ..
# 4. make -j
@@ -100,7 +100,7 @@ endif()
option(ROCKSDB_BUILD_SHARED "Build shared versions of the RocksDB libraries" ON)
if( NOT DEFINED CMAKE_CXX_STANDARD )
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 17)
endif()
include(CMakeDependentOption)
@@ -314,6 +314,7 @@ endif()
# Check if -latomic is required or not
if (NOT MSVC)
set(CMAKE_REQUIRED_FLAGS "--std=c++17")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
std::atomic<uint64_t> x(0);
@@ -1503,7 +1504,6 @@ if(WITH_TESTS)
utilities/transactions/optimistic_transaction_test.cc
utilities/transactions/transaction_test.cc
utilities/transactions/lock/point/point_lock_manager_test.cc
utilities/transactions/lock/point/point_lock_manager_stress_test.cc
utilities/transactions/write_committed_transaction_ts_test.cc
utilities/transactions/write_prepared_transaction_test.cc
utilities/transactions/write_unprepared_transaction_test.cc
@@ -1614,12 +1614,6 @@ if(WITH_BENCHMARK_TOOLS)
utilities/persistent_cache/hash_table_bench.cc)
target_link_libraries(hash_table_bench${ARTIFACT_SUFFIX}
${ROCKSDB_LIB} ${GFLAGS_LIB} ${FOLLY_LIBS})
add_executable(point_lock_bench${ARTIFACT_SUFFIX}
utilities/transactions/lock/point/point_lock_bench.cc
utilities/transactions/lock/point/point_lock_bench_tool.cc)
target_link_libraries(point_lock_bench${ARTIFACT_SUFFIX}
${ROCKSDB_LIB} ${GFLAGS_LIB} ${FOLLY_LIBS})
endif()
option(WITH_TRACE_TOOLS "build with trace tools" ON)
+3 -45
View File
@@ -1,56 +1,14 @@
# Rocksdb Change Log
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
## 10.7.6 (10/23/2025)
* Fix a bug when del range and data are in same file for multi-scan
## 10.7.5 (10/20/2025)
## 10.6.2 (09/15/2025)
### Bug Fixes
* Fix a bug in Page unpinning in MultiScan
* Fix a race condition in FIFO size-based compaction where concurrent threads could select the same non-L0 file, causing assertion failures in debug builds or "Cannot delete table file from LSM tree" errors in release builds.
## 10.7.4 (10/14/2025)
### Public API Changes
* The MultiScan API contract is updated. After a multi scan range got prepared with Prepare API call, the following seeks must seek the start of each prepared scan range in order. In addition, when limit is set, upper bound must be set to the same value of limit before each seek
## 10.7.3 (10/06/2025)
### Bug Fixes
* Fix a few bugs in MultiScan
## 10.7.2 (09/30/2025)
### Bug Fixes
* Fix incorrect MultiScan seek error status due to bugs in handling range limit falling between adjacent SST files key range.
### Performance Improvements
* Fixed a performance regression in LZ4 compression that started in version 10.6.0
## 10.7.0 (09/24/2025)
## 10.6.1 (09/05/2025)
### New Features
* Add the fail_if_no_udi_on_open flag in BlockBasedTableOption to control whether a missing user defined index block in a SST is a hard error or not.
* A new flag memtable_veirfy_per_key_checksum_on_seek is added to AdvancedColumnFamilyOptions. When it is enabled, it will validate key checksum along the binary search path on skiplist based memtable during seek operation.
* Introduce option MultiScanArgs::use_async_io to enable asynchronous I/O during MultiScan, instead of waiting for I/O to be done in Prepare().
* Add new option `MultiScanArgs::max_prefetch_size` that limits the memory usage of per file pinning of prefetched blocks.
* Improved `sst_dump` by allowing standalone file and directory arguments without `--file=`. Also added new options and better output for `sst_dump --command=recompress`. See `sst_dump --help`
### Public API Changes
* HyperClockCache with no `estimated_entry_charge` is now production-ready and is the preferred block cache implementation vs. LRUCache. Please consider updating your code to minimize the risk of hitting performance bottlenecks or anomalies from LRUCache. See cache.h for more detail.
* RocksDB now requires a C++20 compatible compiler (GCC >= 11, Clang >= 10, Visual Studio >= 2019), including for any code using RocksDB headers.
* MultiScanArgs used to have a default constructor with default parameter of BytewiseComparator. Now it always requires Comparator in its constructor.
### Behavior Changes
* The default provided block cache implementation is now HyperClockCache instead of LRUCache, when `block_cache` is nullptr (default) and `no_block_cache==false` (default). We recommend explicitly creating a HyperClockCache block cache based on memory budget and sharing it across all column families and even DB instances. This change could expose previously hidden memory or resource leaks.
* Allow UDIs with a non BytewiseComparator
### Bug Fixes
* Reported numbers for compaction and flush CPU usage now include time spent by parallel compression worker threads. This now means compaction/flush CPU usage could exceed the wall clock time.
* Fix a race condition in FIFO size-based compaction where concurrent threads could select the same non-L0 file, causing assertion failures in debug builds or "Cannot delete table file from LSM tree" errors in release builds.
* Fix a bug in RocksDB MultiScan with UDI when one of the scan ranges is determined to be empty by the UDI, which causes incorrect results.
### Performance Improvements
* Add a new table property "rocksdb.key.smallest.seqno" which records the smallest sequence number of all keys in file. It makes ingesting DB generated files faster by
avoiding scanning the whole file to find the smallest sequence number.
* Add a new experimental PerKeyPointLockManager to improve efficiency under high lock contention. PointLockManager was not efficient when there is high write contention on same key, as it uses a single conditional variable per lock stripe. PerKeyPointLockManager uses per thread conditional variable supporting fifo order. Although this is an experimental feature. By default, it is disabled. A new boolean flag TransactionDBOptions::use_per_key_point_lock_mgr is added to optionally enable it. Search the flag in code for more info.
Together, a new configuration TransactionOptions::deadlock_timeout_us is added, which allows the transaction to wait for a short period before perform deadlock detection. When the workload has low lock contention, the deadlock_timeout_us can be configured to be slightly higher than average transaction execution time, so that transaction would likely be able to take the lock before deadlock detection is performed when it is waiting for a lock. This allows transaction to reduce CPU cost on performing deadlock detection, which could be expensive in CPU time. When the workload has high lock contention, the deadlock_timeout_us can be configured to 0, so that transaction would perform deadlock detection immediately. By default the value is 0 to keep the behavior same as before.
* Majorly improved CPU efficiency and scalability of parallel compression (`CompressionOptions::parallel_threads` > 1), though this efficiency improvement makes parallel compression currently incompatible with UserDefinedIndex and with old setting of `decouple_partitioned_filters=false`. Parallel compression is now considered a production-ready feature. Maximum performance is available with `-DROCKSDB_USE_STD_SEMAPHORES` at compile time, but this is not currently recommended because of reported bugs in implementations of `std::counting_semaphore`/`binary_semaphore`.
## 10.6.0 (08/22/2025)
### New Features
+5 -5
View File
@@ -6,7 +6,7 @@ than release mode.
RocksDB's library should be able to compile without any dependency installed,
although we recommend installing some compression libraries (see below).
We do depend on newer gcc/clang with C++20 support (GCC >= 11, Clang >= 10).
We do depend on newer gcc/clang with C++17 support (GCC >= 7, Clang >= 5).
There are few options when compiling RocksDB:
@@ -60,7 +60,7 @@ most processors made since roughly 2013.
## Supported platforms
* **Linux - Ubuntu**
* Upgrade your gcc to version at least 11 to get C++20 support.
* Upgrade your gcc to version at least 7 to get C++17 support.
* Install gflags. First, try: `sudo apt-get install libgflags-dev`
If this doesn't work and you're using Ubuntu, here's a nice tutorial:
(http://askubuntu.com/questions/312173/installing-gflags-12-04)
@@ -72,7 +72,7 @@ most processors made since roughly 2013.
* Install zstandard: `sudo apt-get install libzstd-dev`.
* **Linux - CentOS / RHEL**
* Upgrade your gcc to version at least 11 to get C++20 support
* Upgrade your gcc to version at least 7 to get C++17 support
* Install gflags:
git clone https://github.com/gflags/gflags.git
@@ -122,7 +122,7 @@ most processors made since roughly 2013.
make && sudo make install
* **OS X**:
* Install latest C++ compiler that supports C++20:
* Install latest C++ compiler that supports C++ 17:
* 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.
@@ -213,7 +213,7 @@ most processors made since roughly 2013.
export PATH=/opt/freeware/bin:$PATH
* **Solaris Sparc**
* Install GCC 11 and higher.
* Install GCC 7 and higher.
* Use these environment variables:
export CC=gcc
+8 -13
View File
@@ -148,8 +148,10 @@ ifeq ($(USE_COROUTINES), 1)
USE_FOLLY = 1
# glog/logging.h requires HAVE_CXX11_ATOMIC
OPT += -DUSE_COROUTINES -DHAVE_CXX11_ATOMIC
ROCKSDB_CXX_STANDARD = c++2a
USE_RTTI = 1
ifneq ($(USE_CLANG), 1)
ROCKSDB_CXX_STANDARD = c++20
PLATFORM_CXXFLAGS += -fcoroutines
endif
endif
@@ -636,14 +638,13 @@ endif
TEST_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(TEST_LIB_SOURCES) $(MOCK_LIB_SOURCES)) $(GTEST)
BENCH_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(BENCH_LIB_SOURCES))
CACHE_BENCH_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(CACHE_BENCH_LIB_SOURCES))
POINT_LOCK_BENCH_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(POINT_LOCK_BENCH_LIB_SOURCES))
TOOL_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(TOOL_LIB_SOURCES))
ANALYZE_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(ANALYZER_LIB_SOURCES))
STRESS_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(STRESS_LIB_SOURCES))
# Exclude build_version.cc -- a generated source file -- from all sources. Not needed for dependencies
ALL_SOURCES = $(filter-out util/build_version.cc, $(LIB_SOURCES)) $(TEST_LIB_SOURCES) $(MOCK_LIB_SOURCES) $(GTEST_DIR)/gtest/gtest-all.cc
ALL_SOURCES += $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(CACHE_BENCH_LIB_SOURCES) $(POINT_LOCK_BENCH_LIB_SOURCES) $(ANALYZER_LIB_SOURCES) $(STRESS_LIB_SOURCES)
ALL_SOURCES += $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(CACHE_BENCH_LIB_SOURCES) $(ANALYZER_LIB_SOURCES) $(STRESS_LIB_SOURCES)
ALL_SOURCES += $(TEST_MAIN_SOURCES) $(TOOL_MAIN_SOURCES) $(BENCH_MAIN_SOURCES)
ALL_SOURCES += $(ROCKSDB_PLUGIN_SOURCES) $(ROCKSDB_PLUGIN_TESTS)
@@ -682,7 +683,7 @@ am__v_CCH_1 =
# 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) -std=$(or $(ROCKSDB_CXX_STANDARD),c++20) -I. -DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
$(CXX) -I. -DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
check-headers: $(HEADER_OK_FILES)
@@ -1344,9 +1345,6 @@ block_cache_trace_analyzer: $(OBJ_DIR)/tools/block_cache_analyzer/block_cache_tr
cache_bench: $(OBJ_DIR)/cache/cache_bench.o $(CACHE_BENCH_OBJECTS) $(LIBRARY)
$(AM_LINK)
point_lock_bench: $(OBJ_DIR)/utilities/transactions/lock/point/point_lock_bench.o $(POINT_LOCK_BENCH_OBJECTS) $(LIBRARY)
$(AM_LINK)
persistent_cache_bench: $(OBJ_DIR)/utilities/persistent_cache/persistent_cache_bench.o $(LIBRARY)
$(AM_LINK)
@@ -1427,13 +1425,13 @@ agg_merge_test: $(OBJ_DIR)/utilities/agg_merge/agg_merge_test.o $(TEST_LIBRARY)
stringappend_test: $(OBJ_DIR)/utilities/merge_operators/string_append/stringappend_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
cassandra_format_test: $(OBJ_DIR)/utilities/cassandra/cassandra_format_test.o $(TEST_LIBRARY) $(LIBRARY)
cassandra_format_test: $(OBJ_DIR)/utilities/cassandra/cassandra_format_test.o $(OBJ_DIR)/utilities/cassandra/test_utils.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
cassandra_functional_test: $(OBJ_DIR)/utilities/cassandra/cassandra_functional_test.o $(TEST_LIBRARY) $(LIBRARY)
cassandra_functional_test: $(OBJ_DIR)/utilities/cassandra/cassandra_functional_test.o $(OBJ_DIR)/utilities/cassandra/test_utils.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
cassandra_row_merge_test: $(OBJ_DIR)/utilities/cassandra/cassandra_row_merge_test.o $(TEST_LIBRARY) $(LIBRARY)
cassandra_row_merge_test: $(OBJ_DIR)/utilities/cassandra/cassandra_row_merge_test.o $(OBJ_DIR)/utilities/cassandra/test_utils.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
cassandra_serialize_test: $(OBJ_DIR)/utilities/cassandra/cassandra_serialize_test.o $(TEST_LIBRARY) $(LIBRARY)
@@ -1883,9 +1881,6 @@ heap_test: $(OBJ_DIR)/util/heap_test.o $(TEST_LIBRARY) $(LIBRARY)
point_lock_manager_test: utilities/transactions/lock/point/point_lock_manager_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
point_lock_manager_stress_test: utilities/transactions/lock/point/point_lock_manager_stress_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
transaction_test: $(OBJ_DIR)/utilities/transactions/transaction_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -2256,7 +2251,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 ${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 -DSNAPPY_BUILD_BENCHMARKS=OFF -DSNAPPY_BUILD_TESTS=OFF --compile-no-warning-as-error ${PLATFORM_CMAKE_FLAGS} .. && $(MAKE) ${SNAPPY_MAKE_TARGET}
cp snappy-$(SNAPPY_VER)/build/libsnappy.a .
lz4-$(LZ4_VER).tar.gz:
-12
View File
@@ -206,12 +206,6 @@ def generate_buck(repo_path, deps_map):
src_mk.get("CACHE_BENCH_LIB_SOURCES", []),
[":rocksdb_lib"],
)
# rocksdb_point_lock_bench_tools_lib
BUCK.add_library(
"rocksdb_point_lock_bench_tools_lib",
src_mk.get("POINT_LOCK_BENCH_LIB_SOURCES", []),
[":rocksdb_lib"],
)
# rocksdb_stress_lib
BUCK.add_rocksdb_library(
"rocksdb_stress_lib",
@@ -235,12 +229,6 @@ def generate_buck(repo_path, deps_map):
BUCK.add_binary(
"cache_bench", ["cache/cache_bench.cc"], [":rocksdb_cache_bench_tools_lib"]
)
# point_lock_bench binary
BUCK.add_binary(
"point_lock_bench",
["utilities/transactions/lock/point/point_lock_bench.cc"],
[":rocksdb_point_lock_bench_tools_lib"]
)
# bench binaries
for src in src_mk.get("MICROBENCH_SOURCES", []):
name = src.rsplit("/", 1)[1].split(".")[0] if "/" in src else src.split(".")[0]
+2 -2
View File
@@ -45,11 +45,11 @@ if test -z "$OUTPUT"; then
exit 1
fi
# we depend on C++20, but should be compatible with newer standards
# we depend on C++17, but should be compatible with newer standards
if [ "$ROCKSDB_CXX_STANDARD" ]; then
PLATFORM_CXXFLAGS="-std=$ROCKSDB_CXX_STANDARD"
else
PLATFORM_CXXFLAGS="-std=c++20"
PLATFORM_CXXFLAGS="-std=c++17"
fi
# we currently depend on POSIX platform
-88
View File
@@ -1,88 +0,0 @@
# INSTRUCTIONS:
# I was not able to build docker images on an isolated devserver because of
# issues with proxy internet access. Use a public cloud or other Linux system.
# (I used a Debian system after installing docker features, adding my user to
# the docker and docker-registry groups, and logging out and back in to pick
# those up.)
#
# Follow https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-with-a-personal-access-token-classic
# to login with your GitHub credentials, as in
#
# $ docker login ghcr.io -u pdillinger
#
# and paste the limited-purpose GitHub token into the terminal.
#
# Then in the build_tools/ubuntu22_image directory, (bump minor version for
# random docker file updates, major version tracks Ubuntu release)
#
# $ docker build -t ghcr.io/facebook/rocksdb_ubuntu:22.0
# $ docker push ghcr.io/facebook/rocksdb_ubuntu:22.0
#
# Might need to change visibility to public through
# https://github.com/orgs/facebook/packages/container/rocksdb_ubuntu/settings
# or similar.
# from official ubuntu 22.04
FROM ubuntu:22.04
# update system
RUN apt-get update
RUN apt-get upgrade -y
# install basic tools
RUN apt-get install -y vim wget curl
# install tzdata noninteractive
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
# install git and default compilers
RUN apt-get install -y git gcc g++ clang clang-tools
# install basic package
RUN apt-get install -y lsb-release software-properties-common gnupg
# install gflags, tbb
RUN apt-get install -y libgflags-dev libtbb-dev
# install compression libs
RUN apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
# install cmake
RUN apt-get install -y cmake
RUN apt-get install -y libssl-dev
# install clang-13
WORKDIR /root
RUN wget https://apt.llvm.org/llvm.sh
RUN chmod +x llvm.sh
RUN ./llvm.sh 13 all
# There are incompatibilities between clang with -std=c++20 and libstdc++
# provided by gcc, so we have to compile with clang-13 using -stdlib=libc++
# and only one version of libc++ can be installed on the system at one time.
# So to avoid confusion we remove unusable clang-14 also.
RUN apt-get install libc++-13-dev libc++abi-13-dev
RUN apt-get purge -y clang-14 && apt-get autoremove -y
# install gcc-10 and more, default is 11
RUN apt-get install -y gcc-10 g++-10
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test
RUN apt-get install -y gcc-13 g++-13
# install apt-get install -y valgrind
RUN apt-get install -y valgrind
# install folly depencencies
# Missing compatible libunwind: RUN apt-get install -y libgoogle-glog-dev
# So instead install from source. This currently requires compiling with
# -DGLOG_USE_GLOG_EXPORT
RUN wget https://github.com/google/glog/archive/refs/tags/v0.7.1.tar.gz && tar xzf v0.7.1.tar.gz && cd glog-0.7.1/ && cmake -S . -B build -G "Unix Makefiles" && cmake --build build && cmake --build build --target install && cd .. && rm -rf v0.7.1.tar.gz glog-0.7.1
# install openjdk 8
RUN apt-get install -y openjdk-8-jdk
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-amd64
# install mingw
RUN apt-get install -y mingw-w64
# install gtest-parallel package
RUN git clone --single-branch --branch master --depth 1 https://github.com/google/gtest-parallel.git ~/gtest-parallel
ENV PATH $PATH:/root/gtest-parallel
# install libprotobuf for fuzzers test
RUN apt-get install -y ninja-build binutils liblzma-dev libz-dev pkg-config autoconf libtool
RUN git clone --branch v1.0 https://github.com/google/libprotobuf-mutator.git ~/libprotobuf-mutator && cd ~/libprotobuf-mutator && git checkout ffd86a32874e5c08a143019aad1aaf0907294c9f && mkdir build && cd build && cmake .. -GNinja -DCMAKE_C_COMPILER=clang-13 -DCMAKE_CXX_COMPILER=clang++-13 -DCMAKE_BUILD_TYPE=Release -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON && ninja && ninja install
ENV PKG_CONFIG_PATH /usr/local/OFF/:/root/libprotobuf-mutator/build/external.protobuf/lib/pkgconfig/
ENV PROTOC_BIN /root/libprotobuf-mutator/build/external.protobuf/bin/protoc
# install the latest google benchmark
RUN git clone --depth 1 --branch v1.7.0 https://github.com/google/benchmark.git ~/benchmark && cd ~/benchmark && mkdir build && cd build && cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_GTEST_TESTS=0 && ninja && ninja install && cd ~ && rm -rf /root/benchmark
# clean up
RUN rm -rf /var/lib/apt/lists/*
-72
View File
@@ -1,72 +0,0 @@
# INSTRUCTIONS:
# I was not able to build docker images on an isolated devserver because of
# issues with proxy internet access. Use a public cloud or other Linux system.
# (I used a Debian system after installing docker features, adding my user to
# the docker and docker-registry groups, and logging out and back in to pick
# those up.)
#
# Follow https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-with-a-personal-access-token-classic
# to login with your GitHub credentials, as in
#
# $ docker login ghcr.io -u pdillinger
#
# and paste the limited-purpose GitHub token into the terminal.
#
# Then in the build_tools/ubuntu24_image directory, (bump minor version for
# random docker file updates, major version tracks Ubuntu release)
#
# $ docker build -t ghcr.io/facebook/rocksdb_ubuntu:24.0
# $ docker push ghcr.io/facebook/rocksdb_ubuntu:24.0
#
# Might need to change visibility to public through
# https://github.com/orgs/facebook/packages/container/rocksdb_ubuntu/settings
# or similar.
# from official ubuntu 24.04
FROM ubuntu:24.04
# update system
RUN apt-get update
RUN apt-get upgrade -y
# install basic tools
RUN apt-get install -y vim wget curl
# install tzdata noninteractive
RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata
# install git and default compilers
RUN apt-get install -y git gcc g++ clang clang-tools
# install basic package
RUN apt-get install -y lsb-release software-properties-common gnupg
# install gflags, tbb
RUN apt-get install -y libgflags-dev libtbb-dev
# install compression libs
RUN apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
# install cmake
RUN apt-get install -y cmake
RUN apt-get install -y libssl-dev
# install gcc-12 and more, default is 13
RUN apt-get install -y gcc-12 g++-12 gcc-14 g++-14
# install apt-get install -y valgrind
RUN apt-get install -y valgrind
# install folly depencencies
RUN apt-get install -y libgoogle-glog-dev
# install openjdk 8
RUN apt-get install -y openjdk-8-jdk
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-amd64
# install mingw
RUN apt-get install -y mingw-w64
# install gtest-parallel package
RUN git clone --single-branch --branch master --depth 1 https://github.com/google/gtest-parallel.git ~/gtest-parallel
ENV PATH $PATH:/root/gtest-parallel
# install libprotobuf for fuzzers test
RUN apt-get install -y ninja-build binutils liblzma-dev libz-dev pkg-config autoconf libtool
RUN git clone --branch v1.0 https://github.com/google/libprotobuf-mutator.git ~/libprotobuf-mutator && cd ~/libprotobuf-mutator && git checkout ffd86a32874e5c08a143019aad1aaf0907294c9f && mkdir build && cd build && cmake .. -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON && ninja && ninja install
ENV PKG_CONFIG_PATH /usr/local/OFF/:/root/libprotobuf-mutator/build/external.protobuf/lib/pkgconfig/
ENV PROTOC_BIN /root/libprotobuf-mutator/build/external.protobuf/bin/protoc
# install the latest google benchmark
RUN git clone --depth 1 --branch v1.7.0 https://github.com/google/benchmark.git ~/benchmark && cd ~/benchmark && mkdir build && cd build && cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_GTEST_TESTS=0 && ninja && ninja install && cd ~ && rm -rf /root/benchmark
# clean up
RUN rm -rf /var/lib/apt/lists/*
+8 -74
View File
@@ -184,11 +184,6 @@ DEFINE_bool(sck_randomize, false,
DEFINE_bool(sck_footer_unique_id, false,
"(-stress_cache_key) Simulate using proposed footer unique id");
// ## END stress_cache_key sub-tool options ##
// ## BEGIN stress_cache_instances sub-tool options ##
DEFINE_uint32(stress_cache_instances, 0,
"If > 0, run cache instance stress test instead");
// Uses cache_size and cache_type, maybe more
// ## END stress_cache_instance sub-tool options ##
namespace ROCKSDB_NAMESPACE {
@@ -392,12 +387,7 @@ class CacheBench {
fprintf(stderr, "Percentages must add to 100.\n");
exit(1);
}
cache_ = MakeCache();
}
~CacheBench() = default;
static std::shared_ptr<Cache> MakeCache() {
std::shared_ptr<MemoryAllocator> allocator;
if (FLAGS_use_jemalloc_no_dump_allocator) {
JemallocAllocatorOptions opts;
@@ -416,12 +406,12 @@ class CacheBench {
opts.hash_seed = BitwiseAnd(FLAGS_seed, INT32_MAX);
opts.memory_allocator = allocator;
opts.eviction_effort_cap = FLAGS_eviction_effort_cap;
if (FLAGS_cache_type == "fixed_hyper_clock_cache") {
if (FLAGS_cache_type == "fixed_hyper_clock_cache" ||
FLAGS_cache_type == "hyper_clock_cache") {
opts.estimated_entry_charge = FLAGS_value_bytes_estimate > 0
? FLAGS_value_bytes_estimate
: FLAGS_value_bytes;
} else if (FLAGS_cache_type == "auto_hyper_clock_cache" ||
FLAGS_cache_type == "hyper_clock_cache") {
} else if (FLAGS_cache_type == "auto_hyper_clock_cache") {
if (FLAGS_value_bytes_estimate > 0) {
opts.min_avg_entry_charge = FLAGS_value_bytes_estimate;
}
@@ -430,7 +420,7 @@ class CacheBench {
exit(1);
}
ConfigureSecondaryCache(opts);
return opts.MakeSharedCache();
cache_ = opts.MakeSharedCache();
} else if (FLAGS_cache_type == "lru_cache") {
LRUCacheOptions opts(FLAGS_cache_size, FLAGS_num_shard_bits,
false /* strict_capacity_limit */,
@@ -438,13 +428,15 @@ class CacheBench {
opts.hash_seed = BitwiseAnd(FLAGS_seed, INT32_MAX);
opts.memory_allocator = allocator;
ConfigureSecondaryCache(opts);
return NewLRUCache(opts);
cache_ = NewLRUCache(opts);
} else {
fprintf(stderr, "Cache type not supported.\n");
exit(1);
}
}
~CacheBench() = default;
void PopulateCache() {
Random64 rnd(FLAGS_seed);
KeyGen keygen;
@@ -498,7 +490,7 @@ class CacheBench {
PrintEnv();
SharedState shared(this);
std::vector<std::unique_ptr<ThreadState>> threads(FLAGS_threads);
std::vector<std::unique_ptr<ThreadState> > threads(FLAGS_threads);
for (uint32_t i = 0; i < FLAGS_threads; i++) {
threads[i].reset(new ThreadState(i, &shared));
std::thread(ThreadBody, threads[i].get()).detach();
@@ -1160,59 +1152,6 @@ class StressCacheKey {
double multiplier_ = 0.0;
};
// cache_bench -stress_cache_instances is a partially independent embedded tool
// for evaluating the time and space required to create and destroy many cache
// instances, as this is considered important for a default cache implementation
// which could see many throw-away instances in handling of Options, or created
// in large numbers for many very small DBs with many CFs. Prefix command line
// with /usr/bin/time to see max RSS memory.
class StressCacheInstances {
public:
void Run() {
const int kNumIterations = 10;
const auto clock = SystemClock::Default().get();
caches_.reserve(FLAGS_stress_cache_instances);
uint64_t total_create_time_us = 0;
uint64_t total_destroy_time_us = 0;
for (int iter = 0; iter < kNumIterations; ++iter) {
// Create many cache instances
uint64_t start_create = clock->NowMicros();
for (uint32_t i = 0; i < FLAGS_stress_cache_instances; ++i) {
caches_.emplace_back(CacheBench::MakeCache());
}
uint64_t end_create = clock->NowMicros();
uint64_t create_time = end_create - start_create;
total_create_time_us += create_time;
// Destroy them
uint64_t start_destroy = clock->NowMicros();
caches_.clear();
uint64_t end_destroy = clock->NowMicros();
uint64_t destroy_time = end_destroy - start_destroy;
total_destroy_time_us += destroy_time;
printf(
"Iteration %d: Created %u caches in %.3f ms, destroyed in %.3f ms\n",
iter + 1, FLAGS_stress_cache_instances, create_time / 1000.0,
destroy_time / 1000.0);
}
printf("Average creation time: %.3f ms (%.1f us per cache)\n",
static_cast<double>(total_create_time_us) / kNumIterations / 1000.0,
static_cast<double>(total_create_time_us) / kNumIterations /
FLAGS_stress_cache_instances);
printf("Average destruction time: %.3f ms (%.1f us per cache)\n",
static_cast<double>(total_destroy_time_us) / kNumIterations / 1000.0,
static_cast<double>(total_destroy_time_us) / kNumIterations /
FLAGS_stress_cache_instances);
}
private:
std::vector<std::shared_ptr<Cache>> caches_;
};
int cache_bench_tool(int argc, char** argv) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
ParseCommandLineFlags(&argc, &argv, true);
@@ -1223,11 +1162,6 @@ int cache_bench_tool(int argc, char** argv) {
return 0;
}
if (FLAGS_stress_cache_instances > 0) {
StressCacheInstances().Run();
return 0;
}
if (FLAGS_threads <= 0) {
fprintf(stderr, "threads number <= 0\n");
exit(1);
+75 -88
View File
@@ -10,12 +10,12 @@
#include "cache/clock_cache.h"
#include <algorithm>
#include <atomic>
#include <bitset>
#include <cassert>
#include <cinttypes>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <exception>
#include <functional>
#include <numeric>
@@ -26,9 +26,10 @@
#include "cache/cache_key.h"
#include "cache/secondary_cache_adapter.h"
#include "logging/logging.h"
#include "port/likely.h"
#include "monitoring/perf_context_imp.h"
#include "monitoring/statistics_impl.h"
#include "port/lang.h"
#include "rocksdb/env.h"
#include "util/autovector.h"
#include "util/hash.h"
#include "util/math.h"
#include "util/random.h"
@@ -360,9 +361,16 @@ void ConstApplyToEntriesRange(const Func& func, const HandleImpl* begin,
}
}
uint32_t SanitizeEvictionEffortCap(int eviction_effort_cap) {
constexpr uint32_t kStrictCapacityLimitBit = 1u << 31;
uint32_t SanitizeEncodeEecAndScl(int eviction_effort_cap,
bool strict_capacit_limit) {
eviction_effort_cap = std::max(int{1}, eviction_effort_cap);
return static_cast<uint32_t>(eviction_effort_cap);
eviction_effort_cap =
std::min(static_cast<int>(~kStrictCapacityLimitBit), eviction_effort_cap);
uint32_t eec_and_scl = static_cast<uint32_t>(eviction_effort_cap);
eec_and_scl |= strict_capacit_limit ? kStrictCapacityLimitBit : 0;
return eec_and_scl;
}
} // namespace
@@ -373,22 +381,6 @@ void ClockHandleBasicData::FreeData(MemoryAllocator* allocator) const {
}
}
BaseClockTable::BaseClockTable(size_t capacity, bool strict_capacity_limit,
int eviction_effort_cap,
CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback,
const uint32_t* hash_seed)
: capacity_(capacity),
eec_and_scl_(EecAndScl{}
.With<EvictionEffortCap>(
SanitizeEvictionEffortCap(eviction_effort_cap))
.With<StrictCapacityLimit>(strict_capacity_limit)),
metadata_charge_policy_(metadata_charge_policy),
allocator_(allocator),
eviction_callback_(*eviction_callback),
hash_seed_(*hash_seed) {}
template <class HandleImpl>
HandleImpl* BaseClockTable::StandaloneInsert(
const ClockHandleBasicData& proto) {
@@ -410,7 +402,8 @@ HandleImpl* BaseClockTable::StandaloneInsert(
template <class Table>
typename Table::HandleImpl* BaseClockTable::CreateStandalone(
ClockHandleBasicData& proto, bool allow_uncharged) {
ClockHandleBasicData& proto, size_t capacity, uint32_t eec_and_scl,
bool allow_uncharged) {
Table& derived = static_cast<Table&>(*this);
typename Table::InsertState state;
derived.StartInsert(state);
@@ -419,10 +412,10 @@ typename Table::HandleImpl* BaseClockTable::CreateStandalone(
// NOTE: we can use eec_and_scl as eviction_effort_cap below because
// strict_capacity_limit=true is supposed to disable the limit on eviction
// effort, and a large value effectively does that.
if (eec_and_scl_.LoadRelaxed().Get<StrictCapacityLimit>()) {
if (eec_and_scl & kStrictCapacityLimitBit) {
Status s = ChargeUsageMaybeEvictStrict<Table>(
total_charge,
/*need_evict_for_occupancy=*/false, state);
total_charge, capacity,
/*need_evict_for_occupancy=*/false, eec_and_scl, state);
if (!s.ok()) {
if (allow_uncharged) {
proto.total_charge = 0;
@@ -433,8 +426,8 @@ typename Table::HandleImpl* BaseClockTable::CreateStandalone(
} else {
// Case strict_capacity_limit == false
bool success = ChargeUsageMaybeEvictNonStrict<Table>(
total_charge,
/*need_evict_for_occupancy=*/false, state);
total_charge, capacity,
/*need_evict_for_occupancy=*/false, eec_and_scl, state);
if (!success) {
// Force the issue
usage_.FetchAddRelaxed(total_charge);
@@ -446,9 +439,8 @@ typename Table::HandleImpl* BaseClockTable::CreateStandalone(
template <class Table>
Status BaseClockTable::ChargeUsageMaybeEvictStrict(
size_t total_charge, bool need_evict_for_occupancy,
typename Table::InsertState& state) {
const size_t capacity = capacity_.LoadRelaxed();
size_t total_charge, size_t capacity, bool need_evict_for_occupancy,
uint32_t eviction_effort_cap, typename Table::InsertState& state) {
if (total_charge > capacity) {
return Status::MemoryLimit(
"Cache entry too large for a single cache shard: " +
@@ -473,7 +465,8 @@ Status BaseClockTable::ChargeUsageMaybeEvictStrict(
}
if (request_evict_charge > 0) {
EvictionData data;
static_cast<Table*>(this)->Evict(request_evict_charge, state, &data);
static_cast<Table*>(this)->Evict(request_evict_charge, state, &data,
eviction_effort_cap);
occupancy_.FetchSub(data.freed_count);
if (LIKELY(data.freed_charge > need_evict_charge)) {
assert(data.freed_count > 0);
@@ -502,8 +495,8 @@ Status BaseClockTable::ChargeUsageMaybeEvictStrict(
template <class Table>
inline bool BaseClockTable::ChargeUsageMaybeEvictNonStrict(
size_t total_charge, bool need_evict_for_occupancy,
typename Table::InsertState& state) {
size_t total_charge, size_t capacity, bool need_evict_for_occupancy,
uint32_t eviction_effort_cap, typename Table::InsertState& state) {
// For simplicity, we consider that either the cache can accept the insert
// with no evictions, or we must evict enough to make (at least) enough
// space. It could lead to unnecessary failures or excessive evictions in
@@ -513,8 +506,7 @@ inline bool BaseClockTable::ChargeUsageMaybeEvictNonStrict(
// charge. Thus, we should evict some extra if it's not a signifcant
// portion of the shard capacity. This can have the side benefit of
// involving fewer threads in eviction.
const size_t old_usage = usage_.LoadRelaxed();
const size_t capacity = capacity_.LoadRelaxed();
size_t old_usage = usage_.LoadRelaxed();
size_t need_evict_charge;
// NOTE: if total_charge > old_usage, there isn't yet enough to evict
// `total_charge` amount. Even if we only try to evict `old_usage` amount,
@@ -540,7 +532,8 @@ inline bool BaseClockTable::ChargeUsageMaybeEvictNonStrict(
}
EvictionData data;
if (need_evict_charge > 0) {
static_cast<Table*>(this)->Evict(need_evict_charge, state, &data);
static_cast<Table*>(this)->Evict(need_evict_charge, state, &data,
eviction_effort_cap);
// Deal with potential occupancy deficit
if (UNLIKELY(need_evict_for_occupancy) && data.freed_count == 0) {
assert(data.freed_charge == 0);
@@ -576,10 +569,8 @@ void BaseClockTable::TrackAndReleaseEvictedEntry(ClockHandle* h) {
MarkEmpty(*h);
}
bool BaseClockTable::IsEvictionEffortExceeded(
const BaseClockTable::EvictionData& data) const {
auto eviction_effort_cap =
eec_and_scl_.LoadRelaxed().GetEffectiveEvictionEffortCap();
bool IsEvictionEffortExceeded(const BaseClockTable::EvictionData& data,
uint32_t eviction_effort_cap) {
// Basically checks whether the ratio of useful effort to wasted effort is
// too low, with a start-up allowance for wasted effort before any useful
// effort.
@@ -590,7 +581,8 @@ bool BaseClockTable::IsEvictionEffortExceeded(
template <class Table>
Status BaseClockTable::Insert(const ClockHandleBasicData& proto,
typename Table::HandleImpl** handle,
Cache::Priority priority) {
Cache::Priority priority, size_t capacity,
uint32_t eec_and_scl) {
using HandleImpl = typename Table::HandleImpl;
Table& derived = static_cast<Table&>(*this);
@@ -611,9 +603,9 @@ Status BaseClockTable::Insert(const ClockHandleBasicData& proto,
// NOTE: we can use eec_and_scl as eviction_effort_cap below because
// strict_capacity_limit=true is supposed to disable the limit on eviction
// effort, and a large value effectively does that.
if (eec_and_scl_.LoadRelaxed().Get<StrictCapacityLimit>()) {
if (eec_and_scl & kStrictCapacityLimitBit) {
Status s = ChargeUsageMaybeEvictStrict<Table>(
total_charge, need_evict_for_occupancy, state);
total_charge, capacity, need_evict_for_occupancy, eec_and_scl, state);
if (!s.ok()) {
// Revert occupancy
occupancy_.FetchSubRelaxed(1);
@@ -622,7 +614,7 @@ Status BaseClockTable::Insert(const ClockHandleBasicData& proto,
} else {
// Case strict_capacity_limit == false
bool success = ChargeUsageMaybeEvictNonStrict<Table>(
total_charge, need_evict_for_occupancy, state);
total_charge, capacity, need_evict_for_occupancy, eec_and_scl, state);
if (!success) {
// Revert occupancy
occupancy_.FetchSubRelaxed(1);
@@ -726,13 +718,11 @@ void BaseClockTable::TEST_ReleaseNMinus1(ClockHandle* h, size_t n) {
#endif
FixedHyperClockTable::FixedHyperClockTable(
size_t capacity, bool strict_capacity_limit,
CacheMetadataChargePolicy metadata_charge_policy,
size_t capacity, CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback, const uint32_t* hash_seed,
const Opts& opts)
: BaseClockTable(capacity, strict_capacity_limit, opts.eviction_effort_cap,
metadata_charge_policy, allocator, eviction_callback,
: BaseClockTable(metadata_charge_policy, allocator, eviction_callback,
hash_seed),
length_bits_(CalcHashBits(capacity, opts.estimated_value_size,
metadata_charge_policy)),
@@ -1123,7 +1113,8 @@ inline void FixedHyperClockTable::ReclaimEntryUsage(size_t total_charge) {
}
inline void FixedHyperClockTable::Evict(size_t requested_charge, InsertState&,
EvictionData* data) {
EvictionData* data,
uint32_t eviction_effort_cap) {
// precondition
assert(requested_charge > 0);
@@ -1158,7 +1149,7 @@ inline void FixedHyperClockTable::Evict(size_t requested_charge, InsertState&,
if (old_clock_pointer >= max_clock_pointer) {
return;
}
if (IsEvictionEffortExceeded(*data)) {
if (IsEvictionEffortExceeded(*data, eviction_effort_cap)) {
eviction_effort_exceeded_count_.FetchAddRelaxed(1);
return;
}
@@ -1176,11 +1167,14 @@ ClockCacheShard<Table>::ClockCacheShard(
const Cache::EvictionCallback* eviction_callback, const uint32_t* hash_seed,
const typename Table::Opts& opts)
: CacheShardBase(metadata_charge_policy),
table_(capacity, strict_capacity_limit, metadata_charge_policy, allocator,
eviction_callback, hash_seed, opts) {
table_(capacity, metadata_charge_policy, allocator, eviction_callback,
hash_seed, opts),
capacity_(capacity),
eec_and_scl_(SanitizeEncodeEecAndScl(opts.eviction_effort_cap,
strict_capacity_limit)) {
// Initial charge metadata should not exceed capacity
assert(table_.GetUsage() <= table_.GetCapacity() ||
table_.GetCapacity() < sizeof(HandleImpl));
assert(table_.GetUsage() <= capacity_.LoadRelaxed() ||
capacity_.LoadRelaxed() < sizeof(HandleImpl));
}
template <class Table>
@@ -1246,14 +1240,18 @@ int FixedHyperClockTable::CalcHashBits(
template <class Table>
void ClockCacheShard<Table>::SetCapacity(size_t capacity) {
table_.SetCapacity(capacity);
capacity_.StoreRelaxed(capacity);
// next Insert will take care of any necessary evictions
}
template <class Table>
void ClockCacheShard<Table>::SetStrictCapacityLimit(
bool strict_capacity_limit) {
table_.SetStrictCapacityLimit(strict_capacity_limit);
if (strict_capacity_limit) {
eec_and_scl_.FetchOrRelaxed(kStrictCapacityLimitBit);
} else {
eec_and_scl_.FetchAndRelaxed(~kStrictCapacityLimitBit);
}
// next Insert will take care of any necessary evictions
}
@@ -1273,7 +1271,9 @@ Status ClockCacheShard<Table>::Insert(const Slice& key,
proto.value = value;
proto.helper = helper;
proto.total_charge = charge;
return table_.template Insert<Table>(proto, handle, priority);
return table_.template Insert<Table>(proto, handle, priority,
capacity_.LoadRelaxed(),
eec_and_scl_.LoadRelaxed());
}
template <class Table>
@@ -1288,7 +1288,9 @@ typename Table::HandleImpl* ClockCacheShard<Table>::CreateStandalone(
proto.value = obj;
proto.helper = helper;
proto.total_charge = charge;
return table_.template CreateStandalone<Table>(proto, allow_uncharged);
return table_.template CreateStandalone<Table>(proto, capacity_.LoadRelaxed(),
eec_and_scl_.LoadRelaxed(),
allow_uncharged);
}
template <class Table>
@@ -1357,7 +1359,7 @@ size_t ClockCacheShard<Table>::GetStandaloneUsage() const {
template <class Table>
size_t ClockCacheShard<Table>::GetCapacity() const {
return table_.GetCapacity();
return capacity_.LoadRelaxed();
}
template <class Table>
@@ -1725,13 +1727,10 @@ inline uint64_t UsedLengthToLengthInfo(size_t used_length) {
return length_info;
}
// Avoid potential initialization order race with port::kPageSize
constexpr size_t kPresumedPageSize = 4096;
inline size_t GetStartingLength(size_t capacity) {
if (capacity > kPresumedPageSize) {
if (capacity > port::kPageSize) {
// Start with one memory page
return kPresumedPageSize / sizeof(AutoHyperClockTable::HandleImpl);
return port::kPageSize / sizeof(AutoHyperClockTable::HandleImpl);
} else {
// Mostly to make unit tests happy
return 4;
@@ -1970,13 +1969,11 @@ class AutoHyperClockTable::ChainRewriteLock {
};
AutoHyperClockTable::AutoHyperClockTable(
size_t capacity, bool strict_capacity_limit,
CacheMetadataChargePolicy metadata_charge_policy,
size_t capacity, CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback, const uint32_t* hash_seed,
const Opts& opts)
: BaseClockTable(capacity, strict_capacity_limit, opts.eviction_effort_cap,
metadata_charge_policy, allocator, eviction_callback,
: BaseClockTable(metadata_charge_policy, allocator, eviction_callback,
hash_seed),
array_(MemMapping::AllocateLazyZeroed(
sizeof(HandleImpl) * CalcMaxUsableLength(capacity,
@@ -1988,11 +1985,6 @@ AutoHyperClockTable::AutoHyperClockTable(
grow_frontier_(GetTableSize()),
clock_pointer_mask_(
BottomNBits(UINT64_MAX, LengthInfoToMinShift(length_info_.Load()))) {
if (array_.Get() == nullptr) {
fprintf(stderr,
"Anonymous mmap for RocksDB HyperClockCache failed. Aborting.\n");
std::terminate();
}
if (metadata_charge_policy ==
CacheMetadataChargePolicy::kFullChargeCacheMetadata) {
// NOTE: ignoring page boundaries for simplicity
@@ -2060,21 +2052,15 @@ AutoHyperClockTable::~AutoHyperClockTable() {
HandleImpl::kUnusedMarker) {
used_end++;
}
// This check can be extra expensive for a cache that is just created,
// maybe used for a small number of entries, as in a unit test, and then
// destroyed. Only do this in rare modes. REVISED: Don't scan the whole mmap,
// just a reasonable frontier past what we expect to have written.
#ifdef MUST_FREE_HEAP_ALLOCATIONS
for (size_t i = used_end; i < array_.Count() && i < used_end + 64U; i++) {
#ifndef NDEBUG
for (size_t i = used_end; i < array_.Count(); i++) {
assert(array_[i].head_next_with_shift.LoadRelaxed() == 0);
assert(array_[i].chain_next_with_shift.LoadRelaxed() == 0);
assert(array_[i].meta.LoadRelaxed() == 0);
}
#endif // MUST_FREE_HEAP_ALLOCATIONS
#ifndef NDEBUG // Extra invariant checking
std::vector<bool> was_populated(used_end);
std::vector<bool> was_pointed_to(used_end);
#endif // !NDEBUG
#endif
for (size_t i = 0; i < used_end; i++) {
HandleImpl& h = array_[i];
switch (h.meta.LoadRelaxed() >> ClockHandle::kStateShift) {
@@ -2097,7 +2083,7 @@ AutoHyperClockTable::~AutoHyperClockTable() {
assert(!was_pointed_to[next]);
was_pointed_to[next] = true;
}
#endif // !NDEBUG
#endif
break;
// otherwise
default:
@@ -2111,7 +2097,7 @@ AutoHyperClockTable::~AutoHyperClockTable() {
assert(!was_pointed_to[next]);
was_pointed_to[next] = true;
}
#endif // !NDEBUG
#endif
}
#ifndef NDEBUG // Extra invariant checking
// This check is not perfect, but should detect most reasonable cases
@@ -2124,7 +2110,7 @@ AutoHyperClockTable::~AutoHyperClockTable() {
assert(!was_pointed_to[i]);
}
}
#endif // !NDEBUG
#endif
// Metadata charging only follows the published table size
assert(usage_.LoadRelaxed() == 0 ||
@@ -3482,7 +3468,8 @@ void AutoHyperClockTable::EraseUnRefEntries() {
}
void AutoHyperClockTable::Evict(size_t requested_charge, InsertState& state,
EvictionData* data) {
EvictionData* data,
uint32_t eviction_effort_cap) {
// precondition
assert(requested_charge > 0);
@@ -3574,7 +3561,7 @@ void AutoHyperClockTable::Evict(size_t requested_charge, InsertState& state,
return;
}
if (IsEvictionEffortExceeded(*data)) {
if (IsEvictionEffortExceeded(*data, eviction_effort_cap)) {
eviction_effort_exceeded_count_.FetchAddRelaxed(1);
return;
}
@@ -3592,7 +3579,7 @@ size_t AutoHyperClockTable::CalcMaxUsableLength(
size_t num_slots =
static_cast<size_t>(capacity / min_avg_slot_charge + 0.999999);
const size_t slots_per_page = kPresumedPageSize / sizeof(HandleImpl);
const size_t slots_per_page = port::kPageSize / sizeof(HandleImpl);
// Round up to page size
return ((num_slots + slots_per_page - 1) / slots_per_page) * slots_per_page;
+36 -44
View File
@@ -9,6 +9,8 @@
#pragma once
#include <array>
#include <atomic>
#include <climits>
#include <cstddef>
#include <cstdint>
@@ -17,10 +19,14 @@
#include "cache/cache_key.h"
#include "cache/sharded_cache.h"
#include "port/lang.h"
#include "port/malloc.h"
#include "port/mmap.h"
#include "port/port.h"
#include "rocksdb/cache.h"
#include "rocksdb/secondary_cache.h"
#include "util/atomic.h"
#include "util/bit_fields.h"
#include "util/autovector.h"
#include "util/math.h"
namespace ROCKSDB_NAMESPACE {
@@ -377,20 +383,25 @@ class BaseClockTable {
int eviction_effort_cap;
};
BaseClockTable(size_t capacity, bool strict_capacity_limit,
int eviction_effort_cap,
CacheMetadataChargePolicy metadata_charge_policy,
BaseClockTable(CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback,
const uint32_t* hash_seed);
const uint32_t* hash_seed)
: metadata_charge_policy_(metadata_charge_policy),
allocator_(allocator),
eviction_callback_(*eviction_callback),
hash_seed_(*hash_seed) {}
template <class Table>
typename Table::HandleImpl* CreateStandalone(ClockHandleBasicData& proto,
size_t capacity,
uint32_t eec_and_scl,
bool allow_uncharged);
template <class Table>
Status Insert(const ClockHandleBasicData& proto,
typename Table::HandleImpl** handle, Cache::Priority priority);
typename Table::HandleImpl** handle, Cache::Priority priority,
size_t capacity, uint32_t eec_and_scl);
void Ref(ClockHandle& handle);
@@ -400,18 +411,6 @@ class BaseClockTable {
size_t GetStandaloneUsage() const { return standalone_usage_.LoadRelaxed(); }
size_t GetCapacity() const { return capacity_.LoadRelaxed(); }
void SetCapacity(size_t capacity) { capacity_.StoreRelaxed(capacity); }
void SetStrictCapacityLimit(bool strict_capacity_limit) {
if (strict_capacity_limit) {
eec_and_scl_.ApplyRelaxed(StrictCapacityLimit::SetTransform());
} else {
eec_and_scl_.ApplyRelaxed(StrictCapacityLimit::ClearTransform());
}
}
uint32_t GetHashSeed() const { return hash_seed_; }
uint64_t GetYieldCount() const { return yield_count_.LoadRelaxed(); }
@@ -428,7 +427,6 @@ class BaseClockTable {
void TrackAndReleaseEvictedEntry(ClockHandle* h);
bool IsEvictionEffortExceeded(const BaseClockTable::EvictionData& data) const;
#ifndef NDEBUG
// Acquire N references
void TEST_RefN(ClockHandle& handle, size_t n);
@@ -450,8 +448,9 @@ class BaseClockTable {
// required, and the operation should fail if not possible.
// NOTE: Otherwise, occupancy_ is not managed in this function
template <class Table>
Status ChargeUsageMaybeEvictStrict(size_t total_charge,
Status ChargeUsageMaybeEvictStrict(size_t total_charge, size_t capacity,
bool need_evict_for_occupancy,
uint32_t eviction_effort_cap,
typename Table::InsertState& state);
// Helper for updating `usage_` for new entry with given `total_charge`
@@ -463,8 +462,9 @@ class BaseClockTable {
// true, indicating success.
// NOTE: occupancy_ is not managed in this function
template <class Table>
bool ChargeUsageMaybeEvictNonStrict(size_t total_charge,
bool ChargeUsageMaybeEvictNonStrict(size_t total_charge, size_t capacity,
bool need_evict_for_occupancy,
uint32_t eviction_effort_cap,
typename Table::InsertState& state);
protected: // data
@@ -497,25 +497,6 @@ class BaseClockTable {
// Part of usage by standalone entries (not in table)
AcqRelAtomic<size_t> standalone_usage_{};
// Maximum total charge of all elements stored in the table.
// (Relaxed: eventual consistency/update is OK)
RelaxedAtomic<size_t> capacity_;
// Encodes eviction_effort_cap (bottom 31 bits) and strict_capacity_limit
// (top bit). See HyperClockCacheOptions::eviction_effort_cap etc.
struct EecAndScl : public BitFields<uint32_t, EecAndScl> {
uint32_t GetEffectiveEvictionEffortCap() const {
// Because setting strict_capacity_limit is supposed to imply infinite
// cap on eviction effort, we can let the bit for strict_capacity_limit
// in the upper-most bit position to used as part of the effective cap.
return underlying;
}
};
using EvictionEffortCap = UnsignedBitField<EecAndScl, 31, NoPrevBitField>;
using StrictCapacityLimit = BoolBitField<EecAndScl, EvictionEffortCap>;
// (Relaxed: eventual consistency/update is OK)
RelaxedBitFieldsAtomic<EecAndScl> eec_and_scl_;
ALIGN_AS(CACHE_LINE_SIZE)
const CacheMetadataChargePolicy metadata_charge_policy_;
@@ -570,7 +551,7 @@ class FixedHyperClockTable : public BaseClockTable {
size_t estimated_value_size;
};
FixedHyperClockTable(size_t capacity, bool strict_capacity_limit,
FixedHyperClockTable(size_t capacity,
CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback,
@@ -592,7 +573,8 @@ class FixedHyperClockTable : public BaseClockTable {
// Runs the clock eviction algorithm trying to reclaim at least
// requested_charge. Returns how much is evicted, which could be less
// if it appears impossible to evict the requested amount without blocking.
void Evict(size_t requested_charge, InsertState& state, EvictionData* data);
void Evict(size_t requested_charge, InsertState& state, EvictionData* data,
uint32_t eviction_effort_cap);
HandleImpl* Lookup(const UniqueId64x2& hashed_key);
@@ -859,7 +841,7 @@ class AutoHyperClockTable : public BaseClockTable {
size_t min_avg_value_size;
};
AutoHyperClockTable(size_t capacity, bool strict_capacity_limit,
AutoHyperClockTable(size_t capacity,
CacheMetadataChargePolicy metadata_charge_policy,
MemoryAllocator* allocator,
const Cache::EvictionCallback* eviction_callback,
@@ -886,7 +868,8 @@ class AutoHyperClockTable : public BaseClockTable {
// Runs the clock eviction algorithm trying to reclaim at least
// requested_charge. Returns how much is evicted, which could be less
// if it appears impossible to evict the requested amount without blocking.
void Evict(size_t requested_charge, InsertState& state, EvictionData* data);
void Evict(size_t requested_charge, InsertState& state, EvictionData* data,
uint32_t eviction_effort_cap);
HandleImpl* Lookup(const UniqueId64x2& hashed_key);
@@ -1119,6 +1102,15 @@ class ALIGN_AS(CACHE_LINE_SIZE) ClockCacheShard final : public CacheShardBase {
private: // data
Table table_;
// Maximum total charge of all elements stored in the table.
// (Relaxed: eventual consistency/update is OK)
RelaxedAtomic<size_t> capacity_;
// Encodes eviction_effort_cap (bottom 31 bits) and strict_capacity_limit
// (top bit). See HyperClockCacheOptions::eviction_effort_cap etc.
// (Relaxed: eventual consistency/update is OK)
RelaxedAtomic<uint32_t> eec_and_scl_;
}; // class ClockCacheShard
template <class Table>
+1 -1
View File
@@ -1405,9 +1405,9 @@ TEST_P(BasicSecondaryCacheTest, SaveFailTest) {
TestItem* item1 = new TestItem(str1.data(), str1.length());
ASSERT_OK(cache->Insert(k1.AsSlice(), item1, GetHelperFail(), str1.length()));
std::string str2 = rnd.RandomString(1020);
ASSERT_EQ(secondary_cache->num_inserts(), 0u);
TestItem* item2 = new TestItem(str2.data(), str2.length());
// k1 should be demoted to NVM
ASSERT_EQ(secondary_cache->num_inserts(), 0u);
ASSERT_OK(cache->Insert(k2.AsSlice(), item2, GetHelperFail(), str2.length()));
ASSERT_EQ(secondary_cache->num_inserts(), 1u);
+1 -1
View File
@@ -584,7 +584,7 @@ Status CacheWithSecondaryAdapter::UpdateCacheReservationRatio(
size_t pri_capacity = target_->GetCapacity();
size_t sec_capacity =
static_cast<size_t>(pri_capacity * compressed_secondary_ratio);
size_t old_sec_capacity = 0;
size_t old_sec_capacity;
Status s = secondary_cache_->GetCapacity(old_sec_capacity);
if (!s.ok()) {
return s;
-3
View File
@@ -342,9 +342,6 @@ Status BuildTable(
if (s.ok() && !empty) {
if (flush_stats) {
flush_stats->bytes_written_pre_comp = builder->PreCompressionSize();
// Add worker CPU micros here. Caller needs to add CPU micros from
// calling thread.
flush_stats->cpu_micros += builder->GetWorkerCPUMicros();
}
uint64_t file_size = builder->FileSize();
meta->fd.file_size = file_size;
-193
View File
@@ -82,7 +82,6 @@ using ROCKSDB_NAMESPACE::DbPath;
using ROCKSDB_NAMESPACE::Env;
using ROCKSDB_NAMESPACE::EnvOptions;
using ROCKSDB_NAMESPACE::EventListener;
using ROCKSDB_NAMESPACE::ExportImportFilesMetaData;
using ROCKSDB_NAMESPACE::ExternalFileIngestionInfo;
using ROCKSDB_NAMESPACE::FileLock;
using ROCKSDB_NAMESPACE::FilterPolicy;
@@ -90,7 +89,6 @@ using ROCKSDB_NAMESPACE::FlushJobInfo;
using ROCKSDB_NAMESPACE::FlushOptions;
using ROCKSDB_NAMESPACE::HistogramData;
using ROCKSDB_NAMESPACE::HyperClockCacheOptions;
using ROCKSDB_NAMESPACE::ImportColumnFamilyOptions;
using ROCKSDB_NAMESPACE::InfoLogLevel;
using ROCKSDB_NAMESPACE::IngestExternalFileOptions;
using ROCKSDB_NAMESPACE::Iterator;
@@ -247,9 +245,6 @@ struct rocksdb_write_buffer_manager_t {
struct rocksdb_sst_file_manager_t {
std::shared_ptr<SstFileManager> rep;
};
struct rocksdb_livefile_t {
LiveFileMetaData rep;
};
struct rocksdb_livefiles_t {
std::vector<LiveFileMetaData> rep;
};
@@ -260,12 +255,6 @@ struct rocksdb_column_family_handle_t {
struct rocksdb_column_family_metadata_t {
ColumnFamilyMetaData rep;
};
struct rocksdb_export_import_files_metadata_t {
ExportImportFilesMetaData* rep;
};
struct rocksdb_import_column_family_options_t {
ImportColumnFamilyOptions rep;
};
struct rocksdb_level_metadata_t {
const LevelMetaData* rep;
};
@@ -958,22 +947,6 @@ void rocksdb_checkpoint_create(rocksdb_checkpoint_t* checkpoint,
std::string(checkpoint_dir), log_size_for_flush));
}
rocksdb_export_import_files_metadata_t* rocksdb_checkpoint_export_column_family(
rocksdb_checkpoint_t* checkpoint,
rocksdb_column_family_handle_t* column_family, const char* export_dir,
char** errptr) {
ExportImportFilesMetaData* metadata = nullptr;
if (SaveError(errptr,
checkpoint->rep->ExportColumnFamily(
column_family->rep, std::string(export_dir), &metadata))) {
return nullptr;
}
rocksdb_export_import_files_metadata_t* result =
new rocksdb_export_import_files_metadata_t;
result->rep = metadata;
return result;
}
void rocksdb_checkpoint_object_destroy(rocksdb_checkpoint_t* checkpoint) {
delete checkpoint->rep;
delete checkpoint;
@@ -1217,26 +1190,6 @@ rocksdb_column_family_handle_t** rocksdb_create_column_families(
return c_handles;
}
rocksdb_column_family_handle_t* rocksdb_create_column_family_with_import(
rocksdb_t* db, rocksdb_options_t* column_family_options,
const char* column_family_name,
rocksdb_import_column_family_options_t* import_options,
rocksdb_export_import_files_metadata_t* export_import_files_metadata,
char** errptr) {
rocksdb_column_family_handle_t* handle = new rocksdb_column_family_handle_t;
handle->rep = nullptr;
if (SaveError(errptr,
db->rep->CreateColumnFamilyWithImport(
ColumnFamilyOptions(column_family_options->rep),
std::string(column_family_name), import_options->rep,
*(export_import_files_metadata->rep), &(handle->rep)))) {
delete handle;
return nullptr;
}
handle->immortal = false;
return handle;
}
void rocksdb_create_column_families_destroy(
rocksdb_column_family_handle_t** list) {
free(list);
@@ -6256,10 +6209,6 @@ void rocksdb_options_set_min_level_to_compress(rocksdb_options_t* opt,
}
}
rocksdb_livefiles_t* rocksdb_livefiles_create() {
return new rocksdb_livefiles_t;
}
int rocksdb_livefiles_count(const rocksdb_livefiles_t* lf) {
return static_cast<int>(lf->rep.size());
}
@@ -6273,16 +6222,6 @@ const char* rocksdb_livefiles_name(const rocksdb_livefiles_t* lf, int index) {
return lf->rep[index].name.c_str();
}
const char* rocksdb_livefiles_directory(const rocksdb_livefiles_t* lf,
int index) {
if (lf->rep[index].directory.empty()) {
// db_path is deprecated but still returned by some code paths
return lf->rep[index].db_path.c_str();
} else {
return lf->rep[index].directory.c_str();
}
}
int rocksdb_livefiles_level(const rocksdb_livefiles_t* lf, int index) {
return lf->rep[index].level;
}
@@ -6303,16 +6242,6 @@ const char* rocksdb_livefiles_largestkey(const rocksdb_livefiles_t* lf,
return lf->rep[index].largestkey.data();
}
uint64_t rocksdb_livefiles_smallest_seqno(const rocksdb_livefiles_t* lf,
int index) {
return lf->rep[index].smallest_seqno;
}
uint64_t rocksdb_livefiles_largest_seqno(const rocksdb_livefiles_t* lf,
int index) {
return lf->rep[index].largest_seqno;
}
uint64_t rocksdb_livefiles_entries(const rocksdb_livefiles_t* lf, int index) {
return lf->rep[index].num_entries;
}
@@ -6323,71 +6252,6 @@ uint64_t rocksdb_livefiles_deletions(const rocksdb_livefiles_t* lf, int index) {
void rocksdb_livefiles_destroy(const rocksdb_livefiles_t* lf) { delete lf; }
rocksdb_livefile_t* rocksdb_livefile_create() { return new rocksdb_livefile_t; }
void rocksdb_livefile_set_column_family_name(rocksdb_livefile_t* lf,
const char* column_family_name) {
lf->rep.column_family_name = std::string(column_family_name);
}
void rocksdb_livefile_set_level(rocksdb_livefile_t* lf, int level) {
lf->rep.level = level;
}
void rocksdb_livefile_set_name(rocksdb_livefile_t* lf, const char* name) {
lf->rep.name = std::string(name);
}
void rocksdb_livefile_set_directory(rocksdb_livefile_t* lf,
const char* directory) {
lf->rep.directory = std::string(directory);
lf->rep.db_path = std::string(directory); // deprecated but still needed
}
void rocksdb_livefile_set_size(rocksdb_livefile_t* lf, size_t size) {
lf->rep.size = size;
}
void rocksdb_livefile_set_smallest_key(rocksdb_livefile_t* lf,
const char* smallest_key,
size_t smallest_key_len) {
lf->rep.smallestkey = std::string(smallest_key, smallest_key_len);
}
void rocksdb_livefile_set_largest_key(rocksdb_livefile_t* lf,
const char* largest_key,
size_t largest_key_len) {
lf->rep.largestkey = std::string(largest_key, largest_key_len);
}
void rocksdb_livefile_set_smallest_seqno(rocksdb_livefile_t* lf,
uint64_t smallest_seqno) {
lf->rep.smallest_seqno = smallest_seqno;
}
void rocksdb_livefile_set_largest_seqno(rocksdb_livefile_t* lf,
uint64_t largest_seqno) {
lf->rep.largest_seqno = largest_seqno;
}
void rocksdb_livefile_set_num_entries(rocksdb_livefile_t* lf,
uint64_t num_entries) {
lf->rep.num_entries = num_entries;
}
void rocksdb_livefile_set_num_deletions(rocksdb_livefile_t* lf,
uint64_t num_deletions) {
lf->rep.num_deletions = num_deletions;
}
void rocksdb_livefile_destroy(rocksdb_livefile_t* lf) { delete lf; }
void rocksdb_livefiles_add(rocksdb_livefiles_t* lf,
rocksdb_livefile_t* livefile) {
lf->rep.push_back(std::move(livefile->rep));
delete livefile;
}
void rocksdb_get_options_from_string(const rocksdb_options_t* base_options,
const char* opts_str,
rocksdb_options_t* new_options,
@@ -6538,58 +6402,6 @@ char* rocksdb_sst_file_metadata_get_largestkey(
return CopyString(file_meta->rep->largestkey);
}
rocksdb_import_column_family_options_t*
rocksdb_import_column_family_options_create() {
return new rocksdb_import_column_family_options_t;
}
void rocksdb_import_column_family_options_set_move_files(
rocksdb_import_column_family_options_t* opt, unsigned char v) {
opt->rep.move_files = v;
}
void rocksdb_import_column_family_options_destroy(
rocksdb_import_column_family_options_t* metadata) {
delete metadata;
}
rocksdb_export_import_files_metadata_t*
rocksdb_export_import_files_metadata_create() {
auto metadata = new rocksdb_export_import_files_metadata_t;
metadata->rep = new ExportImportFilesMetaData;
return metadata;
}
char* rocksdb_export_import_files_metadata_get_db_comparator_name(
rocksdb_export_import_files_metadata_t* metadata) {
return strdup(metadata->rep->db_comparator_name.c_str());
}
void rocksdb_export_import_files_metadata_set_db_comparator_name(
rocksdb_export_import_files_metadata_t* metadata, const char* name) {
metadata->rep->db_comparator_name = std::string(name);
}
rocksdb_livefiles_t* rocksdb_export_import_files_metadata_get_files(
rocksdb_export_import_files_metadata_t* export_import_metadata) {
auto files = new rocksdb_livefiles_t;
files->rep = std::vector(export_import_metadata->rep->files);
return files;
}
void rocksdb_export_import_files_metadata_set_files(
rocksdb_export_import_files_metadata_t* metadata,
rocksdb_livefiles_t* files) {
metadata->rep->files = std::move(files->rep);
delete files;
}
void rocksdb_export_import_files_metadata_destroy(
rocksdb_export_import_files_metadata_t* metadata) {
delete metadata->rep;
delete metadata;
}
/* Transactions */
rocksdb_transactiondb_options_t* rocksdb_transactiondb_options_create() {
@@ -6621,11 +6433,6 @@ void rocksdb_transactiondb_options_set_default_lock_timeout(
opt->rep.default_lock_timeout = default_lock_timeout;
}
void rocksdb_transactiondb_options_set_use_per_key_point_lock_mgr(
rocksdb_transactiondb_options_t* opt, int use_per_key_point_lock_mgr) {
opt->rep.use_per_key_point_lock_mgr = use_per_key_point_lock_mgr;
}
rocksdb_transaction_options_t* rocksdb_transaction_options_create() {
return new rocksdb_transaction_options_t;
}
-72
View File
@@ -1036,78 +1036,6 @@ int main(int argc, char** argv) {
rocksdb_options_set_error_if_exists(options, 1);
}
StartPhase("checkpoint_export_column_family");
{
static char cf_export_path[200];
static char db_import_path[200];
snprintf(cf_export_path, sizeof(cf_export_path),
"%s/rocksdb_c_test-%d-cf_export", GetTempDir(), ((int)geteuid()));
snprintf(db_import_path, sizeof(db_import_path),
"%s/rocksdb_c_test-%d-db_import", GetTempDir(), ((int)geteuid()));
rocksdb_options_t* db_options = rocksdb_options_create();
rocksdb_column_family_handle_t* cf_export =
rocksdb_create_column_family(db, db_options, "cf_export", &err);
CheckNoError(err);
rocksdb_put_cf(db, woptions, cf_export, "k1", 2, "v1", 2, &err);
CheckNoError(err);
rocksdb_put_cf(db, woptions, cf_export, "k2", 2, "v2", 2, &err);
CheckNoError(err);
rocksdb_checkpoint_t* checkpoint =
rocksdb_checkpoint_object_create(db, &err);
CheckNoError(err);
rocksdb_export_import_files_metadata_t* export_metadata =
rocksdb_checkpoint_export_column_family(checkpoint, cf_export,
cf_export_path, &err);
CheckNoError(err);
const char* comparator_name =
rocksdb_export_import_files_metadata_get_db_comparator_name(
export_metadata);
CheckEqual("leveldb.BytewiseComparator", comparator_name, 26);
rocksdb_free((void*)comparator_name);
rocksdb_checkpoint_object_destroy(checkpoint);
checkpoint = NULL;
rocksdb_drop_column_family(db, cf_export, &err);
CheckNoError(err);
rocksdb_column_family_handle_destroy(cf_export);
rocksdb_options_set_create_if_missing(db_options, 1);
rocksdb_options_set_error_if_exists(db_options, 1);
rocksdb_t* db_import = rocksdb_open(db_options, db_import_path, &err);
CheckNoError(err);
rocksdb_import_column_family_options_t* import_options =
rocksdb_import_column_family_options_create();
rocksdb_column_family_handle_t* cf_import =
rocksdb_create_column_family_with_import(db_import, db_options,
"cf_import", import_options,
export_metadata, &err);
CheckNoError(err);
rocksdb_import_column_family_options_destroy(import_options);
rocksdb_export_import_files_metadata_destroy(export_metadata);
size_t val_len;
char* val =
rocksdb_get_cf(db_import, roptions, cf_import, "k1", 2, &val_len, &err);
CheckNoError(err);
CheckEqual("v1", val, val_len);
free(val);
val =
rocksdb_get_cf(db_import, roptions, cf_import, "k2", 2, &val_len, &err);
CheckNoError(err);
CheckEqual("v2", val, val_len);
free(val);
rocksdb_column_family_handle_destroy(cf_import);
cf_import = NULL;
rocksdb_close(db_import);
rocksdb_destroy_db(db_options, db_import_path, &err);
CheckNoError(err);
rocksdb_options_destroy(db_options);
db_options = NULL;
}
StartPhase("compactall");
rocksdb_compact_range(db, NULL, 0, NULL, 0);
CheckGet(db, roptions, "foo", "hello");
+11 -9
View File
@@ -1120,15 +1120,17 @@ void CompactionIterator::NextFromInput() {
}
}
if (status_.ok()) {
if (!Valid() && IsShuttingDown()) {
status_ = Status::ShutdownInProgress();
} else if (IsPausingManualCompaction()) {
status_ = Status::Incomplete(Status::SubCode::kManualCompactionPaused);
} else if (!input_.Valid() && input_.status().IsCorruption()) {
// Propagate corruption status from memtable iterator
status_ = input_.status();
}
if (!Valid() && IsShuttingDown()) {
status_ = Status::ShutdownInProgress();
}
if (IsPausingManualCompaction()) {
status_ = Status::Incomplete(Status::SubCode::kManualCompactionPaused);
}
// Propagate corruption status from memtable itereator
if (!input_.Valid() && input_.status().IsCorruption()) {
status_ = input_.status();
}
}
+4 -18
View File
@@ -183,20 +183,10 @@ class CompactionIterator {
const Compaction* compaction_;
};
// @param must_count_input_entries Controls input entry counting accuracy vs
// performance:
// - If true: `NumInputEntryScanned()` always returns the exact count of
// input keys
// scanned. The iterator will use sequential `Next()` calls instead of
// `Seek()` to maintain count accuracy as `Seek()` will not count the
// skipped input entries, which is slower but guarantees correctness.
// - If false: `NumInputEntryScanned()` returns the count only if no
// `Seek()` operations
// were performed on the input iterator. When compaction filters request
// skipping ranges of keys or other optimizations trigger seek operations,
// the count becomes unreliable. Always call `HasNumInputEntryScanned()`
// first to verify if the count is accurate before using
// `NumInputEntryScanned()`.
// @param must_count_input_entries if true, `NumInputEntryScanned()` will
// return the number of input keys scanned. If false, `NumInputEntryScanned()`
// will return this number if no Seek was called on `input`. User should call
// `HasNumInputEntryScanned()` first in this case.
CompactionIterator(
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
SequenceNumber last_sequence, std::vector<SequenceNumber>* snapshots,
@@ -265,10 +255,6 @@ class CompactionIterator {
}
const CompactionIterationStats& iter_stats() const { return iter_stats_; }
bool HasNumInputEntryScanned() const { return input_.HasNumItered(); }
// This method should only be used when `HasNumInputEntryScanned()` returns
// true, unless `must_count_input_entries=true` was specified during iterator
// creation (which ensures the count is always accurate).
uint64_t NumInputEntryScanned() const { return input_.NumItered(); }
Status InputStatus() const { return input_.status(); }
+222 -340
View File
@@ -170,11 +170,7 @@ CompactionJob::CompactionJob(
blob_output_directory_(blob_output_directory),
db_mutex_(db_mutex),
db_error_handler_(db_error_handler),
// job_context cannot be nullptr, but we will assert later in the body of
// the constructor.
earliest_snapshot_(job_context
? job_context->GetEarliestSnapshotSequence()
: kMaxSequenceNumber),
earliest_snapshot_(job_context->GetEarliestSnapshotSequence()),
job_context_(job_context),
table_cache_(std::move(table_cache)),
event_logger_(event_logger),
@@ -189,7 +185,6 @@ CompactionJob::CompactionJob(
bg_bottom_compaction_scheduled_(bg_bottom_compaction_scheduled) {
assert(job_stats_ != nullptr);
assert(log_buffer_ != nullptr);
assert(job_context);
assert(job_context->snapshot_context_initialized);
const auto* cfd = compact_->compaction->column_family_data();
@@ -882,7 +877,7 @@ void CompactionJob::SetOutputTableProperties() {
}
}
void CompactionJob::AggregateSubcompactionOutputAndJobStats() {
void CompactionJob::AggregateSubcompactionStats() {
// Before the compaction starts, is_remote_compaction was set to true if
// compaction_service is set. We now know whether each sub_compaction was
// done remotely or not. Reset is_remote_compaction back to false and allow
@@ -896,8 +891,7 @@ void CompactionJob::AggregateSubcompactionOutputAndJobStats() {
Status CompactionJob::VerifyCompactionRecordCounts(
bool stats_built_from_input_table_prop, uint64_t num_input_range_del) {
Status status;
if (stats_built_from_input_table_prop &&
job_stats_->has_accurate_num_input_records) {
if (stats_built_from_input_table_prop && job_stats_->has_num_input_records) {
status = VerifyInputRecordCount(num_input_range_del);
if (!status.ok()) {
return status;
@@ -921,10 +915,9 @@ void CompactionJob::FinalizeCompactionRun(
const Status& input_status, bool stats_built_from_input_table_prop,
uint64_t num_input_range_del) {
if (stats_built_from_input_table_prop) {
UpdateCompactionJobInputStatsFromInternalStats(internal_stats_,
num_input_range_del);
UpdateCompactionJobInputStats(internal_stats_, num_input_range_del);
}
UpdateCompactionJobOutputStatsFromInternalStats(internal_stats_);
UpdateCompactionJobOutputStats(internal_stats_);
RecordCompactionIOStats();
LogFlush(db_options_.info_log);
@@ -959,11 +952,11 @@ Status CompactionJob::Run() {
SetOutputTableProperties();
}
AggregateSubcompactionOutputAndJobStats();
AggregateSubcompactionStats();
uint64_t num_input_range_del = 0;
bool stats_built_from_input_table_prop =
UpdateInternalStatsFromInputFiles(&num_input_range_del);
BuildStatsFromInputFiles(&num_input_range_del);
if (status.ok()) {
status = VerifyCompactionRecordCounts(stats_built_from_input_table_prop,
@@ -1196,62 +1189,58 @@ void CompactionJob::NotifyOnSubcompactionCompleted(
}
}
bool CompactionJob::ShouldUseLocalCompaction(SubcompactionState* sub_compact) {
void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
assert(sub_compact);
assert(sub_compact->compaction);
if (db_options_.compaction_service) {
CompactionServiceJobStatus comp_status =
ProcessKeyValueCompactionWithCompactionService(sub_compact);
if (comp_status != CompactionServiceJobStatus::kUseLocal) {
return false;
return;
}
// fallback to local compaction
assert(comp_status == CompactionServiceJobStatus::kUseLocal);
sub_compact->compaction_job_stats.is_remote_compaction = false;
}
return true;
}
CompactionJob::CompactionIOStatsSnapshot CompactionJob::InitializeIOStats() {
CompactionIOStatsSnapshot io_stats;
uint64_t prev_cpu_micros = db_options_.clock->CPUMicros();
if (measure_io_stats_) {
io_stats.prev_perf_level = GetPerfLevel();
SetPerfLevel(PerfLevel::kEnableTimeAndCPUTimeExceptForMutex);
io_stats.prev_write_nanos = IOSTATS(write_nanos);
io_stats.prev_fsync_nanos = IOSTATS(fsync_nanos);
io_stats.prev_range_sync_nanos = IOSTATS(range_sync_nanos);
io_stats.prev_prepare_write_nanos = IOSTATS(prepare_write_nanos);
io_stats.prev_cpu_write_nanos = IOSTATS(cpu_write_nanos);
io_stats.prev_cpu_read_nanos = IOSTATS(cpu_read_nanos);
}
return io_stats;
}
Status CompactionJob::SetupAndValidateCompactionFilter(
SubcompactionState* sub_compact,
const CompactionFilter* configured_compaction_filter,
const CompactionFilter*& compaction_filter,
std::unique_ptr<CompactionFilter>& compaction_filter_from_factory) {
compaction_filter = configured_compaction_filter;
ColumnFamilyData* cfd = sub_compact->compaction->column_family_data();
// Create compaction filter and fail the compaction if
// IgnoreSnapshots() = false because it is not supported anymore
const CompactionFilter* compaction_filter = cfd->ioptions().compaction_filter;
std::unique_ptr<CompactionFilter> compaction_filter_from_factory = nullptr;
if (compaction_filter == nullptr) {
compaction_filter_from_factory =
sub_compact->compaction->CreateCompactionFilter();
compaction_filter = compaction_filter_from_factory.get();
}
if (compaction_filter != nullptr && !compaction_filter->IgnoreSnapshots()) {
return Status::NotSupported(
sub_compact->status = Status::NotSupported(
"CompactionFilter::IgnoreSnapshots() = false is not supported "
"anymore.");
return;
}
return Status::OK();
}
NotifyOnSubcompactionBegin(sub_compact);
void CompactionJob::InitializeReadOptions(
ColumnFamilyData* cfd, ReadOptions& read_options,
SubcompactionKeyBoundaries& boundaries) {
// This is assigned after creation of SubcompactionState to simplify that
// creation across both CompactionJob and CompactionServiceCompactionJob
sub_compact->AssignRangeDelAggregator(
std::make_unique<CompactionRangeDelAggregator>(
&cfd->internal_comparator(), job_context_->snapshot_seqs,
&full_history_ts_low_, &trim_ts_));
// TODO: since we already use C++17, should use
// std::optional<const Slice> instead.
const std::optional<Slice> start = sub_compact->start;
const std::optional<Slice> end = sub_compact->end;
std::optional<Slice> start_without_ts;
std::optional<Slice> end_without_ts;
ReadOptions read_options;
read_options.verify_checksums = true;
read_options.fill_cache = false;
read_options.rate_limiter_priority = GetRateLimiterPriority();
@@ -1262,207 +1251,222 @@ void CompactionJob::InitializeReadOptions(
// (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.
const size_t ts_sz = cfd->user_comparator()->timestamp_size();
if (boundaries.start.has_value()) {
read_options.iterate_lower_bound = &(*boundaries.start);
size_t ts_sz = cfd->user_comparator()->timestamp_size();
if (start.has_value()) {
read_options.iterate_lower_bound = &(*start);
if (ts_sz > 0) {
boundaries.start_without_ts =
StripTimestampFromUserKey(*boundaries.start, ts_sz);
read_options.iterate_lower_bound = &(*boundaries.start_without_ts);
start_without_ts = StripTimestampFromUserKey(*start, ts_sz);
read_options.iterate_lower_bound = &(*start_without_ts);
}
}
if (boundaries.end.has_value()) {
read_options.iterate_upper_bound = &(*boundaries.end);
if (end.has_value()) {
read_options.iterate_upper_bound = &(*end);
if (ts_sz > 0) {
boundaries.end_without_ts =
StripTimestampFromUserKey(*boundaries.end, ts_sz);
read_options.iterate_upper_bound = &(*boundaries.end_without_ts);
end_without_ts = StripTimestampFromUserKey(*end, ts_sz);
read_options.iterate_upper_bound = &(*end_without_ts);
}
}
}
InternalIterator* CompactionJob::CreateInputIterator(
SubcompactionState* sub_compact, ColumnFamilyData* cfd,
SubcompactionInternalIterators& iterators,
SubcompactionKeyBoundaries& boundaries, ReadOptions& read_options) {
// This is assigned after creation of SubcompactionState to simplify that
// creation across both CompactionJob and CompactionServiceCompactionJob
sub_compact->AssignRangeDelAggregator(
std::make_unique<CompactionRangeDelAggregator>(
&cfd->internal_comparator(), job_context_->snapshot_seqs,
&full_history_ts_low_, &trim_ts_));
InitializeReadOptions(cfd, read_options, boundaries);
// Although the v2 aggregator is what the level iterator(s) know about,
// the AddTombstones calls will be propagated down to the v1 aggregator.
iterators.raw_input =
std::unique_ptr<InternalIterator>(versions_->MakeInputIterator(
read_options, sub_compact->compaction, sub_compact->RangeDelAgg(),
file_options_for_read_, boundaries.start, boundaries.end));
InternalIterator* input = iterators.raw_input.get();
std::unique_ptr<InternalIterator> raw_input(versions_->MakeInputIterator(
read_options, sub_compact->compaction, sub_compact->RangeDelAgg(),
file_options_for_read_, start, end));
InternalIterator* input = raw_input.get();
const size_t ts_sz = cfd->user_comparator()->timestamp_size();
IterKey start_ikey;
IterKey end_ikey;
Slice start_slice;
Slice end_slice;
Slice start_user_key{};
Slice end_user_key{};
static constexpr char kMaxTs[] =
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
Slice ts_slice;
std::string max_ts;
if (ts_sz > 0) {
if (ts_sz <= strlen(boundaries.kMaxTs)) {
boundaries.ts_slice = Slice(boundaries.kMaxTs, ts_sz);
if (ts_sz <= strlen(kMaxTs)) {
ts_slice = Slice(kMaxTs, ts_sz);
} else {
boundaries.max_ts = std::string(ts_sz, '\xff');
boundaries.ts_slice = Slice(boundaries.max_ts);
max_ts = std::string(ts_sz, '\xff');
ts_slice = Slice(max_ts);
}
}
if (boundaries.start.has_value()) {
boundaries.start_ikey.SetInternalKey(*boundaries.start, kMaxSequenceNumber,
kValueTypeForSeek);
if (start.has_value()) {
start_ikey.SetInternalKey(*start, kMaxSequenceNumber, kValueTypeForSeek);
if (ts_sz > 0) {
boundaries.start_ikey.UpdateInternalKey(
kMaxSequenceNumber, kValueTypeForSeek, &boundaries.ts_slice);
start_ikey.UpdateInternalKey(kMaxSequenceNumber, kValueTypeForSeek,
&ts_slice);
}
boundaries.start_internal_key = boundaries.start_ikey.GetInternalKey();
boundaries.start_user_key = boundaries.start_ikey.GetUserKey();
start_slice = start_ikey.GetInternalKey();
start_user_key = start_ikey.GetUserKey();
}
if (boundaries.end.has_value()) {
boundaries.end_ikey.SetInternalKey(*boundaries.end, kMaxSequenceNumber,
kValueTypeForSeek);
if (end.has_value()) {
end_ikey.SetInternalKey(*end, kMaxSequenceNumber, kValueTypeForSeek);
if (ts_sz > 0) {
boundaries.end_ikey.UpdateInternalKey(
kMaxSequenceNumber, kValueTypeForSeek, &boundaries.ts_slice);
end_ikey.UpdateInternalKey(kMaxSequenceNumber, kValueTypeForSeek,
&ts_slice);
}
boundaries.end_internal_key = boundaries.end_ikey.GetInternalKey();
boundaries.end_user_key = boundaries.end_ikey.GetUserKey();
end_slice = end_ikey.GetInternalKey();
end_user_key = end_ikey.GetUserKey();
}
if (boundaries.start.has_value() || boundaries.end.has_value()) {
iterators.clip = std::make_unique<ClippingIterator>(
iterators.raw_input.get(),
boundaries.start.has_value() ? &boundaries.start_internal_key : nullptr,
boundaries.end.has_value() ? &boundaries.end_internal_key : nullptr,
&cfd->internal_comparator());
input = iterators.clip.get();
std::unique_ptr<InternalIterator> clip;
if (start.has_value() || end.has_value()) {
clip = std::make_unique<ClippingIterator>(
raw_input.get(), start.has_value() ? &start_slice : nullptr,
end.has_value() ? &end_slice : nullptr, &cfd->internal_comparator());
input = clip.get();
}
std::unique_ptr<InternalIterator> blob_counter;
if (sub_compact->compaction->DoesInputReferenceBlobFiles()) {
BlobGarbageMeter* meter = sub_compact->Current().CreateBlobGarbageMeter();
iterators.blob_counter =
std::make_unique<BlobCountingIterator>(input, meter);
input = iterators.blob_counter.get();
blob_counter = std::make_unique<BlobCountingIterator>(input, meter);
input = blob_counter.get();
}
std::unique_ptr<InternalIterator> trim_history_iter;
if (ts_sz > 0 && !trim_ts_.empty()) {
iterators.trim_history_iter = std::make_unique<HistoryTrimmingIterator>(
trim_history_iter = std::make_unique<HistoryTrimmingIterator>(
input, cfd->user_comparator(), trim_ts_);
input = iterators.trim_history_iter.get();
input = trim_history_iter.get();
}
return input;
}
input->SeekToFirst();
AutoThreadOperationStageUpdater stage_updater(
ThreadStatus::STAGE_COMPACTION_PROCESS_KV);
// I/O measurement variables
PerfLevel prev_perf_level = PerfLevel::kEnableTime;
const uint64_t kRecordStatsEvery = 1000;
uint64_t prev_write_nanos = 0;
uint64_t prev_fsync_nanos = 0;
uint64_t prev_range_sync_nanos = 0;
uint64_t prev_prepare_write_nanos = 0;
uint64_t prev_cpu_write_nanos = 0;
uint64_t prev_cpu_read_nanos = 0;
if (measure_io_stats_) {
prev_perf_level = GetPerfLevel();
SetPerfLevel(PerfLevel::kEnableTimeAndCPUTimeExceptForMutex);
prev_write_nanos = IOSTATS(write_nanos);
prev_fsync_nanos = IOSTATS(fsync_nanos);
prev_range_sync_nanos = IOSTATS(range_sync_nanos);
prev_prepare_write_nanos = IOSTATS(prepare_write_nanos);
prev_cpu_write_nanos = IOSTATS(cpu_write_nanos);
prev_cpu_read_nanos = IOSTATS(cpu_read_nanos);
}
MergeHelper merge(
env_, cfd->user_comparator(), cfd->ioptions().merge_operator.get(),
compaction_filter, db_options_.info_log.get(),
false /* internal key corruption is expected */,
job_context_->GetLatestSnapshotSequence(), job_context_->snapshot_checker,
compact_->compaction->level(), db_options_.stats);
void CompactionJob::CreateBlobFileBuilder(SubcompactionState* sub_compact,
ColumnFamilyData* cfd,
BlobFileResources& blob_resources,
const WriteOptions& write_options) {
const auto& mutable_cf_options =
sub_compact->compaction->mutable_cf_options();
std::vector<std::string> blob_file_paths;
// TODO: BlobDB to support output_to_proximal_level compaction, which needs
// 2 builders, so may need to move to `CompactionOutputs`
if (mutable_cf_options.enable_blob_files &&
sub_compact->compaction->output_level() >=
mutable_cf_options.blob_file_starting_level) {
blob_resources.blob_file_builder = std::make_unique<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(), write_hint_,
io_tracer_, blob_callback_, BlobFileCreationReason::kCompaction,
&blob_resources.blob_file_paths,
sub_compact->Current().GetBlobFileAdditionsPtr());
} else {
blob_resources.blob_file_builder = nullptr;
}
}
std::unique_ptr<BlobFileBuilder> blob_file_builder(
(mutable_cf_options.enable_blob_files &&
sub_compact->compaction->output_level() >=
mutable_cf_options.blob_file_starting_level)
? 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(),
write_hint_, io_tracer_, blob_callback_,
BlobFileCreationReason::kCompaction, &blob_file_paths,
sub_compact->Current().GetBlobFileAdditionsPtr())
: nullptr);
std::unique_ptr<CompactionIterator> CompactionJob::CreateCompactionIterator(
SubcompactionState* sub_compact, ColumnFamilyData* cfd,
InternalIterator* input, const CompactionFilter* compaction_filter,
MergeHelper& merge, BlobFileResources& blob_resources,
const WriteOptions& write_options) {
CreateBlobFileBuilder(sub_compact, cfd, blob_resources, write_options);
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_)));
const std::string* const full_history_ts_low =
full_history_ts_low_.empty() ? nullptr : &full_history_ts_low_;
assert(job_context_);
const SequenceNumber job_snapshot_seq =
job_context_ ? job_context_->GetJobSnapshotSequence()
: kMaxSequenceNumber;
return std::make_unique<CompactionIterator>(
auto c_iter = std::make_unique<CompactionIterator>(
input, cfd->user_comparator(), &merge, versions_->LastSequence(),
&(job_context_->snapshot_seqs), earliest_snapshot_,
job_context_->earliest_write_conflict_snapshot,
job_context_->GetJobSnapshotSequence(), job_context_->snapshot_checker,
env_, ShouldReportDetailedTime(env_, stats_), sub_compact->RangeDelAgg(),
blob_resources.blob_file_builder.get(), db_options_.allow_data_in_errors,
job_context_->earliest_write_conflict_snapshot, job_snapshot_seq,
job_context_->snapshot_checker, env_,
ShouldReportDetailedTime(env_, stats_), sub_compact->RangeDelAgg(),
blob_file_builder.get(), db_options_.allow_data_in_errors,
db_options_.enforce_single_del_contracts, manual_compaction_canceled_,
sub_compact->compaction->DoesInputReferenceBlobFiles(),
sub_compact->compaction
->DoesInputReferenceBlobFiles() /* must_count_input_entries */,
sub_compact->compaction, compaction_filter, shutting_down_,
db_options_.info_log, full_history_ts_low, preserve_seqno_after_);
}
c_iter->SeekToFirst();
std::pair<CompactionFileOpenFunc, CompactionFileCloseFunc>
CompactionJob::CreateFileHandlers(SubcompactionState* sub_compact,
SubcompactionKeyBoundaries& boundaries) {
const auto& c_iter_stats = c_iter->iter_stats();
// define the open and close functions for the compaction files, which will be
// used open/close output files when needed.
const CompactionFileOpenFunc open_file_func =
[this, sub_compact](CompactionOutputs& outputs) {
return this->OpenCompactionOutputFile(sub_compact, outputs);
};
const Slice* start_user_key =
sub_compact->start.has_value() ? &boundaries.start_user_key : nullptr;
const Slice* end_user_key =
sub_compact->end.has_value() ? &boundaries.end_user_key : nullptr;
const CompactionFileCloseFunc close_file_func =
[this, sub_compact, start_user_key, end_user_key](
CompactionOutputs& outputs, const Status& status,
const Slice& next_table_min_key) {
return this->FinishCompactionOutputFile(status, sub_compact, outputs,
next_table_min_key,
start_user_key, end_user_key);
return this->FinishCompactionOutputFile(
status, sub_compact, outputs, next_table_min_key,
sub_compact->start.has_value() ? &start_user_key : nullptr,
sub_compact->end.has_value() ? &end_user_key : nullptr);
};
return {open_file_func, close_file_func};
}
Status CompactionJob::ProcessKeyValue(
SubcompactionState* sub_compact, ColumnFamilyData* cfd,
CompactionIterator* c_iter, const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func, uint64_t& prev_cpu_micros) {
Status status;
const uint64_t kRecordStatsEvery = 1000;
[[maybe_unused]] const std::optional<const Slice> end = sub_compact->end;
TEST_SYNC_POINT_CALLBACK(
"CompactionJob::ProcessKeyValueCompaction()::Processing",
static_cast<void*>(const_cast<Compaction*>(sub_compact->compaction)));
while (status.ok() && !cfd->IsDropped() && c_iter->Valid() &&
c_iter->status().ok()) {
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()
// returns true.
assert(!end.has_value() ||
cfd->user_comparator()->Compare(c_iter->user_key(), *end) < 0);
if (c_iter->iter_stats().num_input_records % kRecordStatsEvery ==
if (c_iter_stats.num_input_records % kRecordStatsEvery ==
kRecordStatsEvery - 1) {
UpdateSubcompactionJobStatsIncrementally(
c_iter, &sub_compact->compaction_job_stats,
db_options_.clock->CPUMicros(), prev_cpu_micros);
RecordDroppedKeys(c_iter_stats, &sub_compact->compaction_job_stats);
c_iter->ResetRecordCounts();
RecordCompactionIOStats();
uint64_t cur_cpu_micros = db_options_.clock->CPUMicros();
assert(cur_cpu_micros >= last_cpu_micros);
RecordTick(stats_, COMPACTION_CPU_TOTAL_TIME,
cur_cpu_micros - last_cpu_micros);
last_cpu_micros = cur_cpu_micros;
}
const auto& ikey = c_iter->ikey();
bool use_proximal_output = ikey.sequence > proximal_after_seqno_;
#ifndef NDEBUG
if (sub_compact->compaction->SupportsPerKeyPlacement()) {
// Could be overridden by unittest
PerKeyPlacementContext context(sub_compact->compaction->output_level(),
ikey.user_key, c_iter->value(),
ikey.sequence, use_proximal_output);
@@ -1501,6 +1505,9 @@ Status CompactionJob::ProcessKeyValue(
static_cast<void*>(const_cast<std::atomic<bool>*>(
&manual_compaction_canceled_)));
c_iter->Next();
if (c_iter->status().IsManualCompactionPaused()) {
break;
}
#ifndef NDEBUG
bool stop = false;
@@ -1512,33 +1519,13 @@ Status CompactionJob::ProcessKeyValue(
#endif // NDEBUG
}
return status;
}
void CompactionJob::UpdateSubcompactionJobStatsIncrementally(
CompactionIterator* c_iter, CompactionJobStats* compaction_job_stats,
uint64_t cur_cpu_micros, uint64_t& prev_cpu_micros) {
RecordDroppedKeys(c_iter->iter_stats(), compaction_job_stats);
c_iter->ResetRecordCounts();
RecordCompactionIOStats();
assert(cur_cpu_micros >= prev_cpu_micros);
RecordTick(stats_, COMPACTION_CPU_TOTAL_TIME,
cur_cpu_micros - prev_cpu_micros);
prev_cpu_micros = cur_cpu_micros;
}
void CompactionJob::FinalizeSubcompactionJobStats(
SubcompactionState* sub_compact, CompactionIterator* c_iter,
uint64_t start_cpu_micros, uint64_t prev_cpu_micros,
const CompactionIOStatsSnapshot& io_stats) {
const CompactionIterationStats& c_iter_stats = c_iter->iter_stats();
// This number may not be accurate when CompactionIterator was created
// with `must_count_input_entries=false`.
assert(!sub_compact->compaction->DoesInputReferenceBlobFiles() ||
c_iter->HasNumInputEntryScanned());
sub_compact->compaction_job_stats.has_accurate_num_input_records &=
sub_compact->compaction_job_stats.has_num_input_records =
c_iter->HasNumInputEntryScanned();
sub_compact->compaction_job_stats.num_input_records +=
sub_compact->compaction_job_stats.num_input_records =
c_iter->NumInputEntryScanned();
sub_compact->compaction_job_stats.num_blobs_read =
c_iter_stats.num_blobs_read;
@@ -1569,188 +1556,84 @@ void CompactionJob::FinalizeSubcompactionJobStats(
c_iter_stats.total_blob_bytes_relocated);
}
uint64_t cur_cpu_micros = db_options_.clock->CPUMicros();
RecordDroppedKeys(c_iter_stats, &sub_compact->compaction_job_stats);
RecordCompactionIOStats();
// Record final compaction statistics including dropped keys, I/O stats,
// and CPU time delta from the last periodic measurement
UpdateSubcompactionJobStatsIncrementally(c_iter,
&sub_compact->compaction_job_stats,
cur_cpu_micros, prev_cpu_micros);
// Finalize timing and I/O statistics
sub_compact->compaction_job_stats.cpu_micros =
cur_cpu_micros - start_cpu_micros + sub_compact->GetWorkerCPUMicros();
if (measure_io_stats_) {
sub_compact->compaction_job_stats.file_write_nanos +=
IOSTATS(write_nanos) - io_stats.prev_write_nanos;
sub_compact->compaction_job_stats.file_fsync_nanos +=
IOSTATS(fsync_nanos) - io_stats.prev_fsync_nanos;
sub_compact->compaction_job_stats.file_range_sync_nanos +=
IOSTATS(range_sync_nanos) - io_stats.prev_range_sync_nanos;
sub_compact->compaction_job_stats.file_prepare_write_nanos +=
IOSTATS(prepare_write_nanos) - io_stats.prev_prepare_write_nanos;
sub_compact->compaction_job_stats.cpu_micros -=
(IOSTATS(cpu_write_nanos) - io_stats.prev_cpu_write_nanos +
IOSTATS(cpu_read_nanos) - io_stats.prev_cpu_read_nanos) /
1000;
if (io_stats.prev_perf_level !=
PerfLevel::kEnableTimeAndCPUTimeExceptForMutex) {
SetPerfLevel(io_stats.prev_perf_level);
}
}
}
Status CompactionJob::FinalizeProcessKeyValueStatus(
ColumnFamilyData* cfd, InternalIterator* input_iter,
CompactionIterator* c_iter, Status status) {
if (status.ok() && cfd->IsDropped()) {
status =
Status::ColumnFamilyDropped("Column family dropped during compaction");
}
if (status.ok() && shutting_down_->load(std::memory_order_relaxed)) {
if ((status.ok() || status.IsColumnFamilyDropped()) &&
shutting_down_->load(std::memory_order_relaxed)) {
status = Status::ShutdownInProgress("Database shutdown");
}
if (status.ok() &&
if ((status.ok() || status.IsColumnFamilyDropped()) &&
(manual_compaction_canceled_.load(std::memory_order_relaxed))) {
status = Status::Incomplete(Status::SubCode::kManualCompactionPaused);
}
if (status.ok()) {
status = input_iter->status();
status = input->status();
}
if (status.ok()) {
status = c_iter->status();
}
return status;
}
Status CompactionJob::CleanupCompactionFiles(
SubcompactionState* sub_compact, Status status,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func) {
// Call FinishCompactionOutputFile() even if status is not ok: it needs to
// close the output files. Open file function is also passed, in case there's
// only range-dels, no file was opened, to save the range-dels, it need to
// create a new output file.
return sub_compact->CloseCompactionFiles(status, open_file_func,
close_file_func);
}
status = sub_compact->CloseCompactionFiles(status, open_file_func,
close_file_func);
Status CompactionJob::FinalizeBlobFiles(SubcompactionState* sub_compact,
BlobFileBuilder* blob_file_builder,
Status status) {
if (blob_file_builder) {
if (status.ok()) {
status = blob_file_builder->Finish();
} else {
blob_file_builder->Abandon(status);
}
blob_file_builder.reset();
sub_compact->Current().UpdateBlobStats();
}
return status;
}
uint64_t cur_cpu_micros = db_options_.clock->CPUMicros();
sub_compact->compaction_job_stats.cpu_micros =
cur_cpu_micros - prev_cpu_micros;
RecordTick(stats_, COMPACTION_CPU_TOTAL_TIME,
cur_cpu_micros - last_cpu_micros);
void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
assert(sub_compact);
assert(sub_compact->compaction);
if (!ShouldUseLocalCompaction(sub_compact)) {
return;
if (measure_io_stats_) {
sub_compact->compaction_job_stats.file_write_nanos +=
IOSTATS(write_nanos) - prev_write_nanos;
sub_compact->compaction_job_stats.file_fsync_nanos +=
IOSTATS(fsync_nanos) - prev_fsync_nanos;
sub_compact->compaction_job_stats.file_range_sync_nanos +=
IOSTATS(range_sync_nanos) - prev_range_sync_nanos;
sub_compact->compaction_job_stats.file_prepare_write_nanos +=
IOSTATS(prepare_write_nanos) - prev_prepare_write_nanos;
sub_compact->compaction_job_stats.cpu_micros -=
(IOSTATS(cpu_write_nanos) - prev_cpu_write_nanos +
IOSTATS(cpu_read_nanos) - prev_cpu_read_nanos) /
1000;
if (prev_perf_level != PerfLevel::kEnableTimeAndCPUTimeExceptForMutex) {
SetPerfLevel(prev_perf_level);
}
}
AutoThreadOperationStageUpdater stage_updater(
ThreadStatus::STAGE_COMPACTION_PROCESS_KV);
const uint64_t start_cpu_micros = db_options_.clock->CPUMicros();
uint64_t prev_cpu_micros = start_cpu_micros;
const CompactionIOStatsSnapshot io_stats = InitializeIOStats();
ColumnFamilyData* cfd = sub_compact->compaction->column_family_data();
const CompactionFilter* compaction_filter;
std::unique_ptr<CompactionFilter> compaction_filter_from_factory = nullptr;
Status filter_status = SetupAndValidateCompactionFilter(
sub_compact, cfd->ioptions().compaction_filter, compaction_filter,
compaction_filter_from_factory);
if (!filter_status.ok()) {
sub_compact->status = filter_status;
return;
}
NotifyOnSubcompactionBegin(sub_compact);
SubcompactionKeyBoundaries boundaries(sub_compact->start, sub_compact->end);
SubcompactionInternalIterators iterators;
ReadOptions read_options;
const WriteOptions write_options(Env::IOPriority::IO_LOW,
Env::IOActivity::kCompaction);
MergeHelper merge(
env_, cfd->user_comparator(), cfd->ioptions().merge_operator.get(),
compaction_filter, db_options_.info_log.get(),
false /* internal key corruption is expected */,
job_context_->GetLatestSnapshotSequence(), job_context_->snapshot_checker,
compact_->compaction->level(), db_options_.stats);
BlobFileResources blob_resources;
InternalIterator* input_iter = CreateInputIterator(
sub_compact, cfd, iterators, boundaries, read_options);
assert(input_iter);
input_iter->SeekToFirst();
auto c_iter =
CreateCompactionIterator(sub_compact, cfd, input_iter, compaction_filter,
merge, blob_resources, write_options);
assert(c_iter);
c_iter->SeekToFirst();
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_)));
auto [open_file_func, close_file_func] =
CreateFileHandlers(sub_compact, boundaries);
Status status =
ProcessKeyValue(sub_compact, cfd, c_iter.get(), open_file_func,
close_file_func, prev_cpu_micros);
status = FinalizeProcessKeyValueStatus(cfd, input_iter, c_iter.get(), status);
FinalizeSubcompaction(sub_compact, status, open_file_func, close_file_func,
blob_resources.blob_file_builder.get(), c_iter.get(),
input_iter, start_cpu_micros, prev_cpu_micros,
io_stats);
NotifyOnSubcompactionCompleted(sub_compact);
}
void CompactionJob::FinalizeSubcompaction(
SubcompactionState* sub_compact, Status status,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func,
BlobFileBuilder* blob_file_builder, CompactionIterator* c_iter,
[[maybe_unused]] InternalIterator* input_iter, uint64_t start_cpu_micros,
uint64_t prev_cpu_micros, const CompactionIOStatsSnapshot& io_stats) {
status = CleanupCompactionFiles(sub_compact, status, open_file_func,
close_file_func);
status = FinalizeBlobFiles(sub_compact, blob_file_builder, status);
FinalizeSubcompactionJobStats(sub_compact, c_iter, start_cpu_micros,
prev_cpu_micros, io_stats);
#ifdef ROCKSDB_ASSERT_STATUS_CHECKED
if (!status.ok()) {
if (c_iter) {
c_iter->status().PermitUncheckedError();
}
if (input_iter) {
input_iter->status().PermitUncheckedError();
if (input) {
input->status().PermitUncheckedError();
}
}
#endif // ROCKSDB_ASSERT_STATUS_CHECKED
blob_counter.reset();
clip.reset();
raw_input.reset();
sub_compact->status = status;
NotifyOnSubcompactionCompleted(sub_compact);
}
uint64_t CompactionJob::GetCompactionId(SubcompactionState* sub_compact) const {
@@ -2267,8 +2150,7 @@ void CopyPrefix(const Slice& src, size_t prefix_length, std::string* dst) {
}
} // namespace
bool CompactionJob::UpdateInternalStatsFromInputFiles(
uint64_t* num_input_range_del) {
bool CompactionJob::BuildStatsFromInputFiles(uint64_t* num_input_range_del) {
assert(compact_);
Compaction* compaction = compact_->compaction;
@@ -2350,7 +2232,7 @@ bool CompactionJob::UpdateInternalStatsFromInputFiles(
return !has_error;
}
void CompactionJob::UpdateCompactionJobInputStatsFromInternalStats(
void CompactionJob::UpdateCompactionJobInputStats(
const InternalStats::CompactionStatsFull& internal_stats,
uint64_t num_input_range_del) const {
assert(job_stats_);
@@ -2403,7 +2285,7 @@ void CompactionJob::UpdateCompactionJobInputStatsFromInternalStats(
}
}
void CompactionJob::UpdateCompactionJobOutputStatsFromInternalStats(
void CompactionJob::UpdateCompactionJobOutputStats(
const InternalStats::CompactionStatsFull& internal_stats) const {
assert(job_stats_);
job_stats_->elapsed_micros = internal_stats.output_level_stats.micros;
+4 -115
View File
@@ -196,7 +196,7 @@ class CompactionJob {
IOStatus io_status() const { return io_status_; }
protected:
void UpdateCompactionJobOutputStatsFromInternalStats(
void UpdateCompactionJobOutputStats(
const InternalStats::CompactionStatsFull& internal_stats) const;
void LogCompaction();
@@ -242,10 +242,9 @@ class CompactionJob {
// num_input_range_del are calculated successfully.
//
// This should be called only once for compactions (not per subcompaction)
bool UpdateInternalStatsFromInputFiles(
uint64_t* num_input_range_del = nullptr);
bool BuildStatsFromInputFiles(uint64_t* num_input_range_del = nullptr);
void UpdateCompactionJobInputStatsFromInternalStats(
void UpdateCompactionJobInputStats(
const InternalStats::CompactionStatsFull& internal_stats,
uint64_t num_input_range_del) const;
@@ -288,10 +287,7 @@ class CompactionJob {
Status SyncOutputDirectories();
Status VerifyOutputFiles();
void SetOutputTableProperties();
// Aggregates subcompaction output stats to internal stat, and aggregates
// subcompaction's compaction job stats to the whole entire surrounding
// compaction job stats.
void AggregateSubcompactionOutputAndJobStats();
void AggregateSubcompactionStats();
Status VerifyCompactionRecordCounts(bool stats_built_from_input_table_prop,
uint64_t num_input_range_del);
void FinalizeCompactionRun(const Status& status,
@@ -301,113 +297,6 @@ class CompactionJob {
CompactionServiceJobStatus ProcessKeyValueCompactionWithCompactionService(
SubcompactionState* sub_compact);
struct CompactionIOStatsSnapshot {
PerfLevel prev_perf_level = PerfLevel::kEnableTime;
uint64_t prev_write_nanos = 0;
uint64_t prev_fsync_nanos = 0;
uint64_t prev_range_sync_nanos = 0;
uint64_t prev_prepare_write_nanos = 0;
uint64_t prev_cpu_write_nanos = 0;
uint64_t prev_cpu_read_nanos = 0;
};
struct SubcompactionKeyBoundaries {
const std::optional<const Slice> start;
const std::optional<const Slice> end;
// Boundaries without timestamps for read options
std::optional<Slice> start_without_ts;
std::optional<Slice> end_without_ts;
// Timestamp management
static constexpr char kMaxTs[] =
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
std::string max_ts;
Slice ts_slice;
// Internal key boundaries
IterKey start_ikey;
IterKey end_ikey;
Slice start_internal_key;
Slice end_internal_key;
// User key boundaries
Slice start_user_key;
Slice end_user_key;
SubcompactionKeyBoundaries(std::optional<const Slice> start_boundary,
std::optional<const Slice> end_boundary)
: start(start_boundary), end(end_boundary) {}
};
struct SubcompactionInternalIterators {
std::unique_ptr<InternalIterator> raw_input;
std::unique_ptr<InternalIterator> clip;
std::unique_ptr<InternalIterator> blob_counter;
std::unique_ptr<InternalIterator> trim_history_iter;
};
struct BlobFileResources {
std::vector<std::string> blob_file_paths;
std::unique_ptr<BlobFileBuilder> blob_file_builder;
};
bool ShouldUseLocalCompaction(SubcompactionState* sub_compact);
CompactionIOStatsSnapshot InitializeIOStats();
Status SetupAndValidateCompactionFilter(
SubcompactionState* sub_compact,
const CompactionFilter* configured_compaction_filter,
const CompactionFilter*& compaction_filter,
std::unique_ptr<CompactionFilter>& compaction_filter_from_factory);
void InitializeReadOptions(ColumnFamilyData* cfd, ReadOptions& read_options,
SubcompactionKeyBoundaries& boundaries);
InternalIterator* CreateInputIterator(
SubcompactionState* sub_compact, ColumnFamilyData* cfd,
SubcompactionInternalIterators& iterators,
SubcompactionKeyBoundaries& boundaries, ReadOptions& read_options);
void CreateBlobFileBuilder(SubcompactionState* sub_compact,
ColumnFamilyData* cfd,
BlobFileResources& blob_resources,
const WriteOptions& write_options);
std::unique_ptr<CompactionIterator> CreateCompactionIterator(
SubcompactionState* sub_compact, ColumnFamilyData* cfd,
InternalIterator* input_iter, const CompactionFilter* compaction_filter,
MergeHelper& merge, BlobFileResources& blob_resources,
const WriteOptions& write_options);
std::pair<CompactionFileOpenFunc, CompactionFileCloseFunc> CreateFileHandlers(
SubcompactionState* sub_compact, SubcompactionKeyBoundaries& boundaries);
Status ProcessKeyValue(SubcompactionState* sub_compact, ColumnFamilyData* cfd,
CompactionIterator* c_iter,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func,
uint64_t& prev_cpu_micros);
void UpdateSubcompactionJobStatsIncrementally(
CompactionIterator* c_iter, CompactionJobStats* compaction_job_stats,
uint64_t cur_cpu_micros, uint64_t& prev_cpu_micros);
void FinalizeSubcompactionJobStats(SubcompactionState* sub_compact,
CompactionIterator* c_iter,
uint64_t start_cpu_micros,
uint64_t prev_cpu_micros,
const CompactionIOStatsSnapshot& io_stats);
Status FinalizeProcessKeyValueStatus(ColumnFamilyData* cfd,
InternalIterator* input_iter,
CompactionIterator* c_iter,
Status status);
Status CleanupCompactionFiles(SubcompactionState* sub_compact, Status status,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func);
Status FinalizeBlobFiles(SubcompactionState* sub_compact,
BlobFileBuilder* blob_file_builder, Status status);
void FinalizeSubcompaction(SubcompactionState* sub_compact, Status status,
const CompactionFileOpenFunc& open_file_func,
const CompactionFileCloseFunc& close_file_func,
BlobFileBuilder* blob_file_builder,
CompactionIterator* c_iter,
InternalIterator* input_iter,
uint64_t start_cpu_micros,
uint64_t prev_cpu_micros,
const CompactionIOStatsSnapshot& io_stats);
// update the thread status for starting a compaction.
void ReportStartedCompaction(Compaction* compaction);
-1
View File
@@ -56,7 +56,6 @@ Status CompactionOutputs::Finish(
stats_.bytes_written += current_bytes;
stats_.bytes_written_pre_comp += builder_->PreCompressionSize();
stats_.num_output_files = static_cast<int>(outputs_.size());
worker_cpu_micros_ += builder_->GetWorkerCPUMicros();
return s;
}
-7
View File
@@ -168,10 +168,6 @@ class CompactionOutputs {
uint64_t NumEntries() const { return builder_->NumEntries(); }
uint64_t GetWorkerCPUMicros() const {
return worker_cpu_micros_ + (builder_ ? builder_->GetWorkerCPUMicros() : 0);
}
void ResetBuilder() {
builder_.reset();
current_output_file_size_ = 0;
@@ -300,9 +296,6 @@ class CompactionOutputs {
uint64_t current_output_file_size_ = 0;
SequenceNumber smallest_preferred_seqno_ = kMaxSequenceNumber;
// Sum of all the GetWorkerCPUMicros() for all the closed builders so far.
uint64_t worker_cpu_micros_ = 0;
// all the compaction outputs so far
std::vector<Output> outputs_;
+6 -8
View File
@@ -390,14 +390,12 @@ Compaction* FIFOCompactionPicker::PickTemperatureChangeCompaction(
assert(compaction_target_temp == Temperature::kLastTemperature);
compaction_target_temp = cur_target_temp;
inputs[0].files.push_back(cur_file);
ROCKS_LOG_BUFFER(log_buffer,
"[%s] FIFO compaction: picking file %" PRIu64
" with estimated newest key time %" PRIu64
" and temperature %s for temperature %s.",
cf_name.c_str(), cur_file->fd.GetNumber(),
est_newest_key_time,
temperature_to_string[cur_file->temperature].c_str(),
temperature_to_string[cur_target_temp].c_str());
ROCKS_LOG_BUFFER(
log_buffer,
"[%s] FIFO compaction: picking file %" PRIu64
" with estimated newest key time %" PRIu64 " for temperature %s.",
cf_name.c_str(), cur_file->fd.GetNumber(), est_newest_key_time,
temperature_to_string[cur_target_temp].c_str());
break;
}
}
+1 -1
View File
@@ -408,7 +408,7 @@ Status CompactionServiceCompactionJob::Run() {
// 2. Update job-level output stats with the aggregated internal_stats_
// Please note that input stats will be updated by primary host when all
// subcompactions are finished
UpdateCompactionJobOutputStatsFromInternalStats(internal_stats_);
UpdateCompactionJobOutputStats(internal_stats_);
// and set fields that are not propagated as part of the update
compaction_result_->stats.is_manual_compaction = c->is_manual_compaction();
compaction_result_->stats.is_full_compaction = c->is_full_compaction();
-8
View File
@@ -191,14 +191,6 @@ class SubcompactionState {
return &compaction_outputs_.stats_;
}
uint64_t GetWorkerCPUMicros() const {
uint64_t rv = compaction_outputs_.GetWorkerCPUMicros();
if (compaction->SupportsPerKeyPlacement()) {
rv += proximal_level_outputs_.GetWorkerCPUMicros();
}
return rv;
}
CompactionRangeDelAggregator* RangeDelAgg() const {
return range_del_agg_.get();
}
+3 -16
View File
@@ -1764,10 +1764,7 @@ TEST_P(PrecludeLastLevelTest, SmallPrecludeTime) {
options.env = mock_env_.get();
options.level0_file_num_compaction_trigger = kNumTrigger;
options.num_levels = kNumLevels;
// This existing test selected to also check the case of various temperatures
// for last_level_temperature, which should not be interesting enough to
// exercise across many/all test cases
options.last_level_temperature = RandomKnownTemperature();
options.last_level_temperature = Temperature::kCold;
DestroyAndReopen(options);
Random rnd(301);
@@ -1794,10 +1791,6 @@ TEST_P(PrecludeLastLevelTest, SmallPrecludeTime) {
ASSERT_FALSE(tp_mapping.Empty());
auto seqs = tp_mapping.TEST_GetInternalMapping();
ASSERT_FALSE(seqs.empty());
ASSERT_GE(GetSstSizeHelper(Temperature::kUnknown), 1);
for (auto t : kKnownTemperatures) {
ASSERT_EQ(GetSstSizeHelper(t), 0);
}
// Wait more than preclude_last_level time, then make sure all the data is
// compacted to the last level even there's no write (no seqno -> time
@@ -1806,14 +1799,8 @@ TEST_P(PrecludeLastLevelTest, SmallPrecludeTime) {
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
ASSERT_EQ("0,0,0,0,0,0,1", FilesPerLevel());
for (auto t : kKnownTemperatures) {
if (t == options.last_level_temperature) {
ASSERT_GT(GetSstSizeHelper(t), 0);
} else {
ASSERT_EQ(GetSstSizeHelper(t), 0);
}
}
ASSERT_EQ(GetSstSizeHelper(Temperature::kUnknown), 0);
ASSERT_GT(GetSstSizeHelper(Temperature::kCold), 0);
Close();
}
-1
View File
@@ -5087,7 +5087,6 @@ TEST_F(DBBasicTest, DisallowMemtableWrite) {
Options options_disallow = options_allow;
options_disallow.disallow_memtable_writes = true;
options_disallow.paranoid_memory_checks = true;
options_disallow.memtable_veirfy_per_key_checksum_on_seek = true;
DestroyAndReopen(options_allow);
// CFs allowing and disallowing memtable write
-259
View File
@@ -19,7 +19,6 @@
#include "rocksdb/advanced_options.h"
#include "rocksdb/concurrent_task_limiter.h"
#include "rocksdb/experimental.h"
#include "rocksdb/iostats_context.h"
#include "rocksdb/sst_file_writer.h"
#include "test_util/mock_time_env.h"
#include "test_util/sync_point.h"
@@ -9792,7 +9791,6 @@ TEST_F(DBCompactionTest, FIFOChangeTemperature) {
int total_cold = 0;
int total_warm = 0;
int total_hot = 0;
int total_ice = 0;
int total_unknown = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"NewWritableFile::FileOptions.temperature", [&](void* arg) {
@@ -9803,8 +9801,6 @@ TEST_F(DBCompactionTest, FIFOChangeTemperature) {
total_warm++;
} else if (temperature == Temperature::kHot) {
total_hot++;
} else if (temperature == Temperature::kIce) {
total_ice++;
} else {
assert(temperature == Temperature::kUnknown);
total_unknown++;
@@ -9878,261 +9874,6 @@ TEST_F(DBCompactionTest, FIFOChangeTemperature) {
}
}
using TemperatureSet = SmallEnumSet<Temperature, Temperature::kLastTemperature>;
static void VerifyTemperatureFileReadStats(const Statistics& st,
TemperatureSet temps) {
SCOPED_TRACE("Temp set size = " + std::to_string(temps.count()));
constexpr uint64_t min_bytes = 100;
constexpr uint64_t min_count = 1;
IOStatsContext* iostats = get_iostats_context();
if (temps.Contains(Temperature::kHot)) {
EXPECT_GE(st.getTickerCount(HOT_FILE_READ_BYTES), min_bytes);
EXPECT_GE(st.getTickerCount(HOT_FILE_READ_COUNT), min_count);
EXPECT_GE(iostats->file_io_stats_by_temperature.hot_file_bytes_read,
min_bytes);
EXPECT_GE(iostats->file_io_stats_by_temperature.hot_file_read_count,
min_count);
} else {
EXPECT_EQ(st.getTickerCount(HOT_FILE_READ_BYTES), 0);
EXPECT_EQ(st.getTickerCount(HOT_FILE_READ_COUNT), 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.hot_file_bytes_read, 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.hot_file_read_count, 0);
}
if (temps.Contains(Temperature::kWarm)) {
EXPECT_GE(st.getTickerCount(WARM_FILE_READ_BYTES), min_bytes);
EXPECT_GE(st.getTickerCount(WARM_FILE_READ_COUNT), min_count);
EXPECT_GE(iostats->file_io_stats_by_temperature.warm_file_bytes_read,
min_bytes);
EXPECT_GE(iostats->file_io_stats_by_temperature.warm_file_read_count,
min_count);
} else {
EXPECT_EQ(st.getTickerCount(WARM_FILE_READ_BYTES), 0);
EXPECT_EQ(st.getTickerCount(WARM_FILE_READ_COUNT), 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.warm_file_bytes_read, 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.warm_file_read_count, 0);
}
if (temps.Contains(Temperature::kCool)) {
EXPECT_GE(st.getTickerCount(COOL_FILE_READ_BYTES), min_bytes);
EXPECT_GE(st.getTickerCount(COOL_FILE_READ_COUNT), min_count);
EXPECT_GE(iostats->file_io_stats_by_temperature.cool_file_bytes_read,
min_bytes);
EXPECT_GE(iostats->file_io_stats_by_temperature.cool_file_read_count,
min_count);
} else {
EXPECT_EQ(st.getTickerCount(COOL_FILE_READ_BYTES), 0);
EXPECT_EQ(st.getTickerCount(COOL_FILE_READ_COUNT), 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.cool_file_bytes_read, 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.cool_file_read_count, 0);
}
if (temps.Contains(Temperature::kCold)) {
EXPECT_GE(st.getTickerCount(COLD_FILE_READ_BYTES), min_bytes);
EXPECT_GE(st.getTickerCount(COLD_FILE_READ_COUNT), min_count);
EXPECT_GE(iostats->file_io_stats_by_temperature.cold_file_bytes_read,
min_bytes);
EXPECT_GE(iostats->file_io_stats_by_temperature.cold_file_read_count,
min_count);
} else {
EXPECT_EQ(st.getTickerCount(COLD_FILE_READ_BYTES), 0);
EXPECT_EQ(st.getTickerCount(COLD_FILE_READ_COUNT), 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.cold_file_bytes_read, 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.cold_file_read_count, 0);
}
if (temps.Contains(Temperature::kIce)) {
EXPECT_GE(st.getTickerCount(ICE_FILE_READ_BYTES), min_bytes);
EXPECT_GE(st.getTickerCount(ICE_FILE_READ_COUNT), min_count);
EXPECT_GE(iostats->file_io_stats_by_temperature.ice_file_bytes_read,
min_bytes);
EXPECT_GE(iostats->file_io_stats_by_temperature.ice_file_read_count,
min_count);
} else {
EXPECT_EQ(st.getTickerCount(ICE_FILE_READ_BYTES), 0);
EXPECT_EQ(st.getTickerCount(ICE_FILE_READ_COUNT), 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.ice_file_bytes_read, 0);
EXPECT_EQ(iostats->file_io_stats_by_temperature.ice_file_read_count, 0);
}
}
TEST_F(DBCompactionTest, FIFOMultiTierTemperatureAging) {
// Test multi-tier aging: Hot -> Warm -> Cool -> Cold -> Ice
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleFIFO;
options.num_levels = 1;
options.max_open_files = -1;
options.level0_file_num_compaction_trigger = 2;
options.create_if_missing = true;
options.statistics = CreateDBStatistics();
BlockBasedTableOptions bbto;
bbto.no_block_cache = true; // Simplify statistics
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
CompactionOptionsFIFO fifo_options;
// Multi-tier aging: files age through multiple temperatures
fifo_options.file_temperature_age_thresholds = {
{Temperature::kWarm, 500}, // Hot -> Warm after 500s
{Temperature::kCool, 1000}, // Warm -> Cool
{Temperature::kCold, 1500}, // Cool -> Cold
{Temperature::kIce, 2000} // Cold -> Ice
};
fifo_options.max_table_files_size = 100000000;
fifo_options.allow_trivial_copy_when_change_temperature = true;
options.compaction_options_fifo = fifo_options;
options.default_write_temperature = Temperature::kHot;
Reopen(options);
env_->SetMockSleep();
// Track all temperature file creations
int total_hot = 0, total_warm = 0, total_cool = 0, total_cold = 0,
total_ice = 0, total_unknown = 0;
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"NewWritableFile::FileOptions.temperature", [&](void* arg) {
Temperature temperature = *(static_cast<Temperature*>(arg));
switch (temperature) {
case Temperature::kHot:
total_hot++;
break;
case Temperature::kWarm:
total_warm++;
break;
case Temperature::kCool:
total_cool++;
break;
case Temperature::kCold:
total_cold++;
break;
case Temperature::kIce:
total_ice++;
break;
case Temperature::kUnknown:
total_unknown++;
break;
default:
break;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
// Create initial three files (will start as Hot), enough to ensure key
// range filtering will be applied in FilePicker::GetNextFile() with one
// more file
for (int i = 0; i < 3; ++i) {
ASSERT_OK(Put(Key(0), Random::GetTLSInstance()->RandomBinaryString(100)));
ASSERT_OK(Flush());
}
// Test reading from Hot temperature file
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
ASSERT_EQ(100U, Get(Key(0)).size());
VerifyTemperatureFileReadStats(*options.statistics, Temperature::kHot);
// Land well into each time interval
env_->MockSleepForSeconds(100);
// Age initial files to warm
env_->MockSleepForSeconds(500);
ASSERT_OK(Put(Key(1), Random::GetTLSInstance()->RandomBinaryString(101)));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// Test reading from Warm temperature file (the aged file)
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
ASSERT_EQ(100U, Get(Key(0)).size());
// Verify Warm file statistics
VerifyTemperatureFileReadStats(*options.statistics, Temperature::kWarm);
// Age initial files to cool
env_->MockSleepForSeconds(500);
ASSERT_OK(Put(Key(2), Random::GetTLSInstance()->RandomBinaryString(102)));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// Test reading from Cool temperature file (the aged file)
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
ASSERT_EQ(100U, Get(Key(0)).size());
VerifyTemperatureFileReadStats(*options.statistics, Temperature::kCool);
// Age initial files to cold
env_->MockSleepForSeconds(500);
ASSERT_OK(Put(Key(3), Random::GetTLSInstance()->RandomBinaryString(103)));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// Test reading from Cold temperature file (the aged file)
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
ASSERT_EQ(100U, Get(Key(0)).size());
VerifyTemperatureFileReadStats(*options.statistics, Temperature::kCold);
// Age initial files to ice
env_->MockSleepForSeconds(500);
ASSERT_OK(Put(Key(4), Random::GetTLSInstance()->RandomBinaryString(104)));
ASSERT_OK(Flush());
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// Test reading from Ice temperature file (the aged file)
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
ASSERT_EQ(100U, Get(Key(0)).size());
VerifyTemperatureFileReadStats(*options.statistics, Temperature::kIce);
// Verify temperature progression in metadata
ColumnFamilyMetaData metadata;
db_->GetColumnFamilyMetaData(&metadata);
// Should have files at different temperatures
std::map<Temperature, int> temp_counts;
for (const auto& file : metadata.levels[0].files) {
temp_counts[file.temperature]++;
}
// Verify current files temperatures
EXPECT_EQ(temp_counts[Temperature::kHot], 1);
EXPECT_EQ(temp_counts[Temperature::kWarm], 1);
EXPECT_EQ(temp_counts[Temperature::kCool], 1);
EXPECT_EQ(temp_counts[Temperature::kCold], 1);
EXPECT_EQ(temp_counts[Temperature::kIce], 3);
// Verify historical (and current) file temperatures
EXPECT_EQ(total_hot, 7);
EXPECT_EQ(total_warm, 6);
EXPECT_EQ(total_cool, 5);
EXPECT_EQ(total_cold, 4);
EXPECT_EQ(total_ice, 3);
// Final comprehensive test: read from all temperature files
Reopen(options);
ASSERT_OK(options.statistics->Reset());
get_iostats_context()->Reset();
// Read from all files to verify cumulative statistics
for (int i = 0; i < 5; i++) {
ASSERT_EQ(static_cast<unsigned>(100 + i), Get(Key(i)).size());
}
VerifyTemperatureFileReadStats(*options.statistics, TemperatureSet::All());
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
}
TEST_F(DBCompactionTest, DisableMultiManualCompaction) {
const int kNumL0Files = 10;
+3 -1
View File
@@ -1069,7 +1069,7 @@ void DBImpl::DumpStats() {
{
InstrumentedMutexLock l(&mutex_);
for (auto cfd : versions_->GetRefedColumnFamilySet()) {
if (!cfd->initialized() || cfd->IsDropped()) {
if (!cfd->initialized()) {
continue;
}
@@ -1245,11 +1245,13 @@ Status DBImpl::SetOptions(
WriteOptionsFile(write_options, true /*db_mutex_already_held*/);
bg_cv_.SignalAll();
#if __cplusplus >= 202002L
assert(new_options_copy == cfd->GetLatestMutableCFOptions());
assert(cfd->GetLatestMutableCFOptions() ==
cfd->GetCurrentMutableCFOptions());
assert(cfd->GetCurrentMutableCFOptions() ==
cfd->current()->GetMutableCFOptions());
#endif
}
}
sv_context.Clean();
-104
View File
@@ -1565,115 +1565,11 @@ void DBIter::SetSavedKeyToSeekForPrevTarget(const Slice& target) {
}
}
Status DBIter::ValidateScanOptions(const MultiScanArgs& multiscan_opts) const {
if (multiscan_opts.empty()) {
return Status::InvalidArgument("Empty MultiScanArgs");
}
const std::vector<ScanOptions>& scan_opts = multiscan_opts.GetScanRanges();
const bool has_limit = scan_opts.front().range.limit.has_value();
if (!has_limit && scan_opts.size() > 1) {
return Status::InvalidArgument("Scan has no upper bound");
}
for (size_t i = 0; i < scan_opts.size(); ++i) {
const auto& scan_range = scan_opts[i].range;
if (!scan_range.start.has_value()) {
return Status::InvalidArgument("Scan has no start key at index " +
std::to_string(i));
}
if (scan_range.limit.has_value()) {
if (user_comparator_.CompareWithoutTimestamp(
scan_range.start.value(), /*a_has_ts=*/false,
scan_range.limit.value(), /*b_has_ts=*/false) >= 0) {
return Status::InvalidArgument(
"Scan start key is large or equal than limit at index " +
std::to_string(i));
}
}
if (i > 0) {
if (!scan_range.limit.has_value()) {
// multiple scan without limit scan ranges
return Status::InvalidArgument("Scan has no upper bound at index " +
std::to_string(i));
}
const auto& last_end_key = scan_opts[i - 1].range.limit.value();
if (user_comparator_.CompareWithoutTimestamp(
scan_range.start.value(), /*a_has_ts=*/false, last_end_key,
/*b_has_ts=*/false) < 0) {
return Status::InvalidArgument("Overlapping ranges at index " +
std::to_string(i));
}
}
}
return Status::OK();
}
void DBIter::Prepare(const MultiScanArgs& scan_opts) {
status_ = ValidateScanOptions(scan_opts);
if (!status_.ok()) {
return;
}
std::optional<MultiScanArgs> new_scan_opts;
new_scan_opts.emplace(scan_opts);
scan_opts_.swap(new_scan_opts);
scan_index_ = 0;
if (!scan_opts.empty()) {
iter_.Prepare(&scan_opts_.value());
} else {
iter_.Prepare(nullptr);
}
}
void DBIter::Seek(const Slice& target) {
PERF_COUNTER_ADD(iter_seek_count, 1);
PERF_CPU_TIMER_GUARD(iter_seek_cpu_nanos, clock_);
StopWatch sw(clock_, statistics_, DB_SEEK);
if (scan_opts_.has_value()) {
// Validate the seek target is as expected in the previously prepared range
auto const& scan_ranges = scan_opts_.value().GetScanRanges();
if (scan_index_ >= scan_ranges.size()) {
status_ = Status::InvalidArgument(
"Seek called after exhausting all of the scan ranges");
valid_ = false;
return;
}
// Validate start key of next prepare range matches the seek target
auto const& range = scan_ranges[scan_index_];
auto const& start = range.range.start;
assert(start.has_value());
if (user_comparator_.CompareWithoutTimestamp(target, *start) != 0) {
status_ = Status::InvalidArgument(
"Seek target does not match the start of the next prepared range at "
"index " +
std::to_string(scan_index_));
valid_ = false;
return;
}
// validate the upper bound is set to the same value of limit, if limit
// exists
auto const& limit = range.range.limit;
if (limit.has_value()) {
if (iterate_upper_bound_ == nullptr ||
user_comparator_.CompareWithoutTimestamp(
limit.value(), *iterate_upper_bound_) != 0) {
status_ = Status::InvalidArgument(
"Upper bound is not set to the same limit value of the next "
"prepared range at index " +
std::to_string(scan_index_));
valid_ = false;
return;
}
}
scan_index_++;
}
if (cfh_ != nullptr) {
// TODO: What do we do if this returns an error?
Slice lower_bound, upper_bound;
+10 -3
View File
@@ -240,8 +240,16 @@ class DBIter final : public Iterator {
bool PrepareValue() override;
void Prepare(const MultiScanArgs& scan_opts) override;
Status ValidateScanOptions(const MultiScanArgs& multiscan_opts) const;
void Prepare(const MultiScanArgs& scan_opts) override {
std::optional<MultiScanArgs> new_scan_opts;
new_scan_opts.emplace(scan_opts);
scan_opts_.swap(new_scan_opts);
if (!scan_opts.empty()) {
iter_.Prepare(&scan_opts_.value());
} else {
iter_.Prepare(nullptr);
}
}
private:
DBIter(Env* _env, const ReadOptions& read_options,
@@ -498,7 +506,6 @@ class DBIter final : public Iterator {
const size_t timestamp_size_;
std::string saved_timestamp_;
std::optional<MultiScanArgs> scan_opts_;
size_t scan_index_{0};
ReadOnlyMemTable* const active_mem_;
SequenceNumber memtable_seqno_lb_;
uint32_t memtable_op_scan_flush_trigger_;
+66 -289
View File
@@ -4149,7 +4149,6 @@ class DBMultiScanIteratorTest : public DBTestBase,
: DBTestBase("db_multi_scan_iterator_test", /*env_do_fsync=*/true) {}
};
// Param 0: ReadOptions::fill_cache
INSTANTIATE_TEST_CASE_P(DBMultiScanIteratorTest, DBMultiScanIteratorTest,
::testing::Bool());
@@ -4193,6 +4192,66 @@ TEST_P(DBMultiScanIteratorTest, BasicTest) {
abort();
}
iter.reset();
// Test the overlapping scan case
key_ranges[1] = "k30";
scan_options = MultiScanArgs(BytewiseComparator());
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
int idx = 0;
int count = 0;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString().compare(key_ranges[idx]), 0);
ASSERT_LT(it.first.ToString().compare(key_ranges[idx + 1]), 0);
count++;
}
idx += 2;
}
ASSERT_EQ(count, 52);
} catch (MultiScanException& ex) {
// Make sure exception contains the status
ASSERT_NOK(ex.status());
std::cerr << "Iterator returned status " << ex.what();
abort();
} catch (std::logic_error& ex) {
std::cerr << "Iterator returned logic error " << ex.what();
abort();
}
iter.reset();
// Test the no limit scan case
scan_options = MultiScanArgs(BytewiseComparator());
scan_options.insert(key_ranges[0]);
scan_options.insert(key_ranges[2]);
iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
int idx = 0;
int count = 0;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString().compare(key_ranges[idx]), 0);
if (it.first.ToString().compare(key_ranges[idx + 1]) == 0) {
break;
}
count++;
}
idx += 2;
}
ASSERT_EQ(count, 52);
} catch (MultiScanException& ex) {
// Make sure exception contains the status
ASSERT_NOK(ex.status());
std::cerr << "Iterator returned status " << ex.what();
abort();
} catch (std::logic_error& ex) {
std::cerr << "Iterator returned logic error " << ex.what();
abort();
}
iter.reset();
}
TEST_P(DBMultiScanIteratorTest, MixedBoundsTest) {
@@ -4307,297 +4366,15 @@ TEST_P(DBMultiScanIteratorTest, RangeAcrossFiles) {
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
std::unique_ptr<MultiScan> iter =
dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
int i = 10;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_EQ(it.first.ToString(), Key(i));
++i;
}
int i = 10;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_EQ(it.first.ToString(), Key(i));
++i;
}
ASSERT_EQ(i, 90);
} catch (MultiScanException& ex) {
// Make sure exception contains the status
ASSERT_NOK(ex.status());
std::cerr << "Iterator returned status " << ex.what();
abort();
} catch (std::logic_error& ex) {
std::cerr << "Iterator returned logic error " << ex.what();
abort();
}
iter.reset();
ASSERT_EQ(i, 90);
}
TEST_P(DBMultiScanIteratorTest, FailureTest) {
auto options = CurrentOptions();
options.compression = kNoCompression;
DestroyAndReopen(options);
Random rnd(301);
// Create a file
for (int i = 0; i < 100; ++i) {
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << i;
ASSERT_OK(Put("k" + ss.str(), rnd.RandomString(1024)));
}
ASSERT_OK(Flush());
std::vector<std::string> key_ranges({"k04", "k06", "k12", "k14"});
ReadOptions ro;
Slice ub;
ro.iterate_upper_bound = &ub;
ro.fill_cache = GetParam();
MultiScanArgs scan_options(BytewiseComparator());
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
scan_options.max_prefetch_size = 4500;
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
std::unique_ptr<Iterator> iter(dbfull()->NewIterator(ro, cfh));
ASSERT_NE(iter, nullptr);
iter->Prepare(scan_options);
int count = 0;
ub = key_ranges[1];
iter->Seek(key_ranges[0]);
while (iter->status().ok() && iter->Valid()) {
ASSERT_GE(iter->key().compare(key_ranges[0]), 0);
ASSERT_LT(iter->key().compare(key_ranges[1]), 0);
count++;
iter->Next();
}
ASSERT_OK(iter->status()) << iter->status().ToString();
ASSERT_EQ(count, 2);
// Second seek should hit the max_prefetch_size limit
ub = key_ranges[3];
iter->Seek(key_ranges[2]);
ASSERT_NOK(iter->status());
iter.reset();
// Test the case of unexpected Seek key
iter.reset(dbfull()->NewIterator(ro, cfh));
ASSERT_NE(iter, nullptr);
scan_options.max_prefetch_size = 0;
iter->Prepare(scan_options);
ub = key_ranges[3];
iter->Seek(key_ranges[2]);
ASSERT_NOK(iter->status());
iter.reset();
}
TEST_P(DBMultiScanIteratorTest, RangeBetweenFiles) {
auto options = CurrentOptions();
options.target_file_size_base = 100 << 10; // 20KB
options.compaction_style = kCompactionStyleUniversal;
options.num_levels = 50;
options.compression = kNoCompression;
DestroyAndReopen(options);
auto rnd = Random::GetTLSInstance();
// Write ~200KB data
for (int i = 0; i < 100; ++i) {
ASSERT_OK(Put(Key(i), rnd->RandomString(2 << 10)));
}
ASSERT_OK(Flush());
ASSERT_OK(db_->CompactRange({}, nullptr, nullptr));
ASSERT_EQ(2, NumTableFilesAtLevel(49));
// Test with a scan range that overlaps an entire file, with upper bound
// between 2 files
std::vector<LiveFileMetaData> file_meta;
dbfull()->GetLiveFilesMetaData(&file_meta);
ASSERT_EQ(file_meta.size(), 2);
std::vector<std::string> key_ranges(4);
key_ranges[0] = file_meta[0].smallestkey;
key_ranges[1] = file_meta[0].largestkey + "0";
key_ranges[2] = file_meta[1].smallestkey + "0";
key_ranges[3] = file_meta[1].largestkey;
ReadOptions ro;
ro.fill_cache = GetParam();
MultiScanArgs scan_options(BytewiseComparator());
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
std::unique_ptr<MultiScan> iter =
dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString(), key_ranges[0]);
}
}
} catch (MultiScanException& ex) {
// Make sure exception contains the status
ASSERT_NOK(ex.status());
std::cerr << "Iterator returned status " << ex.what();
abort();
} catch (std::logic_error& ex) {
std::cerr << "Iterator returned logic error " << ex.what();
abort();
}
iter.reset();
// Test multiscan with a range entirely between adjacent files
key_ranges[0] = file_meta[0].largestkey + "0";
key_ranges[1] = file_meta[0].largestkey + "1";
key_ranges[2] = file_meta[1].smallestkey + "0";
key_ranges[3] = file_meta[1].largestkey;
(*scan_options).clear();
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString(), key_ranges[0]);
}
}
} catch (MultiScanException& ex) {
// Make sure exception contains the status
ASSERT_NOK(ex.status());
std::cerr << "Iterator returned status " << ex.what();
abort();
} catch (std::logic_error& ex) {
std::cerr << "Iterator returned logic error " << ex.what();
abort();
}
iter.reset();
}
// This test case tests multiscan in the presence of fragmented range
// tombstones in the LSM.
TEST_P(DBMultiScanIteratorTest, FragmentedRangeTombstones) {
auto options = CurrentOptions();
// Compaction may create files 2x the target_file_size_base,
// so set this to 50KB so we atleast end up with 2 files of
// 100KB
options.target_file_size_base = 50 << 10; // 50KB
options.compaction_style = kCompactionStyleUniversal;
options.num_levels = 50;
options.compression = kNoCompression;
DestroyAndReopen(options);
// Setup the LSM as follows -
// 1. Ingest a file with 100 keys
// 2. Ingest a file with one overlapping key
// 3. Do a Put and flush a file to L0 with one overlapping key
// 4. Ingest a standalone delete range file that covers the full key space
// and a file with the same 100 keys with new values. This will ingest
// into L0 due to the presence of an existing file in L0
// The final LSM will have an SST in Lmax with 100 keys, and 2 SST files
// in Lmax-1 with half the keys each and completely overlapping delete ranges
std::unordered_map<std::string, std::string> kvs;
auto rnd = Random::GetTLSInstance();
auto create_ingestion_data_file_and_update_key_value =
[&](const std::string& filename, int start_key, int end_key) {
std::unique_ptr<SstFileWriter> writer;
writer.reset(new SstFileWriter(EnvOptions(), options));
ASSERT_OK(writer->Open(filename));
for (int i = start_key; i < end_key; ++i) {
auto kiter = kvs.find(Key(i));
if (kiter != kvs.end()) {
kvs.erase(kiter);
}
auto res =
kvs.emplace(std::make_pair(Key(i), rnd->RandomString(2 << 10)));
ASSERT_OK(writer->Put(res.first->first, res.first->second));
}
ASSERT_OK(writer->Finish());
writer.reset();
};
CreateColumnFamilies({"new_cf"}, options);
std::string ingest_file = dbname_ + "test.sst";
// Write ~200KB data
create_ingestion_data_file_and_update_key_value(ingest_file + "_0", 0, 100);
create_ingestion_data_file_and_update_key_value(ingest_file + "_1", 50, 51);
ColumnFamilyHandle* cfh = handles_[0];
IngestExternalFileOptions ifo;
Status s = dbfull()->IngestExternalFile(
cfh, {ingest_file + "_0", ingest_file + "_1"}, ifo);
ASSERT_OK(s);
ASSERT_OK(Put(0, Key(50), rnd->RandomString(2 << 10)));
ASSERT_OK(Flush());
{
std::unique_ptr<SstFileWriter> writer;
writer.reset(new SstFileWriter(EnvOptions(), options));
ASSERT_OK(writer->Open(ingest_file + "_2"));
ASSERT_OK(writer->DeleteRange("a", "z"));
ASSERT_OK(writer->Finish());
writer.reset();
}
create_ingestion_data_file_and_update_key_value(ingest_file + "_3", 0, 100);
s = dbfull()->IngestExternalFile(
cfh, {ingest_file + "_2", ingest_file + "_3"}, ifo);
ASSERT_OK(s);
ASSERT_OK(dbfull()->TEST_WaitForCompact());
// The first scan range overlaps the DB key range, while the second extends
// beyond but overlaps the delete range
std::vector<std::string> key_ranges({"key000085", "key000090", "l", "n"});
ReadOptions ro;
ro.fill_cache = GetParam();
MultiScanArgs scan_options(BytewiseComparator());
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
std::unique_ptr<MultiScan> iter =
dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
int i = 0;
int count = 0;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString(), key_ranges[i]);
ASSERT_LT(it.first.ToString(), key_ranges[i + 1]);
auto kiter = kvs.find(it.first.ToString());
ASSERT_NE(kiter, kvs.end());
ASSERT_EQ(kiter->second, it.second.ToString());
count++;
}
i += 2;
}
ASSERT_EQ(i, 4);
ASSERT_EQ(count, 5);
} catch (MultiScanException& ex) {
ASSERT_OK(ex.status());
}
iter.reset();
// The second scan range start overlaps the delete range in the first file
// in Lmax-1, while the end overlaps the keys in the second file
(*scan_options).clear();
key_ranges[0] = "key000010";
key_ranges[1] = "key000020";
key_ranges[2] = "key0000500";
key_ranges[3] = "key000060";
scan_options.insert(key_ranges[0], key_ranges[1]);
scan_options.insert(key_ranges[2], key_ranges[3]);
iter = dbfull()->NewMultiScan(ro, cfh, scan_options);
try {
int i = 0;
int count = 0;
for (auto range : *iter) {
for (auto it : range) {
ASSERT_GE(it.first.ToString(), key_ranges[i]);
ASSERT_LT(it.first.ToString(), key_ranges[i + 1]);
auto kiter = kvs.find(it.first.ToString());
ASSERT_NE(kiter, kvs.end());
ASSERT_EQ(kiter->second, it.second.ToString());
count++;
}
i += 2;
}
ASSERT_EQ(i, 4);
ASSERT_EQ(count, 19);
} catch (MultiScanException& ex) {
ASSERT_OK(ex.status());
}
iter.reset();
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
-129
View File
@@ -339,135 +339,6 @@ TEST_F(DBMemTableTest, ColumnFamilyId) {
}
}
class DBMemTableTestForSeek : public DBMemTableTest,
virtual public ::testing::WithParamInterface<
std::tuple<bool, bool, bool>> {};
TEST_P(DBMemTableTestForSeek, IntegrityChecks) {
// Validate key corruption could be detected during seek.
// We insert many keys into skiplist. Then we corrupt the each key one at a
// time. With memtable_veirfy_per_key_checksum_on_seek enabled, when the
// corrupted key is searched, the checksum of every key visited during the
// seek is validated. It will report data corruption. Otherwise seek returns
// not found.
auto allow_data_in_error = std::get<0>(GetParam());
Options options = CurrentOptions();
options.allow_data_in_errors = allow_data_in_error;
options.paranoid_memory_checks = std::get<1>(GetParam());
options.memtable_veirfy_per_key_checksum_on_seek = std::get<2>(GetParam());
options.memtable_protection_bytes_per_key = 8;
DestroyAndReopen(options);
// capture the data pointer of all of the keys
std::vector<char*> raw_data_pointer;
// Insert enough keys, so memtable would create multiple levels.
auto key_count = 100;
for (int i = 0; i < key_count; i++) {
// The last digit of the key will be corrupted from value 0 to value 5
ASSERT_OK(Put(Key(i * 10), "val0"));
}
ReadOptions rops;
// Iterate all the keys to get key pointers
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->SetCallBack("InlineSkipList::Iterator::Next::key",
[&raw_data_pointer](void* key) {
auto p = static_cast<char*>(key);
raw_data_pointer.push_back(p);
});
SyncPoint::GetInstance()->EnableProcessing();
{
std::unique_ptr<Iterator> iter{db_->NewIterator(rops)};
iter->Seek(Key(0));
while (iter->Valid()) {
ASSERT_OK(iter->status());
iter->Next();
}
// check status after valid returned false.
auto status = iter->status();
ASSERT_TRUE(status.ok());
}
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
ASSERT_EQ(raw_data_pointer.size(), key_count);
bool enable_key_validation_on_seek =
options.memtable_veirfy_per_key_checksum_on_seek;
// For each key, corrupt it, validate corruption is detected correctly, then
// revert it.
for (int i = 0; i < key_count; i++) {
std::string key_to_corrupt = Key(i * 10);
raw_data_pointer[i][key_to_corrupt.size()] = '5';
auto corrupted_key = key_to_corrupt;
corrupted_key.data()[key_to_corrupt.size() - 1] = '5';
auto corrupted_key_slice =
Slice(corrupted_key.data(), corrupted_key.length());
auto corrupted_key_hex = corrupted_key_slice.ToString(/*hex=*/true);
{
// Test Get API
std::string val;
auto status = db_->Get(rops, key_to_corrupt, &val);
if (enable_key_validation_on_seek) {
ASSERT_TRUE(status.IsCorruption()) << key_to_corrupt;
ASSERT_EQ(
status.ToString().find(corrupted_key_hex) != std::string::npos,
allow_data_in_error)
<< status.ToString() << "\n"
<< corrupted_key_hex;
} else {
ASSERT_TRUE(status.IsNotFound());
}
}
{
// Test MultiGet API
std::vector<std::string> vals;
std::vector<Status> statuses = db_->MultiGet(
rops, {db_->DefaultColumnFamily()}, {key_to_corrupt}, &vals, nullptr);
if (enable_key_validation_on_seek) {
ASSERT_TRUE(statuses[0].IsCorruption());
ASSERT_EQ(
statuses[0].ToString().find(corrupted_key_hex) != std::string::npos,
allow_data_in_error);
} else {
ASSERT_TRUE(statuses[0].IsNotFound());
}
}
{
// Test Iterator Seek API
std::unique_ptr<Iterator> iter{db_->NewIterator(rops)};
ASSERT_OK(iter->status());
iter->Seek(key_to_corrupt);
auto status = iter->status();
if (enable_key_validation_on_seek) {
ASSERT_TRUE(status.IsCorruption());
ASSERT_EQ(
status.ToString().find(corrupted_key_hex) != std::string::npos,
allow_data_in_error);
} else {
ASSERT_FALSE(iter->Valid());
ASSERT_FALSE(status.ok());
}
}
// revert the key corruption.
raw_data_pointer[i][key_to_corrupt.size()] = '0';
}
}
INSTANTIATE_TEST_CASE_P(DBMemTableTestForSeek, DBMemTableTestForSeek,
::testing::Combine(::testing::Bool(), ::testing::Bool(),
::testing::Bool()));
TEST_F(DBMemTableTest, IntegrityChecks) {
// We insert keys key000000, key000001 and key000002 into skiplist at fixed
// height 1 (smallest height). Then we corrupt the second key to aey000001 to
-40
View File
@@ -787,46 +787,6 @@ TEST_P(DBTablePropertiesTest, RatioBasedDeletionTriggeredCompactionMarking) {
}
}
TEST_F(DBTablePropertiesTest, KeyLargestSmallestSeqno) {
ASSERT_OK(db_->Put(WriteOptions(), "key1", "value1"));
ASSERT_OK(db_->Put(WriteOptions(), "key2", "value2"));
ASSERT_OK(db_->Put(WriteOptions(), "key3", "value3"));
ASSERT_OK(db_->Flush(FlushOptions()));
{
TablePropertiesCollection props;
ASSERT_OK(db_->GetPropertiesOfAllTables(&props));
ASSERT_EQ(1U, props.size());
auto table_props = props.begin()->second;
ASSERT_TRUE(table_props->HasKeyLargestSeqno());
ASSERT_TRUE(table_props->HasKeySmallestSeqno());
ASSERT_EQ(table_props->key_largest_seqno,
table_props->key_smallest_seqno + 2);
ASSERT_GT(table_props->key_largest_seqno, 0U);
ASSERT_GT(table_props->key_smallest_seqno, 0U);
}
// Becomes zero after compaction
{
CompactRangeOptions cro;
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
TablePropertiesCollection props;
ASSERT_OK(db_->GetPropertiesOfAllTables(&props));
ASSERT_EQ(1U, props.size());
auto table_props = props.begin()->second;
ASSERT_TRUE(table_props->HasKeyLargestSeqno());
ASSERT_TRUE(table_props->HasKeySmallestSeqno());
ASSERT_EQ(table_props->key_largest_seqno, table_props->key_smallest_seqno);
ASSERT_EQ(table_props->key_largest_seqno, 0U);
}
}
INSTANTIATE_TEST_CASE_P(DBTablePropertiesTest, DBTablePropertiesTest,
::testing::Values("kCompactionStyleLevel",
"kCompactionStyleUniversal"));
+15 -9
View File
@@ -6063,9 +6063,15 @@ TEST_F(DBTest2, VariousFileTemperatures) {
};
// We don't have enough non-unknown temps to confidently distinguish that
// a specific setting caused a specific outcome, in a single run. Using
// RandomKnownTemperature() is a reasonable work-around without blowing up
// test time.
// a specific setting caused a specific outcome, in a single run. This is a
// reasonable work-around without blowing up test time. Only returns
// non-unknown temperatures.
auto RandomTemp = [] {
static std::vector<Temperature> temps = {
Temperature::kHot, Temperature::kWarm, Temperature::kCold};
return temps[Random::GetTLSInstance()->Uniform(
static_cast<int>(temps.size()))];
};
auto test_fs = std::make_shared<MyTestFS>(env_->GetFileSystem());
std::unique_ptr<Env> env(new CompositeEnvWrapper(env_, test_fs));
@@ -6081,22 +6087,22 @@ TEST_F(DBTest2, VariousFileTemperatures) {
options.env = env.get();
test_fs->Reset();
if (use_optimize) {
test_fs->optimize_manifest_temperature = RandomKnownTemperature();
test_fs->optimize_manifest_temperature = RandomTemp();
test_fs->expected_manifest_temperature =
test_fs->optimize_manifest_temperature;
test_fs->optimize_wal_temperature = RandomKnownTemperature();
test_fs->optimize_wal_temperature = RandomTemp();
test_fs->expected_wal_temperature = test_fs->optimize_wal_temperature;
}
if (use_temp_options) {
options.metadata_write_temperature = RandomKnownTemperature();
options.metadata_write_temperature = RandomTemp();
test_fs->expected_manifest_temperature =
options.metadata_write_temperature;
test_fs->expected_other_metadata_temperature =
options.metadata_write_temperature;
options.wal_write_temperature = RandomKnownTemperature();
options.wal_write_temperature = RandomTemp();
test_fs->expected_wal_temperature = options.wal_write_temperature;
options.last_level_temperature = RandomKnownTemperature();
options.default_write_temperature = RandomKnownTemperature();
options.last_level_temperature = RandomTemp();
options.default_write_temperature = RandomTemp();
}
DestroyAndReopen(options);
+2 -11
View File
@@ -71,9 +71,9 @@ DBTestBase::DBTestBase(const std::string path, bool env_do_fsync)
if (getenv("MEM_ENV")) {
mem_env_ = MockEnv::Create(base_env, base_env->GetSystemClock());
}
if (auto ee = getenv("ENCRYPTED_ENV")) {
if (getenv("ENCRYPTED_ENV")) {
std::shared_ptr<EncryptionProvider> provider;
std::string provider_id = ee;
std::string provider_id = getenv("ENCRYPTED_ENV");
if (provider_id.find('=') == std::string::npos &&
!EndsWith(provider_id, "://test")) {
provider_id = provider_id + "://test";
@@ -1872,13 +1872,4 @@ template class TargetCacheChargeTrackingCache<
CacheEntryRole::kBlockBasedTableReader>;
template class TargetCacheChargeTrackingCache<CacheEntryRole::kFileMetadata>;
const std::vector<Temperature> kKnownTemperatures = {
Temperature::kHot, Temperature::kWarm, Temperature::kCool,
Temperature::kCold, Temperature::kIce};
Temperature RandomKnownTemperature() {
return kKnownTemperatures[Random::GetTLSInstance()->Uniform(
static_cast<int>(kKnownTemperatures.size()))];
}
} // namespace ROCKSDB_NAMESPACE
+14 -21
View File
@@ -1438,23 +1438,20 @@ class DBTestBase : public testing::Test {
std::replace(tp_string.begin(), tp_string.end(), ';', ' ');
std::replace(tp_string.begin(), tp_string.end(), '=', ' ');
ResetTableProperties(tp);
int count = sscanf(
tp_string.c_str(),
"# data blocks %" SCNu64 " # entries %" SCNu64 " # deletions %" SCNu64
" # merge operands %" SCNu64 " # range deletions %" SCNu64
" raw key size %" SCNu64
" raw average key size %lf "
" raw value size %" SCNu64
" raw average value size %lf "
" data block size %" SCNu64 " data uncompressed size %" SCNu64
" index block size (user-key? %" SCNu64 ", delta-value? %" SCNu64
") %" SCNu64 " filter block size %" SCNu64,
&tp->num_data_blocks, &tp->num_entries, &tp->num_deletions,
&tp->num_merge_operands, &tp->num_range_deletions, &tp->raw_key_size,
&dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size,
&tp->uncompressed_data_size, &tp->index_key_is_user_key,
&tp->index_value_is_delta_encoded, &tp->index_size, &tp->filter_size);
ASSERT_EQ(count, 15);
sscanf(tp_string.c_str(),
"# data blocks %" SCNu64 " # entries %" SCNu64
" # deletions %" SCNu64 " # merge operands %" SCNu64
" # range deletions %" SCNu64 " raw key size %" SCNu64
" raw average key size %lf "
" raw value size %" SCNu64
" raw average value size %lf "
" data block size %" SCNu64 " index block size (user-key? %" SCNu64
", delta-value? %" SCNu64 ") %" SCNu64 " filter block size %" SCNu64,
&tp->num_data_blocks, &tp->num_entries, &tp->num_deletions,
&tp->num_merge_operands, &tp->num_range_deletions, &tp->raw_key_size,
&dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size,
&tp->index_key_is_user_key, &tp->index_value_is_delta_encoded,
&tp->index_size, &tp->filter_size);
}
private: // Prone to error on direct use
@@ -1467,8 +1464,4 @@ class DBTestBase : public testing::Test {
// unique ids.
void VerifySstUniqueIds(const TablePropertiesCollection& props);
// Excludes kUnknown
extern const std::vector<Temperature> kKnownTemperatures;
Temperature RandomKnownTemperature();
} // namespace ROCKSDB_NAMESPACE
-1
View File
@@ -129,7 +129,6 @@ void EventHelpers::LogAndNotifyTableFileCreationFinished(
<< "user_defined_timestamps_persisted"
<< table_properties.user_defined_timestamps_persisted
<< "key_largest_seqno" << table_properties.key_largest_seqno
<< "key_smallest_seqno" << table_properties.key_smallest_seqno
<< "merge_operator" << table_properties.merge_operator_name
<< "prefix_extractor_name"
<< table_properties.prefix_extractor_name << "property_collectors"
+13 -95
View File
@@ -42,9 +42,6 @@ Status ExternalSstFileIngestionJob::Prepare(
status =
GetIngestedFileInfo(file_path, next_file_number++, &file_to_ingest, sv);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to get ingested file info: %s: %s",
file_path.c_str(), status.ToString().c_str());
return status;
}
@@ -201,10 +198,6 @@ Status ExternalSstFileIngestionJob::Prepare(
ROCKS_LOG_INFO(db_options_.info_log,
"Tried to link file %s but it's not supported : %s",
path_outside_db.c_str(), status.ToString().c_str());
} else {
ROCKS_LOG_WARN(db_options_.info_log, "Failed to link file %s to %s: %s",
path_outside_db.c_str(), path_inside_db.c_str(),
status.ToString().c_str());
}
} else {
f.copy_file = true;
@@ -229,12 +222,6 @@ Status ExternalSstFileIngestionJob::Prepare(
io_tracer_);
// The destination of the copy will be ingested
f.file_temperature = dst_temp;
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log, "Failed to copy file %s to %s: %s",
path_outside_db.c_str(), path_inside_db.c_str(),
status.ToString().c_str());
}
} else {
// Note: we currently assume that linking files does not cross
// temperatures, so no need to change f.file_temperature
@@ -460,11 +447,6 @@ Status ExternalSstFileIngestionJob::NeedsFlush(bool* flush_needed,
}
status = cfd_->RangesOverlapWithMemtables(
ranges, super_version, db_options_.allow_data_in_errors, flush_needed);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to check ranges overlap with memtables: %s",
status.ToString().c_str());
}
}
if (status.ok() && *flush_needed) {
if (!ingestion_options_.allow_blocking_flush) {
@@ -499,9 +481,6 @@ Status ExternalSstFileIngestionJob::Run() {
bool need_flush = false;
status = NeedsFlush(&need_flush, super_version);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to check if flush is needed: %s",
status.ToString().c_str());
return status;
}
if (need_flush) {
@@ -573,9 +552,6 @@ Status ExternalSstFileIngestionJob::Run() {
&last_seqno, &batch_uppermost_level,
prev_batch_uppermost_level);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to assign levels for one batch: %s",
status.ToString().c_str());
return status;
}
@@ -618,8 +594,6 @@ Status ExternalSstFileIngestionJob::AssignLevelsForOneBatch(
&largest_parsed, false /* log_err_key */);
}
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log, "Failed to parse internal key: %s",
status.ToString().c_str());
return status;
}
@@ -642,10 +616,6 @@ Status ExternalSstFileIngestionJob::AssignLevelsForOneBatch(
status = AssignGlobalSeqnoForIngestedFile(file, assigned_seqno);
if (!status.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"Failed to assign global sequence number for ingested file: %s",
status.ToString().c_str());
return status;
}
TEST_SYNC_POINT_CALLBACK("ExternalSstFileIngestionJob::Run",
@@ -658,9 +628,6 @@ Status ExternalSstFileIngestionJob::AssignLevelsForOneBatch(
status = GenerateChecksumForIngestedFile(file);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to generate checksum for ingested file: %s",
status.ToString().c_str());
return status;
}
@@ -886,10 +853,6 @@ Status ExternalSstFileIngestionJob::ResetTableReader(
Status status =
fs_->NewRandomAccessFile(external_file, fo, &sst_file, nullptr);
if (!status.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"Failed to create random access file for external file %s: %s",
external_file.c_str(), status.ToString().c_str());
return status;
}
Temperature updated_temp = sst_file->GetTemperature();
@@ -1012,10 +975,6 @@ Status ExternalSstFileIngestionJob::SanityCheckTableProperties(
// user_defined_timestamps_persisted flag for the file.
file_to_ingest->user_defined_timestamps_persisted = false;
} else if (!s.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"ValidateUserDefinedTimestampsOptions failed for external file %s: %s",
external_file.c_str(), s.ToString().c_str());
return s;
}
@@ -1040,9 +999,6 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
Status status = fs_->GetFileSize(external_file, IOOptions(),
&file_to_ingest->file_size, nullptr);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to get file size for external file %s: %s",
external_file.c_str(), status.ToString().c_str());
return status;
}
@@ -1059,19 +1015,12 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
/*user_defined_timestamps_persisted=*/true, sv,
file_to_ingest, &table_reader);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to reset table reader for external file %s: %s",
external_file.c_str(), status.ToString().c_str());
return status;
}
status = SanityCheckTableProperties(external_file, new_file_number, sv,
file_to_ingest, &table_reader);
if (!status.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"Failed to sanity check table properties for external file %s: %s",
external_file.c_str(), status.ToString().c_str());
return status;
}
@@ -1085,10 +1034,6 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
table_reader.get(), sv, file_to_ingest, allow_data_in_errors);
if (!seqno_status.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"Failed to get sequence number boundary for external file %s: %s",
external_file.c_str(), seqno_status.ToString().c_str());
return seqno_status;
}
assert(file_to_ingest->smallest_seqno <= file_to_ingest->largest_seqno);
@@ -1116,9 +1061,6 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
status = table_reader->VerifyChecksum(
ro, TableReaderCaller::kExternalSSTIngestion);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to verify checksum for table reader: %s",
status.ToString().c_str());
return status;
}
}
@@ -1310,9 +1252,6 @@ Status ExternalSstFileIngestionJob::AssignLevelAndSeqnoForIngestedFile(
ro, env_options_, file_to_ingest->start_ukey,
file_to_ingest->limit_ukey, lvl, &overlap_with_level);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to check overlap with level iterator: %s",
status.ToString().c_str());
return status;
}
if (overlap_with_level) {
@@ -1425,14 +1364,6 @@ Status ExternalSstFileIngestionJob::AssignGlobalSeqnoForIngestedFile(
PutFixed64(&seqno_val, seqno);
status = fsptr->Write(file_to_ingest->global_seqno_offset, seqno_val,
IOOptions(), nullptr);
if (!status.ok()) {
ROCKS_LOG_WARN(db_options_.info_log,
"Failed to write global seqno to %s: %s",
file_to_ingest->internal_file_path.c_str(),
status.ToString().c_str());
return status;
}
if (status.ok()) {
TEST_SYNC_POINT("ExternalSstFileIngestionJob::BeforeSyncGlobalSeqno");
status = SyncIngestedFile(fsptr.get());
@@ -1449,11 +1380,6 @@ Status ExternalSstFileIngestionJob::AssignGlobalSeqnoForIngestedFile(
return status;
}
} else if (!status.IsNotSupported()) {
ROCKS_LOG_WARN(
db_options_.info_log,
"Failed to open ingested file %s for random read/write: %s",
file_to_ingest->internal_file_path.c_str(),
status.ToString().c_str());
return status;
}
}
@@ -1486,9 +1412,6 @@ IOStatus ExternalSstFileIngestionJob::GenerateChecksumForIngestedFile(
db_options_.allow_mmap_reads, io_tracer_, db_options_.rate_limiter.get(),
ro, db_options_.stats, db_options_.clock);
if (!io_s.ok()) {
ROCKS_LOG_WARN(
db_options_.info_log, "Failed to generate checksum for %s: %s",
file_to_ingest->internal_file_path.c_str(), io_s.ToString().c_str());
return io_s;
}
file_to_ingest->file_checksum = std::move(file_checksum);
@@ -1531,26 +1454,21 @@ Status ExternalSstFileIngestionJob::SyncIngestedFile(TWritableFile* file) {
Status ExternalSstFileIngestionJob::GetSeqnoBoundaryForFile(
TableReader* table_reader, SuperVersion* sv,
IngestedFileInfo* file_to_ingest, bool allow_data_in_errors) {
const auto tp = table_reader->GetTableProperties();
const bool has_largest_seqno = tp->HasKeyLargestSeqno();
SequenceNumber largest_seqno = tp->key_largest_seqno;
if (has_largest_seqno) {
file_to_ingest->largest_seqno = largest_seqno;
if (largest_seqno == 0) {
file_to_ingest->smallest_seqno = 0;
return Status::OK();
}
if (tp->HasKeySmallestSeqno()) {
file_to_ingest->smallest_seqno = tp->key_smallest_seqno;
return Status::OK();
}
const bool has_largest_seqno =
table_reader->GetTableProperties()->HasKeyLargestSeqno();
SequenceNumber largest_seqno =
table_reader->GetTableProperties()->key_largest_seqno;
if (has_largest_seqno && largest_seqno == 0) {
file_to_ingest->largest_seqno = 0;
file_to_ingest->smallest_seqno = 0;
return Status::OK();
}
// For older SST files they may not be recorded in table properties, so
// we scan the file to find out.
TEST_SYNC_POINT(
"ExternalSstFileIngestionJob::GetSeqnoBoundaryForFile:FileScan");
// The following file scan is only executed when ingesting files with
// non-zero seqno.
// TODO: record smallest_seqno in table properties to avoid the
// file scan here.
SequenceNumber smallest_seqno = kMaxSequenceNumber;
SequenceNumber largest_seqno_from_iter = 0;
ReadOptions ro;
ro.fill_cache = ingestion_options_.fill_cache;
+2 -15
View File
@@ -4099,7 +4099,6 @@ TEST_P(IngestDBGeneratedFileTest2, NonZeroSeqno) {
SCOPED_TRACE("option_config_ = " + std::to_string(option_config_));
Options options = CurrentOptions();
options.statistics = CreateDBStatistics();
options.allow_concurrent_memtable_write =
false; // Required for VectorRepFactory
CreateAndReopenWithCF({"non_overlap", "overlap"}, options);
@@ -4136,7 +4135,7 @@ TEST_P(IngestDBGeneratedFileTest2, NonZeroSeqno) {
// optional L5: files in key range [70, 98]
// L6: files in key range [1, 79]
temp_cf_opts.target_file_size_base =
20 << 10; // Small files to create multiple SSTs
4 << 10; // Small files to create multiple SSTs
temp_cf_opts.num_levels = 7;
temp_cf_opts.disable_auto_compactions = true; // Manually set up LSM
temp_cf_opts.env = options.env;
@@ -4156,7 +4155,7 @@ TEST_P(IngestDBGeneratedFileTest2, NonZeroSeqno) {
const Snapshot* snapshot = from_db->GetSnapshot();
for (int k = 1; k < 99; ++k) {
expected_values[k] = rnd->RandomString(2000);
expected_values[k] = rnd->RandomString(500);
ASSERT_OK(from_db->Put(wo, temp_cfh, Key(k), expected_values[k]));
}
ASSERT_OK(from_db->Flush({}, temp_cfh));
@@ -4234,21 +4233,9 @@ TEST_P(IngestDBGeneratedFileTest2, NonZeroSeqno) {
"assigned a non-zero sequence number"));
db_->ReleaseSnapshot(snapshot);
}
std::atomic<int> file_scan_count{0};
SyncPoint::GetInstance()->SetCallBack(
"ExternalSstFileIngestionJob::GetSeqnoBoundaryForFile:FileScan",
[&](void* /*arg*/) { file_scan_count++; });
SyncPoint::GetInstance()->EnableProcessing();
ASSERT_OK(
db_->IngestExternalFile(non_overlap_cf, sst_file_paths, ingest_opts));
SyncPoint::GetInstance()->DisableProcessing();
SyncPoint::GetInstance()->ClearAllCallBacks();
EXPECT_EQ(file_scan_count, 0);
// Validate ingested data.
ReadOptions ro;
std::string val;
+2 -2
View File
@@ -1104,13 +1104,13 @@ Status FlushJob::WriteLevel0Table() {
const uint64_t micros = clock_->NowMicros() - start_micros;
const uint64_t cpu_micros = clock_->CPUMicros() - start_cpu_micros;
flush_stats.micros = micros;
flush_stats.cpu_micros += cpu_micros;
flush_stats.cpu_micros = cpu_micros;
ROCKS_LOG_INFO(db_options_.info_log,
"[%s] [JOB %d] Flush lasted %" PRIu64
" microseconds, and %" PRIu64 " cpu microseconds.\n",
cfd_->GetName().c_str(), job_context_->job_id, micros,
flush_stats.cpu_micros);
cpu_micros);
if (has_output) {
flush_stats.bytes_written = meta_.fd.GetFileSize();
+13 -38
View File
@@ -70,9 +70,7 @@ ImmutableMemTableOptions::ImmutableMemTableOptions(
protection_bytes_per_key(
mutable_cf_options.memtable_protection_bytes_per_key),
allow_data_in_errors(ioptions.allow_data_in_errors),
paranoid_memory_checks(mutable_cf_options.paranoid_memory_checks),
memtable_veirfy_per_key_checksum_on_seek(
mutable_cf_options.memtable_veirfy_per_key_checksum_on_seek) {}
paranoid_memory_checks(mutable_cf_options.paranoid_memory_checks) {}
MemTable::MemTable(const InternalKeyComparator& cmp,
const ImmutableOptions& ioptions,
@@ -117,13 +115,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
oldest_key_time_(std::numeric_limits<uint64_t>::max()),
approximate_memory_usage_(0),
memtable_max_range_deletions_(
mutable_cf_options.memtable_max_range_deletions),
key_validation_callback_(
(moptions_.protection_bytes_per_key != 0 &&
moptions_.memtable_veirfy_per_key_checksum_on_seek)
? std::bind(&MemTable::ValidateKey, this, std::placeholders::_1,
std::placeholders::_2)
: std::function<Status(const char*, bool)>(nullptr)) {
mutable_cf_options.memtable_max_range_deletions) {
UpdateFlushState();
// something went wrong if we need to flush before inserting anything
assert(!ShouldScheduleFlush());
@@ -402,11 +394,7 @@ class MemTableIterator : public InternalIterator {
!mem.GetImmutableMemTableOptions()->inplace_update_support),
arena_mode_(arena != nullptr),
paranoid_memory_checks_(mem.moptions_.paranoid_memory_checks),
validate_on_seek_(
mem.moptions_.paranoid_memory_checks ||
mem.moptions_.memtable_veirfy_per_key_checksum_on_seek),
allow_data_in_error_(mem.moptions_.allow_data_in_errors),
key_validation_callback_(mem.key_validation_callback_) {
allow_data_in_error(mem.moptions_.allow_data_in_errors) {
if (kind == kRangeDelEntries) {
iter_ = mem.range_del_table_->GetIterator(arena);
} else if (prefix_extractor_ != nullptr &&
@@ -475,10 +463,8 @@ class MemTableIterator : public InternalIterator {
}
}
}
if (validate_on_seek_) {
status_ = iter_->SeekAndValidate(k, nullptr, allow_data_in_error_,
paranoid_memory_checks_,
key_validation_callback_);
if (paranoid_memory_checks_) {
status_ = iter_->SeekAndValidate(k, nullptr, allow_data_in_error);
} else {
iter_->Seek(k, nullptr);
}
@@ -502,10 +488,8 @@ class MemTableIterator : public InternalIterator {
}
}
}
if (validate_on_seek_) {
status_ = iter_->SeekAndValidate(k, nullptr, allow_data_in_error_,
paranoid_memory_checks_,
key_validation_callback_);
if (paranoid_memory_checks_) {
status_ = iter_->SeekAndValidate(k, nullptr, allow_data_in_error);
} else {
iter_->Seek(k, nullptr);
}
@@ -534,7 +518,7 @@ class MemTableIterator : public InternalIterator {
PERF_COUNTER_ADD(next_on_memtable_count, 1);
assert(Valid());
if (paranoid_memory_checks_) {
status_ = iter_->NextAndValidate(allow_data_in_error_);
status_ = iter_->NextAndValidate(allow_data_in_error);
} else {
iter_->Next();
TEST_SYNC_POINT_CALLBACK("MemTableIterator::Next:0", iter_);
@@ -556,7 +540,7 @@ class MemTableIterator : public InternalIterator {
PERF_COUNTER_ADD(prev_on_memtable_count, 1);
assert(Valid());
if (paranoid_memory_checks_) {
status_ = iter_->PrevAndValidate(allow_data_in_error_);
status_ = iter_->PrevAndValidate(allow_data_in_error);
} else {
iter_->Prev();
}
@@ -615,9 +599,7 @@ class MemTableIterator : public InternalIterator {
bool value_pinned_;
bool arena_mode_;
const bool paranoid_memory_checks_;
const bool validate_on_seek_;
const bool allow_data_in_error_;
const std::function<Status(const char*, bool)> key_validation_callback_;
const bool allow_data_in_error;
void VerifyEntryChecksum() {
if (protection_bytes_per_key_ > 0 && Valid()) {
@@ -1511,13 +1493,11 @@ void MemTable::GetFromTable(const LookupKey& key,
saver.allow_data_in_errors = moptions_.allow_data_in_errors;
saver.protection_bytes_per_key = moptions_.protection_bytes_per_key;
if (!moptions_.paranoid_memory_checks &&
!moptions_.memtable_veirfy_per_key_checksum_on_seek) {
if (!moptions_.paranoid_memory_checks) {
table_->Get(key, &saver, SaveValue);
} else {
Status check_s = table_->GetAndValidate(
key, &saver, SaveValue, moptions_.allow_data_in_errors,
moptions_.paranoid_memory_checks, key_validation_callback_);
Status check_s = table_->GetAndValidate(key, &saver, SaveValue,
moptions_.allow_data_in_errors);
if (check_s.IsCorruption()) {
*(saver.status) = check_s;
// Should stop searching the LSM.
@@ -1528,11 +1508,6 @@ void MemTable::GetFromTable(const LookupKey& key,
*seq = saver.seq;
}
Status MemTable::ValidateKey(const char* key, bool allow_data_in_errors) {
return VerifyEntryChecksum(key, moptions_.protection_bytes_per_key,
allow_data_in_errors);
}
void MemTable::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
ReadCallback* callback, bool immutable_memtable) {
// The sequence number is updated synchronously in version_set.h
-6
View File
@@ -64,7 +64,6 @@ struct ImmutableMemTableOptions {
uint32_t protection_bytes_per_key;
bool allow_data_in_errors;
bool paranoid_memory_checks;
bool memtable_veirfy_per_key_checksum_on_seek;
};
// Batched counters to updated when inserting keys in one write batch.
@@ -827,9 +826,6 @@ class MemTable final : public ReadOnlyMemTable {
uint32_t protection_bytes_per_key,
bool allow_data_in_errors = false);
// Validate the checksum of the key/value pair.
Status ValidateKey(const char* key, bool allow_data_in_errors);
private:
enum FlushStateEnum { FLUSH_NOT_REQUESTED, FLUSH_REQUESTED, FLUSH_SCHEDULED };
@@ -960,8 +956,6 @@ class MemTable final : public ReadOnlyMemTable {
SequenceNumber s, char* checksum_ptr);
void MaybeUpdateNewestUDT(const Slice& user_key);
const std::function<Status(const char*, bool)> key_validation_callback_;
};
const char* EncodeKey(std::string* scratch, const Slice& target);
+1 -1
View File
@@ -32,7 +32,6 @@ bool MergeOperator::FullMergeV3(const MergeOperationInputV3& merge_in,
MergeOperationOutputV3* merge_out) const {
assert(merge_out);
Slice value_of_default; // avoid warning about in_v2 pointing at this
MergeOperationInput in_v2(merge_in.key, nullptr, merge_in.operand_list,
merge_in.logger);
@@ -67,6 +66,7 @@ bool MergeOperator::FullMergeV3(const MergeOperationInputV3& merge_in,
const bool has_default_column =
WideColumnsHelper::HasDefaultColumn(existing_columns);
Slice value_of_default;
if (has_default_column) {
value_of_default = existing_columns.front().value();
}
-5
View File
@@ -40,11 +40,6 @@ MultiScan::MultiScan(const ReadOptions& read_options,
}
MultiScanIterator& MultiScanIterator::operator++() {
status_ = db_iter_->status();
if (!status_.ok()) {
throw MultiScanException(status_);
}
if (idx_ >= scan_opts_.size()) {
throw std::logic_error("Index out of range");
}
+1 -1
View File
@@ -396,7 +396,7 @@ const char* VersionEdit::DecodeNewFile4From(Slice* input) {
return "temperature field wrong size";
} else {
Temperature casted_field = static_cast<Temperature>(field[0]);
if (casted_field < Temperature::kLastTemperature) {
if (casted_field <= Temperature::kCold) {
f.temperature = casted_field;
}
}
+13 -91
View File
@@ -1101,27 +1101,6 @@ class LevelIterator final : public InternalIterator {
read_seq_ = read_seq;
}
inline bool FileHasMultiScanArg(size_t file_index) {
if (file_to_scan_opts_.get()) {
auto it = file_to_scan_opts_->find(file_index);
if (it != file_to_scan_opts_->end()) {
return !it->second.empty();
}
}
return false;
}
MultiScanArgs& GetMultiScanArgForFile(size_t file_index) {
auto multi_scan_args_it = file_to_scan_opts_->find(file_index);
if (multi_scan_args_it == file_to_scan_opts_->end()) {
auto ret = file_to_scan_opts_->emplace(
file_index, MultiScanArgs(user_comparator_.user_comparator()));
multi_scan_args_it = ret.first;
assert(ret.second);
}
return multi_scan_args_it->second;
}
void Prepare(const MultiScanArgs* so) override {
// We assume here that scan_opts is sorted such that
// scan_opts[0].range.start < scan_opts[1].range.start, and non overlapping
@@ -1130,9 +1109,6 @@ class LevelIterator final : public InternalIterator {
}
scan_opts_ = so;
// Verify comparator is consistent
assert(so->GetComparator() == user_comparator_.user_comparator());
file_to_scan_opts_ = std::make_unique<ScanOptionsMap>();
for (size_t k = 0; k < scan_opts_->size(); k++) {
const ScanOptions& opt = scan_opts_->GetScanRanges().at(k);
@@ -1148,26 +1124,8 @@ class LevelIterator final : public InternalIterator {
continue;
}
const size_t timestamp_size =
user_comparator_.user_comparator()->timestamp_size();
InternalKey istart, iend;
if (timestamp_size == 0) {
istart =
InternalKey(start.value(), kMaxSequenceNumber, kValueTypeForSeek);
// end key is exclusive for multiscan
iend = InternalKey(end.value(), kMaxSequenceNumber, kValueTypeForSeek);
} else {
std::string start_key_with_ts, end_key_with_ts;
AppendKeyWithMaxTimestamp(&start_key_with_ts, start.value(),
timestamp_size);
AppendKeyWithMaxTimestamp(&end_key_with_ts, end.value(),
timestamp_size);
istart = InternalKey(start_key_with_ts, kMaxSequenceNumber,
kValueTypeForSeek);
// end key is exclusive for multiscan
iend =
InternalKey(end_key_with_ts, kMaxSequenceNumber, kValueTypeForSeek);
}
InternalKey istart(start.value(), kMaxSequenceNumber, kValueTypeForSeek);
InternalKey iend(end.value(), 0, kValueTypeForSeekForPrev);
// TODO: This needs to be optimized, right now we iterate twice, which
// we dont need to. We can do this in N rather than 2N.
@@ -1181,25 +1139,14 @@ class LevelIterator final : public InternalIterator {
// 3. [ S ] ...... [ E ]
for (auto i = fstart; i <= fend; i++) {
if (i < flevel_->num_files) {
// FindFile only compares against the largest_key, so we need this
// additional check to ensure the scan range overlaps the file
if (icomparator_.InternalKeyComparator::Compare(
iend.Encode(), flevel_->files[i].smallest_key) < 0) {
continue;
}
auto const metadata = flevel_->files[i].file_metadata;
if (metadata->FileIsStandAloneRangeTombstone()) {
// Skip stand alone range deletion files.
continue;
}
auto& args = GetMultiScanArgForFile(i);
args.insert(start.value(), end.value(), opt.property_bag);
(*file_to_scan_opts_)[i].insert(start.value(), end.value(),
opt.property_bag);
}
}
}
// Propagate multiscan configs
// Propagate io colaescing threshold
for (auto& file_to_arg : *file_to_scan_opts_) {
file_to_arg.second.CopyConfigFrom(*so);
file_to_arg.second.io_coalesce_threshold = so->io_coalesce_threshold;
}
}
@@ -1275,10 +1222,6 @@ class LevelIterator final : public InternalIterator {
}
}
#ifndef NDEBUG
bool OverlapRange(const ScanOptions& opts);
#endif
TableCache* table_cache_;
const ReadOptions& read_options_;
const FileOptions& file_options_;
@@ -1376,14 +1319,6 @@ void LevelIterator::Seek(const Slice& target) {
}
if (file_iter_.iter() != nullptr) {
if (scan_opts_) {
// At this point, we only know that the seek target is < largest_key
// in the file. We need to check whether there is actual overlap.
const FdWithKeyRange& cur_file = flevel_->files[file_index_];
if (KeyReachedUpperBound(cur_file.smallest_key)) {
return;
}
}
file_iter_.Seek(target);
// Status::TryAgain indicates asynchronous request for retrieval of data
// blocks has been submitted. So it should return at this point and Seek
@@ -1608,10 +1543,9 @@ bool LevelIterator::SkipEmptyFileForward() {
if (file_iter_.iter() != nullptr) {
// If we are doing prepared scan opts then we should seek to the values
// specified by the scan opts
if (scan_opts_ && FileHasMultiScanArg(file_index_)) {
if (scan_opts_ && (*file_to_scan_opts_)[file_index_].size()) {
const ScanOptions& opts =
GetMultiScanArgForFile(file_index_).GetScanRanges().front();
file_to_scan_opts_->at(file_index_).GetScanRanges().front();
if (opts.range.start.has_value()) {
InternalKey target(*opts.range.start.AsPtr(), kMaxSequenceNumber,
kValueTypeForSeek);
@@ -1661,19 +1595,6 @@ void LevelIterator::SkipEmptyFileBackward() {
}
}
#ifndef NDEBUG
bool LevelIterator::OverlapRange(const ScanOptions& opts) {
return (user_comparator_.CompareWithoutTimestamp(
opts.range.start.value(), /*a_has_ts=*/false,
ExtractUserKey(flevel_->files[file_index_].largest_key),
/*b_has_ts=*/true) <= 0 &&
user_comparator_.CompareWithoutTimestamp(
opts.range.limit.value(), /*a_has_ts=*/false,
ExtractUserKey(flevel_->files[file_index_].smallest_key),
/*b_has_ts=*/true) > 0);
}
#endif
void LevelIterator::SetFileIterator(InternalIterator* iter) {
if (pinned_iters_mgr_ && iter) {
iter->SetPinnedItersMgr(pinned_iters_mgr_);
@@ -1681,11 +1602,12 @@ void LevelIterator::SetFileIterator(InternalIterator* iter) {
InternalIterator* old_iter = file_iter_.Set(iter);
if (iter && scan_opts_) {
if (FileHasMultiScanArg(file_index_)) {
const MultiScanArgs& new_opts = GetMultiScanArgForFile(file_index_);
assert(OverlapRange(*new_opts.GetScanRanges().begin()) &&
OverlapRange(*new_opts.GetScanRanges().rbegin()));
if (file_to_scan_opts_.get() &&
file_to_scan_opts_->find(file_index_) != file_to_scan_opts_->end()) {
const MultiScanArgs& new_opts = file_to_scan_opts_->at(file_index_);
file_iter_.Prepare(&new_opts);
} else {
file_iter_.Prepare(scan_opts_);
}
}
+1
View File
@@ -9,6 +9,7 @@ add_executable(db_stress${ARTIFACT_SUFFIX}
db_stress_gflags.cc
db_stress_listener.cc
db_stress_shared_state.cc
db_stress_stat.cc
db_stress_test_base.cc
db_stress_wide_merge_operator.cc
db_stress_tool.cc
-11
View File
@@ -275,7 +275,6 @@ DECLARE_string(last_level_temperature);
DECLARE_string(default_write_temperature);
DECLARE_string(default_temperature);
DECLARE_bool(paranoid_memory_checks);
DECLARE_bool(memtable_veirfy_per_key_checksum_on_seek);
// Options for transaction dbs.
// Use TransactionDB (a.k.a. Pessimistic Transaction DB)
@@ -285,7 +284,6 @@ DECLARE_bool(use_txn);
// Options for TransactionDB (a.k.a. Pessimistic Transaction DB)
DECLARE_uint64(txn_write_policy);
DECLARE_bool(unordered_write);
DECLARE_bool(use_per_key_point_lock_mgr);
// Options for OptimisticTransactionDB
DECLARE_bool(use_optimistic_txn);
@@ -426,21 +424,12 @@ DECLARE_uint32(commit_bypass_memtable_one_in);
DECLARE_bool(track_and_verify_wals);
DECLARE_int32(remote_compaction_worker_threads);
DECLARE_int32(remote_compaction_worker_interval);
DECLARE_bool(remote_compaction_failure_fall_back_to_local);
DECLARE_bool(auto_refresh_iterator_with_snapshot);
DECLARE_uint32(memtable_op_scan_flush_trigger);
DECLARE_uint32(memtable_avg_op_scan_flush_trigger);
DECLARE_uint32(ingest_wbwi_one_in);
DECLARE_bool(universal_reduce_file_locking);
DECLARE_bool(use_multiscan);
DECLARE_bool(multiscan_use_async_io);
// Compaction deletion trigger declarations for stress testing
DECLARE_bool(enable_compaction_on_deletion_trigger);
DECLARE_uint64(compaction_on_deletion_min_file_size);
DECLARE_int32(compaction_on_deletion_trigger_count);
DECLARE_int32(compaction_on_deletion_window_size);
DECLARE_double(compaction_on_deletion_ratio);
constexpr long KB = 1024;
constexpr int kRandomValueMaxFactor = 3;
+2 -11
View File
@@ -14,11 +14,8 @@ namespace ROCKSDB_NAMESPACE {
// Service to simulate Remote Compaction in Stress Test
class DbStressCompactionService : public CompactionService {
public:
explicit DbStressCompactionService(SharedState* shared,
bool failure_should_fall_back_to_local)
: shared_(shared),
aborted_(false),
failure_should_fall_back_to_local_(failure_should_fall_back_to_local) {}
explicit DbStressCompactionService(SharedState* shared)
: shared_(shared), aborted_(false) {}
static const char* kClassName() { return "DbStressCompactionService"; }
@@ -59,11 +56,6 @@ class DbStressCompactionService : public CompactionService {
}
Env::Default()->SleepForMicroseconds(kWaitIntervalInMicros);
}
if (failure_should_fall_back_to_local_) {
fprintf(stdout,
"Remote Compaction failed - fall back to local compaction!\n");
return CompactionServiceJobStatus::kUseLocal;
}
return CompactionServiceJobStatus::kFailure;
}
@@ -98,7 +90,6 @@ class DbStressCompactionService : public CompactionService {
private:
SharedState* shared_;
std::atomic_bool aborted_{false};
bool failure_should_fall_back_to_local_;
};
} // namespace ROCKSDB_NAMESPACE
-38
View File
@@ -724,10 +724,6 @@ DEFINE_uint64(txn_write_policy, 0,
"TxnDBWritePolicy::WRITE_COMMITTED. Note that this should not be "
"changed across crashes.");
DEFINE_bool(use_per_key_point_lock_mgr, true,
"Use PointLockManager(false) or PerKeyPointLockManager(true) in "
"TransactionDB.");
DEFINE_bool(use_optimistic_txn, false, "Use OptimisticTransactionDB.");
DEFINE_uint64(occ_validation_policy, 1,
"Optimistic Concurrency Control Validation Policy for "
@@ -857,10 +853,6 @@ DEFINE_int32(remote_compaction_worker_interval, 10,
"Remote Compaction Worker Thread dequeue tasks every N "
"milliseconds. (Default: 10ms)");
DEFINE_bool(remote_compaction_failure_fall_back_to_local, true,
"If true, remote compaction failures will be ignored and "
"compactions will fall back to local and retried");
DEFINE_uint32(ingest_wbwi_one_in, 0,
"If set, will call"
"IngestWriteBatchWithIndex() instead of regular write operations "
@@ -1484,37 +1476,10 @@ DEFINE_bool(paranoid_memory_checks,
ROCKSDB_NAMESPACE::Options().paranoid_memory_checks,
"Sets CF option paranoid_memory_checks.");
DEFINE_bool(
memtable_veirfy_per_key_checksum_on_seek,
ROCKSDB_NAMESPACE::Options().memtable_veirfy_per_key_checksum_on_seek,
"Sets CF option memtable_veirfy_per_key_checksum_on_seek.");
DEFINE_uint32(commit_bypass_memtable_one_in, 0,
"If greater than zero, transaction option will set "
"commit_bypass_memtable to per every N transactions on average.");
// Compaction on deletion trigger flags
DEFINE_bool(enable_compaction_on_deletion_trigger, false,
"Enable CompactOnDeletionCollectorFactory for stress testing "
"deletion-triggered compaction scenarios.");
DEFINE_uint64(compaction_on_deletion_min_file_size, 32 * 1024,
"Minimum file size (in bytes) for deletion-triggered compaction. "
"Files smaller than this will not trigger compaction even if "
"deletion ratio is exceeded. Default: 32KB");
DEFINE_int32(compaction_on_deletion_trigger_count, 50,
"Number of deletions that triggers compaction when deletion "
"ratio is exceeded. Default: 50");
DEFINE_int32(compaction_on_deletion_window_size, 100,
"Size of the sliding window for tracking deletions. "
"Default: 100");
DEFINE_double(compaction_on_deletion_ratio, 0.5,
"Deletion ratio threshold for triggering compaction. "
"Default: 0.5 (50%)");
DEFINE_bool(
auto_refresh_iterator_with_snapshot,
ROCKSDB_NAMESPACE::ReadOptions().auto_refresh_iterator_with_snapshot,
@@ -1540,7 +1505,4 @@ DEFINE_bool(
DEFINE_bool(use_multiscan, false,
"If set, use the batched MultiScan API for scans.");
DEFINE_bool(multiscan_use_async_io, false,
"If set, enable async_io for MultiScan operations.");
#endif // GFLAGS
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#ifdef GFLAGS
#include "db_stress_tool/db_stress_stat.h"
namespace ROCKSDB_NAMESPACE {
std::shared_ptr<ROCKSDB_NAMESPACE::Statistics> dbstats;
std::shared_ptr<ROCKSDB_NAMESPACE::Statistics> dbstats_secondaries;
} // namespace ROCKSDB_NAMESPACE
#endif // GFLAGS
+4
View File
@@ -22,6 +22,10 @@ DECLARE_bool(progress_reports);
namespace ROCKSDB_NAMESPACE {
// Database statistics
extern std::shared_ptr<ROCKSDB_NAMESPACE::Statistics> dbstats;
extern std::shared_ptr<ROCKSDB_NAMESPACE::Statistics> dbstats_secondaries;
class Stats {
private:
uint64_t start_;
+17 -62
View File
@@ -30,7 +30,6 @@
#include "rocksdb/filter_policy.h"
#include "rocksdb/secondary_cache.h"
#include "rocksdb/sst_file_manager.h"
#include "rocksdb/table_properties.h"
#include "rocksdb/types.h"
#include "rocksdb/utilities/object_registry.h"
#include "rocksdb/utilities/write_batch_with_index.h"
@@ -428,9 +427,6 @@ bool StressTest::BuildOptionsTable() {
options_tbl.emplace(
"file_temperature_age_thresholds",
std::vector<std::string>{
"{{temperature=kWarm;age=10}:{temperature=kCool;age=30}:{"
"temperature=kCold;age=100}:{"
"temperature=kIce;age=300}}",
"{{temperature=kWarm;age=30}:{temperature=kCold;age=300}}",
"{{temperature=kCold;age=100}}", "{}"});
options_tbl.emplace(
@@ -657,20 +653,12 @@ std::string StressTest::DebugString(const Slice& value,
}
void StressTest::PrintStatistics() {
// Print statistics from the DB instance instead of global dbstats
if (db_) {
auto stats = db_->GetOptions().statistics;
if (stats) {
fprintf(stdout, "STATISTICS:\n%s\n", stats->ToString().c_str());
}
if (dbstats) {
fprintf(stdout, "STATISTICS:\n%s\n", dbstats->ToString().c_str());
}
// Print statistics from secondary DB instance if it exists
if (secondary_db_) {
auto stats = secondary_db_->GetOptions().statistics;
if (stats) {
fprintf(stdout, "Secondary instance STATISTICS:\n%s\n",
stats->ToString().c_str());
}
if (dbstats_secondaries) {
fprintf(stdout, "Secondary instances STATISTICS:\n%s\n",
dbstats_secondaries->ToString().c_str());
}
}
@@ -1678,11 +1666,7 @@ Status StressTest::TestMultiScan(ThreadState* thread,
assert(!rand_column_families.empty());
assert(!rand_keys.empty());
ThreadStatus::OperationType cur_op_type =
ThreadStatusUtil::GetThreadOperation();
ThreadStatusUtil::SetThreadOperation(ThreadStatus::OperationType::OP_UNKNOWN);
ManagedSnapshot snapshot_guard(db_);
ThreadStatusUtil::SetThreadOperation(cur_op_type);
ReadOptions ro = read_opts;
ro.snapshot = snapshot_guard.snapshot();
@@ -1693,9 +1677,7 @@ Status StressTest::TestMultiScan(ThreadState* thread,
std::vector<std::string> start_key_strs;
std::vector<std::string> end_key_strs;
// TODO support reverse BytewiseComparator in the stress test
MultiScanArgs scan_opts(options_.comparator);
scan_opts.use_async_io = FLAGS_multiscan_use_async_io;
MultiScanArgs scan_opts;
start_key_strs.reserve(num_scans);
end_key_strs.reserve(num_scans);
@@ -1821,14 +1803,11 @@ Status StressTest::TestMultiScan(ThreadState* thread,
key, op_logs, verify_func, &diverged);
if (diverged) {
if (thread->shared->HasVerificationFailedYet()) {
const std::vector<ScanOptions>& scanoptions =
scan_opts.GetScanRanges();
for (const auto& t : scanoptions) {
fprintf(stdout, "Multiscan options: %s to %s \n",
t.range.start.value().ToString(true).c_str(),
t.range.limit.value().ToString(true).c_str());
}
const std::vector<ScanOptions>& scanoptions = scan_opts.GetScanRanges();
for (const auto& t : scanoptions) {
fprintf(stdout, "Multiscan options: %s to %s \n",
t.range.start.value().ToString(true).c_str(),
t.range.limit.value().ToString(true).c_str());
}
break;
}
@@ -3524,9 +3503,8 @@ void StressTest::PrintEnv() const {
fprintf(stdout, "Verification only : %s\n",
FLAGS_verification_only ? "true" : "false");
const char* memtablerep;
const char* memtablerep = "";
switch (FLAGS_rep_factory) {
default:
case kSkipList:
memtablerep = "skip_list";
break;
@@ -3675,8 +3653,8 @@ void StressTest::Open(SharedState* shared, bool reopen) {
"Compaction\n");
exit(1);
}
options_.compaction_service = std::make_shared<DbStressCompactionService>(
shared, FLAGS_remote_compaction_failure_fall_back_to_local);
options_.compaction_service =
std::make_shared<DbStressCompactionService>(shared);
}
if ((options_.enable_blob_files || options_.enable_blob_garbage_collection ||
@@ -3952,8 +3930,6 @@ void StressTest::Open(SharedState* shared, bool reopen) {
static_cast<size_t>(FLAGS_wp_snapshot_cache_bits);
txn_db_options.wp_commit_cache_bits =
static_cast<size_t>(FLAGS_wp_commit_cache_bits);
txn_db_options.use_per_key_point_lock_mgr =
FLAGS_use_per_key_point_lock_mgr;
PrepareTxnDbOptions(shared, txn_db_options);
s = TransactionDB::Open(options_, txn_db_options, FLAGS_db,
cf_descriptors, &column_families_, &txn_db_);
@@ -3978,13 +3954,6 @@ void StressTest::Open(SharedState* shared, bool reopen) {
assert(s.ok());
assert(column_families_.size() ==
static_cast<size_t>(FLAGS_column_families));
// Clear statistics reference from options_ to intentionally shorten the
// statistics object lifetime to be same as the db object (which is the
// common case in practice) and detect if RocksDB access the statistics
// beyond its lifetime.
if (FLAGS_statistics) {
options_.statistics.reset();
}
// Secondary instance does not support write-prepared/write-unprepared
// transactions, thus just disable secondary instance if we use
@@ -4359,9 +4328,7 @@ void InitializeOptionsFromFlags(
}
}
options.max_open_files = FLAGS_open_files;
if (FLAGS_statistics) {
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
}
options.statistics = dbstats;
options.env = db_stress_env;
options.use_fsync = FLAGS_use_fsync;
options.compaction_readahead_size = FLAGS_compaction_readahead_size;
@@ -4443,8 +4410,6 @@ void InitializeOptionsFromFlags(
FLAGS_memtable_protection_bytes_per_key;
options.block_protection_bytes_per_key = FLAGS_block_protection_bytes_per_key;
options.paranoid_memory_checks = FLAGS_paranoid_memory_checks;
options.memtable_veirfy_per_key_checksum_on_seek =
FLAGS_memtable_veirfy_per_key_checksum_on_seek;
// Integrated BlobDB
options.enable_blob_files = FLAGS_enable_blob_files;
@@ -4613,8 +4578,8 @@ void InitializeOptionsGeneral(
options.create_missing_column_families = true;
options.create_if_missing = true;
if (FLAGS_statistics) {
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
if (!options.statistics) {
options.statistics = dbstats;
}
if (options.env == Options().env) {
@@ -4687,16 +4652,6 @@ void InitializeOptionsGeneral(
if (sqfc_factory && !sqfc_factory->GetConfigs().IsEmptyNotFound()) {
options.table_properties_collector_factories.emplace_back(sqfc_factory);
}
// Add CompactOnDeletionCollectorFactory if enabled
if (FLAGS_enable_compaction_on_deletion_trigger) {
options.table_properties_collector_factories.emplace_back(
ROCKSDB_NAMESPACE::NewCompactOnDeletionCollectorFactory(
FLAGS_compaction_on_deletion_window_size,
FLAGS_compaction_on_deletion_trigger_count,
FLAGS_compaction_on_deletion_ratio,
FLAGS_compaction_on_deletion_min_file_size));
}
}
} // namespace ROCKSDB_NAMESPACE
+6
View File
@@ -53,6 +53,12 @@ int db_stress_tool(int argc, char** argv) {
SetupSyncPointsToMockDirectIO();
}
#endif
if (FLAGS_statistics) {
dbstats = ROCKSDB_NAMESPACE::CreateDBStatistics();
if (FLAGS_test_secondary) {
dbstats_secondaries = ROCKSDB_NAMESPACE::CreateDBStatistics();
}
}
compression_type_e = StringToCompressionType(FLAGS_compression_type.c_str());
bottommost_compression_type_e =
StringToCompressionType(FLAGS_bottommost_compression_type.c_str());
+2 -18
View File
@@ -3156,15 +3156,13 @@ class NonBatchedOpsStressTest : public StressTest {
Status s;
ExpectedValue new_expected_value;
switch (op) {
case Op::PutOrPutEntity:
case Op::Merge: {
ExpectedValue put_value;
put_value.SyncPut(static_cast<uint32_t>(thread->rand.Uniform(
static_cast<int>(ExpectedValue::GetValueBaseMask()))));
new_expected_value = put_value;
ryw_expected_values[k] = put_value;
const uint32_t value_base = put_value.GetValueBase();
@@ -3188,7 +3186,7 @@ class NonBatchedOpsStressTest : public StressTest {
case Op::Delete: {
ExpectedValue delete_value;
delete_value.SyncDelete();
new_expected_value = delete_value;
ryw_expected_values[k] = delete_value;
s = txn->Delete(cfh, k);
break;
@@ -3197,20 +3195,6 @@ class NonBatchedOpsStressTest : public StressTest {
assert(false);
}
// It is possible that multiple thread concurrently try to write to the
// same key, which could cause lock timeout or deadlock in the
// transactiondb layer, before transaction is rolled back.
// E.g.
// Timestamp 1: Transaction A: lock key M for write
// Timestamp 2: Transaction B: lock key N for write
// Timestamp 3: Transaction B: try to lock key M for write -> wait
// Timestamp 4: Transaction A: try to lock key N for write -> deadlock
if (s.IsTimedOut() || s.IsDeadlock()) {
return;
}
ryw_expected_values[k] = new_expected_value;
if (!s.ok()) {
fprintf(stderr,
"Transaction write error in read-your-own-write test: %s\n",
Vendored
-12
View File
@@ -9,7 +9,6 @@
#include "rocksdb/env.h"
#include <sstream>
#include <thread>
#include "env/composite_env_wrapper.h"
@@ -763,17 +762,6 @@ std::string Env::IOActivityToString(IOActivity activity) {
return "GetFileChecksumsFromCurrentManifest";
case Env::IOActivity::kUnknown:
return "Unknown";
default:
int activityIndex = static_cast<int>(activity);
if (activityIndex >=
static_cast<int>(Env::IOActivity::kFirstCustomIOActivity) &&
activityIndex <=
static_cast<int>(Env::IOActivity::kLastCustomIOActivity)) {
std::stringstream ss;
ss << std::hex << std::uppercase << activityIndex;
return "CustomIOActivity" + ss.str();
}
return "Invalid";
};
assert(false);
return "Invalid";
-18
View File
@@ -3692,24 +3692,6 @@ TEST_F(TestGetFileSize, GetFileSize) {
ASSERT_EQ(fileSizeFromFsRandomAccessFileAPI, expectedFileSize);
}
class TestIOActivity : public testing::Test {
public:
TestIOActivity() {}
};
TEST_F(TestIOActivity, IOActivityToString) {
ASSERT_EQ(Env::IOActivityToString(Env::IOActivity::kMultiGet), "MultiGet");
ASSERT_EQ(Env::IOActivityToString(Env::IOActivity::kCustomIOActivity80),
"CustomIOActivity80");
ASSERT_EQ(Env::IOActivityToString(Env::IOActivity::kCustomIOActivityA9),
"CustomIOActivityA9");
ASSERT_EQ(Env::IOActivityToString(Env::IOActivity::kCustomIOActivityFE),
"CustomIOActivityFE");
ASSERT_EQ(Env::IOActivityToString(Env::IOActivity::kUnknown), "Unknown");
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
-2
View File
@@ -355,11 +355,9 @@ IOStatus FSRandomAccessFileTracingWrapper::ReadAsync(
IOStatus s = target()->ReadAsync(req, opts, read_async_callback,
read_async_cb_info, io_handle, del_fn, dbg);
#ifndef __clang_analyzer__
if (!s.ok()) {
delete read_async_cb_info;
}
#endif // __clang_analyzer__
return s;
}
+1 -1
View File
@@ -1153,7 +1153,7 @@ class PosixFileSystem : public FileSystem {
return IOStatus::OK();
#else
(void)io_handles;
return IOStatus::NotSupported("Poll not implemented");
return IOStatus::NotSupported("Poll");
#endif
}
+2 -4
View File
@@ -935,8 +935,7 @@ IOStatus PosixRandomAccessFile::ReadAsync(
// Init failed, platform doesn't support io_uring.
if (iu == nullptr) {
fprintf(stderr, "failed to init io_uring\n");
return IOStatus::NotSupported("ReadAsync: failed to init io_uring");
return IOStatus::NotSupported("ReadAsync");
}
// Allocate io_handle.
@@ -979,8 +978,7 @@ IOStatus PosixRandomAccessFile::ReadAsync(
(void)cb_arg;
(void)io_handle;
(void)del_fn;
return IOStatus::NotSupported(
"ReadAsync: ROCKSDB_IOURING_PRESENT is not set");
return IOStatus::NotSupported("ReadAsync");
#endif
}
+9 -9
View File
@@ -19,16 +19,16 @@ CFLAGS += -Wstrict-prototypes
all: simple_example column_families_example compact_files_example c_simple_example optimistic_transaction_example transaction_example compaction_filter_example options_file_example rocksdb_backup_restore_example
simple_example: librocksdb simple_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
column_families_example: librocksdb column_families_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
compaction_filter_example: librocksdb compaction_filter_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
compact_files_example: librocksdb compact_files_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@ -I../include
@@ -37,19 +37,19 @@ c_simple_example: librocksdb c_simple_example.o
$(CXX) $@.o -o$@ ../librocksdb.a $(PLATFORM_LDFLAGS) $(EXEC_LDFLAGS)
optimistic_transaction_example: librocksdb optimistic_transaction_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
transaction_example: librocksdb transaction_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
options_file_example: librocksdb options_file_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
multi_processes_example: librocksdb multi_processes_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
rocksdb_backup_restore_example: librocksdb rocksdb_backup_restore_example.cc
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++20 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++17 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
clean:
rm -rf ./simple_example ./column_families_example ./compact_files_example ./compaction_filter_example ./c_simple_example c_simple_example.o ./optimistic_transaction_example ./transaction_example ./options_file_example ./multi_processes_example ./rocksdb_backup_restore_example
-19
View File
@@ -80,24 +80,12 @@ inline void RecordIOStats(Statistics* stats, Temperature file_temperature,
RecordTick(stats, WARM_FILE_READ_BYTES, size);
RecordTick(stats, WARM_FILE_READ_COUNT, 1);
break;
case Temperature::kCool:
IOSTATS_ADD(file_io_stats_by_temperature.cool_file_bytes_read, size);
IOSTATS_ADD(file_io_stats_by_temperature.cool_file_read_count, 1);
RecordTick(stats, COOL_FILE_READ_BYTES, size);
RecordTick(stats, COOL_FILE_READ_COUNT, 1);
break;
case Temperature::kCold:
IOSTATS_ADD(file_io_stats_by_temperature.cold_file_bytes_read, size);
IOSTATS_ADD(file_io_stats_by_temperature.cold_file_read_count, 1);
RecordTick(stats, COLD_FILE_READ_BYTES, size);
RecordTick(stats, COLD_FILE_READ_COUNT, 1);
break;
case Temperature::kIce:
IOSTATS_ADD(file_io_stats_by_temperature.ice_file_bytes_read, size);
IOSTATS_ADD(file_io_stats_by_temperature.ice_file_read_count, 1);
RecordTick(stats, ICE_FILE_READ_BYTES, size);
RecordTick(stats, ICE_FILE_READ_COUNT, 1);
break;
default:
break;
}
@@ -503,13 +491,6 @@ IOStatus RandomAccessFileReader::PrepareIOOptions(const ReadOptions& ro,
}
}
// Notes for when direct_io is enabled:
// Unless req.offset, req.len, req.scratch are all already aligned,
// RandomAccessFileReader will creats aligned requests and aligned buffer for
// the request. User should only provide either req.scratch or aligned_buf. If
// only req.scratch is provided, result will be copied from allocated aligned
// buffer to req.scratch. If only alignd_buf is provided, it will be set to
// the ailgned buf allocated by RandomAccessFileReader and saves a copy.
IOStatus RandomAccessFileReader::ReadAsync(
FSReadRequest& req, const IOOptions& opts,
std::function<void(FSReadRequest&, void*)> cb, void* cb_arg,
+8 -14
View File
@@ -64,7 +64,9 @@ enum CompactionPri : char {
struct FileTemperatureAge {
Temperature temperature = Temperature::kUnknown;
uint64_t age = 0;
#if __cplusplus >= 202002L
bool operator==(const FileTemperatureAge& rhs) const = default;
#endif
};
struct CompactionOptionsFIFO {
@@ -133,7 +135,9 @@ struct CompactionOptionsFIFO {
: max_table_files_size(_max_table_files_size),
allow_compaction(_allow_compaction) {}
#if __cplusplus >= 202002L
bool operator==(const CompactionOptionsFIFO& rhs) const = default;
#endif
};
// The control option of how the cache tiers will be used. Currently rocksdb
@@ -1101,22 +1105,12 @@ struct AdvancedColumnFamilyOptions {
uint32_t bottommost_file_compaction_delay = 0;
// Enables additional integrity checks during reads/scans.
// Specifically, for skiplist-based memtables, key ordering validation could
// be enabled optionally. This is helpful to detect corrupted memtable keys
// during reads. Enabling this feature incurs a performance overhead due to
// additional comparison during memtable lookup.
// Specifically, for skiplist-based memtables, we verify that keys visited
// are in order. This is helpful to detect corrupted memtable keys during
// reads. Enabling this feature incurs a performance overhead due to an
// additional key comparison during memtable lookup.
bool paranoid_memory_checks = false;
// Enables additional integrity checks during seek.
// Specifically, for skiplist-based memtables, key checksum validation could
// be enabled during seek optionally. This is helpful to detect corrupted
// memtable keys during reads. Enabling this feature incurs a performance
// overhead due to additional key checksum validation during memtable seek
// operation.
// This option depends on memtable_protection_bytes_per_key to be non zero.
// If memtable_protection_bytes_per_key is zero, no validation is performed.
bool memtable_veirfy_per_key_checksum_on_seek = false;
// When an iterator scans this number of invisible entries (tombstones or
// hidden puts) from the active memtable during a single iterator operation,
// we will attempt to flush the memtable. Currently only forward scans are
-85
View File
@@ -113,15 +113,10 @@ typedef struct rocksdb_writebatch_wi_t rocksdb_writebatch_wi_t;
typedef struct rocksdb_writeoptions_t rocksdb_writeoptions_t;
typedef struct rocksdb_universal_compaction_options_t
rocksdb_universal_compaction_options_t;
typedef struct rocksdb_livefile_t rocksdb_livefile_t;
typedef struct rocksdb_livefiles_t rocksdb_livefiles_t;
typedef struct rocksdb_column_family_handle_t rocksdb_column_family_handle_t;
typedef struct rocksdb_column_family_metadata_t
rocksdb_column_family_metadata_t;
typedef struct rocksdb_import_column_family_options_t
rocksdb_import_column_family_options_t;
typedef struct rocksdb_export_import_files_metadata_t
rocksdb_export_import_files_metadata_t;
typedef struct rocksdb_level_metadata_t rocksdb_level_metadata_t;
typedef struct rocksdb_sst_file_metadata_t rocksdb_sst_file_metadata_t;
typedef struct rocksdb_envoptions_t rocksdb_envoptions_t;
@@ -382,12 +377,6 @@ extern ROCKSDB_LIBRARY_API void rocksdb_checkpoint_create(
rocksdb_checkpoint_t* checkpoint, const char* checkpoint_dir,
uint64_t log_size_for_flush, char** errptr);
extern ROCKSDB_LIBRARY_API rocksdb_export_import_files_metadata_t*
rocksdb_checkpoint_export_column_family(
rocksdb_checkpoint_t* checkpoint,
rocksdb_column_family_handle_t* column_family, const char* export_dir,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_checkpoint_object_destroy(
rocksdb_checkpoint_t* checkpoint);
@@ -448,13 +437,6 @@ rocksdb_create_column_families(rocksdb_t* db,
extern ROCKSDB_LIBRARY_API void rocksdb_create_column_families_destroy(
rocksdb_column_family_handle_t** list);
extern ROCKSDB_LIBRARY_API rocksdb_column_family_handle_t*
rocksdb_create_column_family_with_import(
rocksdb_t* db, rocksdb_options_t* column_family_options,
const char* column_family_name,
rocksdb_import_column_family_options_t* import_options,
rocksdb_export_import_files_metadata_t* metadata, char** errptr);
extern ROCKSDB_LIBRARY_API rocksdb_column_family_handle_t*
rocksdb_create_column_family_with_ttl(
rocksdb_t* db, const rocksdb_options_t* column_family_options,
@@ -2699,16 +2681,12 @@ rocksdb_fifo_compaction_options_get_max_table_files_size(
extern ROCKSDB_LIBRARY_API void rocksdb_fifo_compaction_options_destroy(
rocksdb_fifo_compaction_options_t* fifo_opts);
extern ROCKSDB_LIBRARY_API rocksdb_livefiles_t* rocksdb_livefiles_create(void);
extern ROCKSDB_LIBRARY_API int rocksdb_livefiles_count(
const rocksdb_livefiles_t*);
extern ROCKSDB_LIBRARY_API const char* rocksdb_livefiles_column_family_name(
const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API const char* rocksdb_livefiles_name(
const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API const char* rocksdb_livefiles_directory(
const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API int rocksdb_livefiles_level(
const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API size_t
@@ -2718,44 +2696,12 @@ extern ROCKSDB_LIBRARY_API const char* rocksdb_livefiles_smallestkey(
extern ROCKSDB_LIBRARY_API const char* rocksdb_livefiles_largestkey(
const rocksdb_livefiles_t*, int index, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_livefiles_smallest_seqno(const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_livefiles_largest_seqno(const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_livefiles_entries(const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_livefiles_deletions(const rocksdb_livefiles_t*, int index);
extern ROCKSDB_LIBRARY_API void rocksdb_livefiles_destroy(
const rocksdb_livefiles_t*);
extern ROCKSDB_LIBRARY_API rocksdb_livefile_t* rocksdb_livefile_create(void);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_column_family_name(
rocksdb_livefile_t*, const char*);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_level(rocksdb_livefile_t*,
int);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_name(rocksdb_livefile_t*,
const char*);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_directory(
rocksdb_livefile_t*, const char*);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_size(rocksdb_livefile_t*,
size_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_smallest_key(
rocksdb_livefile_t*, const char*, size_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_largest_key(
rocksdb_livefile_t*, const char*, size_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_smallest_seqno(
rocksdb_livefile_t*, uint64_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_largest_seqno(
rocksdb_livefile_t*, uint64_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_num_entries(
rocksdb_livefile_t*, uint64_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_set_num_deletions(
rocksdb_livefile_t*, uint64_t);
extern ROCKSDB_LIBRARY_API void rocksdb_livefile_destroy(rocksdb_livefile_t*);
extern ROCKSDB_LIBRARY_API void rocksdb_livefiles_add(rocksdb_livefiles_t*,
rocksdb_livefile_t*);
/* Utility Helpers */
extern ROCKSDB_LIBRARY_API void rocksdb_get_options_from_string(
@@ -2776,37 +2722,6 @@ extern ROCKSDB_LIBRARY_API void rocksdb_delete_file_in_range_cf(
extern ROCKSDB_LIBRARY_API rocksdb_column_family_metadata_t*
rocksdb_get_column_family_metadata(rocksdb_t* db);
extern ROCKSDB_LIBRARY_API rocksdb_import_column_family_options_t*
rocksdb_import_column_family_options_create(void);
extern ROCKSDB_LIBRARY_API void
rocksdb_import_column_family_options_set_move_files(
rocksdb_import_column_family_options_t*, unsigned char);
extern ROCKSDB_LIBRARY_API void rocksdb_import_column_family_options_destroy(
rocksdb_import_column_family_options_t*);
extern ROCKSDB_LIBRARY_API rocksdb_export_import_files_metadata_t*
rocksdb_export_import_files_metadata_create(void);
extern ROCKSDB_LIBRARY_API char*
rocksdb_export_import_files_metadata_get_db_comparator_name(
rocksdb_export_import_files_metadata_t*);
extern ROCKSDB_LIBRARY_API void
rocksdb_export_import_files_metadata_set_db_comparator_name(
rocksdb_export_import_files_metadata_t*, const char*);
extern ROCKSDB_LIBRARY_API rocksdb_livefiles_t*
rocksdb_export_import_files_metadata_get_files(
rocksdb_export_import_files_metadata_t*);
extern ROCKSDB_LIBRARY_API void rocksdb_export_import_files_metadata_set_files(
rocksdb_export_import_files_metadata_t*, rocksdb_livefiles_t*);
extern ROCKSDB_LIBRARY_API void rocksdb_export_import_files_metadata_destroy(
rocksdb_export_import_files_metadata_t*);
/**
* Returns the rocksdb_column_family_metadata_t of the specified
* column family.
+49 -43
View File
@@ -210,15 +210,7 @@ struct ShardedCacheOptions {
// shard has its own LRU list for evictions. Each shard also has a mutex for
// exclusive access during operations; even read operations need exclusive
// access in order to update the LRU list. Mutex contention is usually low
// with enough shards. However,
// * For a single hot block, there will be mutex contention even for reads
// regardless of the number of shards.
// * LRUCaches in the size of MBs instead of GBs can have shards small enough
// that there is a random probability of some modest number of large blocks
// (especially non-partitioned filters) thrashing a single cache shard.
//
// HYPERCLOCKCACHE IS NOW GENERALLY RECOMMENDED OVER LRUCACHE. See
// HyperClockCacheOptions below.
// with enough shards.
struct LRUCacheOptions : public ShardedCacheOptions {
// Ratio of cache reserved for high-priority and low-priority entries,
// respectively. (See Cache::Priority below more information on the levels.)
@@ -379,50 +371,64 @@ inline std::shared_ptr<SecondaryCache> NewCompressedSecondaryCache(
return opts.MakeSharedSecondaryCache();
}
// HyperClockCache (also known as HCC) - A lock-free Cache alternative for
// RocksDB block cache that offers much improved CPU efficiency vs. LRUCache
// under high parallel load or high contention. Additionally, HCC only uses
// sharding for a modest performance boost, so can use much larger cache shards
// than LRUCache, dramatically reducing the risk of thrashing in configurations
// or work loads with some large blocks.
//
// HYPERCLOCKCACHE IS NOW GENERALLY RECOMMENDED OVER LRUCACHE
//
// Some caveats:
// HyperClockCache - A lock-free Cache alternative for RocksDB block cache
// that offers much improved CPU efficiency vs. LRUCache under high parallel
// load or high contention, with some caveats:
// * Not a general Cache implementation: can only be used for
// BlockBasedTableOptions::block_cache, which RocksDB uses in a way that is
// compatible with HyperClockCache.
// * Requires an extra tuning parameter: see estimated_entry_charge below.
// Similarly, substantially changing the capacity with SetCapacity could
// harm efficiency. -> EXPERIMENTAL: the tuning parameter can be set to 0
// to find the appropriate balance automatically.
// * Cache priorities are less aggressively enforced, which could cause
// cache dilution from long range scans (unless they use fill_cache=false).
// * In some configurations, depends on anonymous mmap support, available in
// Linux, Windows and more.
// * May have slightly lower (or slightly higher) cache hit rate vs. LRUCache,
// because of the bounded counting-CLOCK eviction algorithm.
//
// See internal cache/clock_cache.h for full description.
struct HyperClockCacheOptions : public ShardedCacheOptions {
// OPTIONAL: The estimated average `charge` associated with cache entries.
// The estimated average `charge` associated with cache entries.
//
// When not provided (== 0, recommended and default), an HCC variant with a
// dynamically-growing table and generally good performance is used. This
// variant depends on anonymous mmaps so might not be available on all
// platforms.
// EXPERIMENTAL: the field can be set to 0 to size the table dynamically
// and automatically. See also min_avg_entry_charge. This feature requires
// platform support for lazy anonymous memory mappings (incl Linux, Windows).
// Performance is very similar to choosing the best configuration parameter.
//
// If the average "charge" (uncompressed block size) of block cache entries
// is reasonably predicted and provided here, the most efficient variant of
// HCC is used. Performance is degraded if the prediction is inaccurate.
// Prediction could be difficult or impossible with cache-charging features
// such as WriteBufferManager. The best parameter choice based on a cache
// in use is roughly given by GetUsage() / GetOccupancyCount(), though it is
// better to estimate toward the lower side than the higher side when the
// ratio might vary.
// PRODUCTION-TESTED: This is a critical configuration parameter for good
// performance, because having a table size that is fixed at creation time
// greatly reduces the required synchronization between threads.
// * If the estimate is substantially too low (e.g. less than half the true
// average) then metadata space overhead with be substantially higher (e.g.
// 200 bytes per entry rather than 100). With kFullChargeCacheMetadata, this
// can slightly reduce cache hit rates, and slightly reduce access times due
// to the larger working memory size.
// * If the estimate is substantially too high (e.g. 25% higher than the true
// average) then there might not be sufficient slots in the hash table for
// both efficient operation and capacity utilization (hit rate). The hyper
// cache will evict entries to prevent load factors that could dramatically
// affect lookup times, instead letting the hit rate suffer by not utilizing
// the full capacity.
//
// A reasonable choice is the larger of block_size and metadata_block_size.
// When WriteBufferManager (and similar) charge memory usage to the block
// cache, this can lead to the same effect as estimate being too low, which
// is better than the opposite. Therefore, the general recommendation is to
// assume that other memory charged to block cache could be negligible, and
// ignore it in making the estimate.
//
// The best parameter choice based on a cache in use is given by
// GetUsage() / GetOccupancyCount(), ignoring metadata overheads such as
// with kDontChargeCacheMetadata. More precisely with
// kFullChargeCacheMetadata is (GetUsage() - 64 * GetTableAddressCount()) /
// GetOccupancyCount(). However, when the average value size might vary
// (e.g. balance between metadata and data blocks in cache), it is better
// to estimate toward the lower side than the higher side.
size_t estimated_entry_charge;
// When estimated_entry_charge == 0, this parameter establishes a promised
// lower bound on the average charge of all entries in the table, which is
// roughly the average uncompressed SST block size of block cache entries,
// typically > 4KB. The default should generally suffice with almost no cost.
// (This option is ignored for estimated_entry_charge > 0.)
// EXPERIMENTAL: When estimated_entry_charge == 0, this parameter establishes
// a promised lower bound on the average charge of all entries in the table,
// which is roughly the average uncompressed SST block size of block cache
// entries, typically > 4KB. The default should generally suffice with almost
// no cost. (This option is ignored for estimated_entry_charge > 0.)
//
// More detail: The table for indexing cache entries will grow automatically
// as needed, but a hard upper bound on that size is needed at creation time.
@@ -472,8 +478,8 @@ struct HyperClockCacheOptions : public ShardedCacheOptions {
// keep operations very fast.
int eviction_effort_cap = 30;
explicit HyperClockCacheOptions(
size_t _capacity, size_t _estimated_entry_charge = 0,
HyperClockCacheOptions(
size_t _capacity, size_t _estimated_entry_charge,
int _num_shard_bits = -1, bool _strict_capacity_limit = false,
std::shared_ptr<MemoryAllocator> _memory_allocator = nullptr,
CacheMetadataChargePolicy _metadata_charge_policy =
+3 -4
View File
@@ -24,10 +24,9 @@ struct CompactionJobStats {
// the elapsed CPU time of this compaction in microseconds.
uint64_t cpu_micros = 0;
// True if `num_input_records` is accurate across all subcompactions.
// See CompactionIterator::must_count_input_entries for some implementation
// details why `num_input_records` may not be accurate.
bool has_accurate_num_input_records = true;
// Used internally indicating whether a subcompaction's
// `num_input_records` is accurate.
bool has_num_input_records = false;
// the number of compaction input records.
uint64_t num_input_records = 0;
// the number of blobs read from blob files
+6 -8
View File
@@ -226,15 +226,11 @@ struct CompressionOptions {
// The training data will be used to generate a dictionary of max_dict_bytes.
uint32_t zstd_max_train_bytes = 0;
// Number of threads for parallel compression for each running flush or
// compaction job. Parallel compression is enabled only if threads > 1. Not
// recommended for lightweight compression algorithms such as Snappy, LZ4, and
// obviously kNoCompression because there is unlikely to be a throughput gain.
// Number of threads for parallel compression.
// Parallel compression is enabled only if threads > 1.
// THE FEATURE IS STILL EXPERIMENTAL
//
// This option is valid only when BlockBasedTable is used and is disabled
// (sanitized to 1) with any of these:
// * User-defined index (UserDefinedIndexFactory)
// * partition_filters == true && decouple_partitioned_filters == false
// This option is valid only when BlockBasedTable is used.
//
// When parallel compression is enabled, SST size file sizes might be
// more inflated compared to the target size, because more data of unknown
@@ -313,7 +309,9 @@ struct CompressionOptions {
max_compressed_bytes_per_kb = static_cast<int>(1024.0 / min_ratio + 0.5);
}
#if __cplusplus >= 202002L
bool operator==(const CompressionOptions& rhs) const = default;
#endif
};
// See advanced_compression.h
+9 -6
View File
@@ -1118,11 +1118,11 @@ class DB {
// // Check ex.what()
// }
virtual std::unique_ptr<MultiScan> NewMultiScan(
const ReadOptions& /*options*/, ColumnFamilyHandle* column_family,
const ReadOptions& /*options*/, ColumnFamilyHandle* /*column_family*/,
const MultiScanArgs& /*scan_opts*/) {
std::unique_ptr<Iterator> iter(NewErrorIterator(Status::NotSupported()));
std::unique_ptr<MultiScan> ms_iter = std::make_unique<MultiScan>(
column_family->GetComparator(), std::move(iter));
std::unique_ptr<MultiScan> ms_iter =
std::make_unique<MultiScan>(std::move(iter));
return ms_iter;
}
@@ -2247,9 +2247,12 @@ inline Status DB::GetApproximateSizes(ColumnFamilyHandle* column_family,
uint64_t* sizes,
SizeApproximationFlags include_flags) {
SizeApproximationOptions options;
using enum SizeApproximationFlags; // Require C++20 support
options.include_memtables = ((include_flags & INCLUDE_MEMTABLES) != NONE);
options.include_files = ((include_flags & INCLUDE_FILES) != NONE);
options.include_memtables =
((include_flags & SizeApproximationFlags::INCLUDE_MEMTABLES) !=
SizeApproximationFlags::NONE);
options.include_files =
((include_flags & SizeApproximationFlags::INCLUDE_FILES) !=
SizeApproximationFlags::NONE);
return GetApproximateSizes(options, column_family, ranges, n, sizes);
}
+1 -135
View File
@@ -456,141 +456,7 @@ class Env : public Customizable {
kGetEntity = 8,
kMultiGetEntity = 9,
kGetFileChecksumsFromCurrentManifest = 10,
// Enums after this, up to 0x7F, are reserved for future use for the public
// RocksDB API (i.e. they should be "non-custom" IO activities). Make sure
// to also update IOActivityToString when adding new values.
kCustomIOActivity80 = 0x80,
kFirstCustomIOActivity = kCustomIOActivity80,
kCustomIOActivity81 = 0x81,
kCustomIOActivity82 = 0x82,
kCustomIOActivity83 = 0x83,
kCustomIOActivity84 = 0x84,
kCustomIOActivity85 = 0x85,
kCustomIOActivity86 = 0x86,
kCustomIOActivity87 = 0x87,
kCustomIOActivity88 = 0x88,
kCustomIOActivity89 = 0x89,
kCustomIOActivity8A = 0x8A,
kCustomIOActivity8B = 0x8B,
kCustomIOActivity8C = 0x8C,
kCustomIOActivity8D = 0x8D,
kCustomIOActivity8E = 0x8E,
kCustomIOActivity8F = 0x8F,
kCustomIOActivity90 = 0x90,
kCustomIOActivity91 = 0x91,
kCustomIOActivity92 = 0x92,
kCustomIOActivity93 = 0x93,
kCustomIOActivity94 = 0x94,
kCustomIOActivity95 = 0x95,
kCustomIOActivity96 = 0x96,
kCustomIOActivity97 = 0x97,
kCustomIOActivity98 = 0x98,
kCustomIOActivity99 = 0x99,
kCustomIOActivity9A = 0x9A,
kCustomIOActivity9B = 0x9B,
kCustomIOActivity9C = 0x9C,
kCustomIOActivity9D = 0x9D,
kCustomIOActivity9E = 0x9E,
kCustomIOActivity9F = 0x9F,
kCustomIOActivityA0 = 0xA0,
kCustomIOActivityA1 = 0xA1,
kCustomIOActivityA2 = 0xA2,
kCustomIOActivityA3 = 0xA3,
kCustomIOActivityA4 = 0xA4,
kCustomIOActivityA5 = 0xA5,
kCustomIOActivityA6 = 0xA6,
kCustomIOActivityA7 = 0xA7,
kCustomIOActivityA8 = 0xA8,
kCustomIOActivityA9 = 0xA9,
kCustomIOActivityAA = 0xAA,
kCustomIOActivityAB = 0xAB,
kCustomIOActivityAC = 0xAC,
kCustomIOActivityAD = 0xAD,
kCustomIOActivityAE = 0xAE,
kCustomIOActivityAF = 0xAF,
kCustomIOActivityB0 = 0xB0,
kCustomIOActivityB1 = 0xB1,
kCustomIOActivityB2 = 0xB2,
kCustomIOActivityB3 = 0xB3,
kCustomIOActivityB4 = 0xB4,
kCustomIOActivityB5 = 0xB5,
kCustomIOActivityB6 = 0xB6,
kCustomIOActivityB7 = 0xB7,
kCustomIOActivityB8 = 0xB8,
kCustomIOActivityB9 = 0xB9,
kCustomIOActivityBA = 0xBA,
kCustomIOActivityBB = 0xBB,
kCustomIOActivityBC = 0xBC,
kCustomIOActivityBD = 0xBD,
kCustomIOActivityBE = 0xBE,
kCustomIOActivityBF = 0xBF,
kCustomIOActivityC0 = 0xC0,
kCustomIOActivityC1 = 0xC1,
kCustomIOActivityC2 = 0xC2,
kCustomIOActivityC3 = 0xC3,
kCustomIOActivityC4 = 0xC4,
kCustomIOActivityC5 = 0xC5,
kCustomIOActivityC6 = 0xC6,
kCustomIOActivityC7 = 0xC7,
kCustomIOActivityC8 = 0xC8,
kCustomIOActivityC9 = 0xC9,
kCustomIOActivityCA = 0xCA,
kCustomIOActivityCB = 0xCB,
kCustomIOActivityCC = 0xCC,
kCustomIOActivityCD = 0xCD,
kCustomIOActivityCE = 0xCE,
kCustomIOActivityCF = 0xCF,
kCustomIOActivityD0 = 0xD0,
kCustomIOActivityD1 = 0xD1,
kCustomIOActivityD2 = 0xD2,
kCustomIOActivityD3 = 0xD3,
kCustomIOActivityD4 = 0xD4,
kCustomIOActivityD5 = 0xD5,
kCustomIOActivityD6 = 0xD6,
kCustomIOActivityD7 = 0xD7,
kCustomIOActivityD8 = 0xD8,
kCustomIOActivityD9 = 0xD9,
kCustomIOActivityDA = 0xDA,
kCustomIOActivityDB = 0xDB,
kCustomIOActivityDC = 0xDC,
kCustomIOActivityDD = 0xDD,
kCustomIOActivityDE = 0xDE,
kCustomIOActivityDF = 0xDF,
kCustomIOActivityE0 = 0xE0,
kCustomIOActivityE1 = 0xE1,
kCustomIOActivityE2 = 0xE2,
kCustomIOActivityE3 = 0xE3,
kCustomIOActivityE4 = 0xE4,
kCustomIOActivityE5 = 0xE5,
kCustomIOActivityE6 = 0xE6,
kCustomIOActivityE7 = 0xE7,
kCustomIOActivityE8 = 0xE8,
kCustomIOActivityE9 = 0xE9,
kCustomIOActivityEA = 0xEA,
kCustomIOActivityEB = 0xEB,
kCustomIOActivityEC = 0xEC,
kCustomIOActivityED = 0xED,
kCustomIOActivityEE = 0xEE,
kCustomIOActivityEF = 0xEF,
kCustomIOActivityF0 = 0xF0,
kCustomIOActivityF1 = 0xF1,
kCustomIOActivityF2 = 0xF2,
kCustomIOActivityF3 = 0xF3,
kCustomIOActivityF4 = 0xF4,
kCustomIOActivityF5 = 0xF5,
kCustomIOActivityF6 = 0xF6,
kCustomIOActivityF7 = 0xF7,
kCustomIOActivityF8 = 0xF8,
kCustomIOActivityF9 = 0xF9,
kCustomIOActivityFA = 0xFA,
kCustomIOActivityFB = 0xFB,
kCustomIOActivityFC = 0xFC,
kCustomIOActivityFD = 0xFD,
kCustomIOActivityFE = 0xFE,
kLastCustomIOActivity = kCustomIOActivityFE,
kUnknown = 0xFF, // Keep last as unknown
kUnknown, // Keep last for easy array of non-unknowns
};
static std::string IOActivityToString(IOActivity activity);
-5
View File
@@ -24,7 +24,6 @@
#include <functional>
#include <limits>
#include <memory>
#include <shared_mutex>
#include <sstream>
#include <string>
#include <unordered_map>
@@ -255,10 +254,6 @@ struct IODebugContext {
// Arbitrary structure containing cost information about the IO request
std::any cost_info;
// FileSystem implementations can use this mutex to synchronize concurrent
// reads/writes as needed (e.g. to update the counters or cost_info field)
std::shared_mutex mutex;
IODebugContext() {}
// Copy constructor
-12
View File
@@ -32,34 +32,22 @@ struct FileIOByTemperature {
uint64_t hot_file_bytes_read;
// the number of bytes read to Temperature::kWarm file
uint64_t warm_file_bytes_read;
// the number of bytes read to Temperature::kCool file
uint64_t cool_file_bytes_read;
// the number of bytes read to Temperature::kCold file
uint64_t cold_file_bytes_read;
// the number of bytes read to Temperature::kIce file
uint64_t ice_file_bytes_read;
// total number of reads to Temperature::kHot file
uint64_t hot_file_read_count;
// total number of reads to Temperature::kWarm file
uint64_t warm_file_read_count;
// total number of reads to Temperature::kCool file
uint64_t cool_file_read_count;
// total number of reads to Temperature::kCold file
uint64_t cold_file_read_count;
// total number of reads to Temperature::kIce file
uint64_t ice_file_read_count;
// reset all the statistics to 0.
void Reset() {
hot_file_bytes_read = 0;
warm_file_bytes_read = 0;
cool_file_bytes_read = 0;
cold_file_bytes_read = 0;
ice_file_bytes_read = 0;
hot_file_read_count = 0;
warm_file_read_count = 0;
cool_file_read_count = 0;
cold_file_read_count = 0;
ice_file_read_count = 0;
}
};
-8
View File
@@ -32,18 +32,10 @@ struct LDBOptions {
class LDBTool {
public:
// DEPRECATED because this function does not return, which can result in
// memory leaks being reported because of the default Options() etc. not being
// destroyed.
void Run(
int argc, char** argv, Options db_options = Options(),
const LDBOptions& ldb_options = LDBOptions(),
const std::vector<ColumnFamilyDescriptor>* column_families = nullptr);
int RunAndReturn(
int argc, char** argv, const Options& db_options = Options(),
const LDBOptions& ldb_options = LDBOptions(),
const std::vector<ColumnFamilyDescriptor>* column_families = nullptr);
};
} // namespace ROCKSDB_NAMESPACE
+8 -12
View File
@@ -38,7 +38,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <functional>
#include <memory>
#include <stdexcept>
#include <unordered_set>
@@ -202,12 +201,11 @@ class MemTableRep {
bool (*callback_func)(void* arg, const char* entry));
// Same as Get() but performs data integrity validation.
virtual Status GetAndValidate(
const LookupKey& /* k */, void* /* callback_args */,
bool (* /* callback_func */)(void* arg, const char* entry),
bool /* allow_data_in_error */, bool /* detect_key_out_of_order */,
const std::function<Status(const char*, bool)>&
/* key_validation_callback */) {
virtual Status GetAndValidate(const LookupKey& /* k */,
void* /* callback_args */,
bool (* /* callback_func */)(void* arg,
const char* entry),
bool /*allow_data_in_error*/) {
return Status::NotSupported("GetAndValidate() not implemented.");
}
@@ -278,11 +276,9 @@ class MemTableRep {
// Seek and perform integrity validations on the skip list.
// Iterator becomes invalid and Corruption is returned if a
// corruption is found.
virtual Status SeekAndValidate(
const Slice& /* internal_key */, const char* /* memtable_key */,
bool /* allow_data_in_errors */, bool /* detect_key_out_of_order */,
const std::function<Status(const char*, bool)>&
/* key_validation_callback */) {
virtual Status SeekAndValidate(const Slice& /* internal_key */,
const char* /* memtable_key */,
bool /* allow_data_in_errors */) {
return Status::NotSupported("SeekAndValidate() not implemented.");
}
+3 -14
View File
@@ -97,13 +97,7 @@ class Scan {
ScanIterator() : db_iter_(nullptr), valid_(false) {}
~ScanIterator() {
if (!status_.ok()) {
fprintf(stderr, "ScanIterator status: %s\n",
status_.ToString().c_str());
assert(false);
}
}
~ScanIterator() { assert(status_.ok()); }
ScanIterator& operator++() {
if (!valid_) {
@@ -161,9 +155,8 @@ class MultiScan {
MultiScan(const ReadOptions& read_options, const MultiScanArgs& scan_opts,
DB* db, ColumnFamilyHandle* cfh);
explicit MultiScan(const Comparator* comp,
std::unique_ptr<Iterator>&& db_iter)
: scan_opts_(comp), db_iter_(std::move(db_iter)) {}
explicit MultiScan(std::unique_ptr<Iterator>&& db_iter)
: db_iter_(std::move(db_iter)) {}
class MultiScanIterator {
public:
@@ -191,10 +184,6 @@ class MultiScan {
if (scan_opts_.empty()) {
throw std::logic_error("Zero scans in multi-scan");
}
status_ = db_iter_->status();
if (!status_.ok()) {
throw MultiScanException(status_);
}
db_iter_->Seek(*scan_opts_[idx_].range.start);
status_ = db_iter_->status();
if (!status_.ok()) {
+3 -22
View File
@@ -623,7 +623,6 @@ struct DBOptions {
// checking for corruption, including
// * paranoid_file_checks
// * paranoid_memory_checks
// * memtable_veirfy_per_key_checksum_on_seek
// * DB::VerifyChecksum()
//
// Default: true
@@ -1783,7 +1782,8 @@ struct ScanOptions {
class MultiScanArgs {
public:
// Constructor that takes a comparator
explicit MultiScanArgs(const Comparator* comparator) : comp_(comparator) {}
explicit MultiScanArgs(const Comparator* comparator = BytewiseComparator())
: comp_(comparator) {}
// Copy Constructor
MultiScanArgs(const MultiScanArgs& other) {
@@ -1791,12 +1791,10 @@ class MultiScanArgs {
original_ranges_ = other.original_ranges_;
io_coalesce_threshold = other.io_coalesce_threshold;
max_prefetch_size = other.max_prefetch_size;
use_async_io = other.use_async_io;
}
MultiScanArgs(MultiScanArgs&& other) noexcept
: io_coalesce_threshold(other.io_coalesce_threshold),
max_prefetch_size(other.max_prefetch_size),
use_async_io(other.use_async_io),
comp_(other.comp_),
original_ranges_(std::move(other.original_ranges_)) {}
@@ -1805,7 +1803,6 @@ class MultiScanArgs {
original_ranges_ = other.original_ranges_;
io_coalesce_threshold = other.io_coalesce_threshold;
max_prefetch_size = other.max_prefetch_size;
use_async_io = other.use_async_io;
return *this;
}
@@ -1815,7 +1812,6 @@ class MultiScanArgs {
original_ranges_ = std::move(other.original_ranges_);
io_coalesce_threshold = other.io_coalesce_threshold;
max_prefetch_size = other.max_prefetch_size;
use_async_io = other.use_async_io;
}
return *this;
}
@@ -1848,23 +1844,13 @@ class MultiScanArgs {
operator std::vector<ScanOptions>*() { return &original_ranges_; }
operator const std::vector<ScanOptions>*() const { return &original_ranges_; }
// Destructor
~MultiScanArgs() {}
const std::vector<ScanOptions>& GetScanRanges() const {
return original_ranges_;
}
const Comparator* GetComparator() const { return comp_; }
// Copies the configurations (excluding actual scan ranges) from another
// MultiScanArgs.
void CopyConfigFrom(const MultiScanArgs& other) {
io_coalesce_threshold = other.io_coalesce_threshold;
max_prefetch_size = other.max_prefetch_size;
use_async_io = other.use_async_io;
}
uint64_t io_coalesce_threshold = 16 << 10; // 16KB by default
// Maximum size (in bytes) for the data blocks loaded by a MultiScan.
@@ -1879,11 +1865,6 @@ class MultiScanArgs {
// Note that this limit is per file and applies to compressed block size.
uint64_t max_prefetch_size = 0;
// Enable async I/O for multi-scan operations
// When true, BlockBasedTableIterator will use ReadAsync() for reading blocks
// When false, it will use synchronous MultiRead().
bool use_async_io = false;
private:
// The comparator used for ordering ranges
const Comparator* comp_;
-14
View File
@@ -1,14 +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 "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
int point_lock_bench_tool(int argc, char** argv);
} // namespace ROCKSDB_NAMESPACE
+1 -1
View File
@@ -24,7 +24,7 @@
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <string_view> // RocksDB now requires C++17 support
#include "rocksdb/cleanable.h"
-4
View File
@@ -443,14 +443,10 @@ enum Tickers : uint32_t {
// Tiered storage related statistics
HOT_FILE_READ_BYTES,
WARM_FILE_READ_BYTES,
COOL_FILE_READ_BYTES,
COLD_FILE_READ_BYTES,
ICE_FILE_READ_BYTES,
HOT_FILE_READ_COUNT,
WARM_FILE_READ_COUNT,
COOL_FILE_READ_COUNT,
COLD_FILE_READ_COUNT,
ICE_FILE_READ_COUNT,
// Last level and non-last level read statistics
LAST_LEVEL_READ_BYTES,
-4
View File
@@ -116,7 +116,6 @@ class Status {
kMergeOperatorFailed = 15,
kMergeOperandThresholdExceeded = 16,
kPrefetchLimitReached = 17,
kNotExpectedCodePath = 18,
kMaxSubCode
};
@@ -330,9 +329,6 @@ class Status {
return code() == kOk;
}
// Assert the status is OK in debug mode
void AssertOK() const { assert(ok()); }
// Returns true iff the status indicates success *with* something
// overwritten
bool IsOkOverwritten() const {
-7
View File
@@ -442,10 +442,6 @@ struct BlockBasedTableOptions {
//
// decouple_partitioned_filters = true is the new default. This option is now
// DEPRECATED and might be ignored and/or removed in a future release.
//
// NOTE: decouple_partitioned_filters = false with partition_filters = true
// disables parallel compression (CompressionOptions::parallel_threads
// sanitized to 1).
bool decouple_partitioned_filters = true;
// Option to generate Bloom/Ribbon filters that minimize memory
@@ -504,9 +500,6 @@ struct BlockBasedTableOptions {
// If non-nullptr, use the specified factory to build user-defined index.
// This allows users to define their own index format and build the index
// during table building.
//
// NOTE: UserDefinedIndexFactory currently disables parallel compression
// (CompressionOptions::parallel_threads sanitized to 1).
std::shared_ptr<UserDefinedIndexFactory> user_defined_index_factory = nullptr;
// EXPERIMENTAL
-11
View File
@@ -76,7 +76,6 @@ struct TablePropertiesNames {
static const std::string kTailStartOffset;
static const std::string kUserDefinedTimestampsPersisted;
static const std::string kKeyLargestSeqno;
static const std::string kKeySmallestSeqno;
};
// `TablePropertiesCollector` provides the mechanism for users to collect
@@ -221,8 +220,6 @@ struct TableProperties {
uint64_t orig_file_number = 0;
// the total size of all data blocks.
uint64_t data_size = 0;
// the total uncompressed size of all data blocks (since RocksDB 10.7)
uint64_t uncompressed_data_size = 0;
// the size of index block.
uint64_t index_size = 0;
// Total number of index partitions if kTwoLevelIndexSearch is used
@@ -312,14 +309,6 @@ struct TableProperties {
bool HasKeyLargestSeqno() const { return key_largest_seqno != UINT64_MAX; }
// The smallest sequence number of keys in this file.
// UINT64_MAX means unknown.
// Only written to properties block if known (should be known unless the
// table is empty).
uint64_t key_smallest_seqno = UINT64_MAX;
bool HasKeySmallestSeqno() const { return key_smallest_seqno != UINT64_MAX; }
// DB identity
// db_id is an identifier generated the first time the DB is created
// If DB identity is unset or unassigned, `db_id` will be an empty string.
-4
View File
@@ -118,11 +118,7 @@ enum class Temperature : uint8_t {
kUnknown = 0,
kHot = 0x04,
kWarm = 0x08,
kCool = 0x0A,
kCold = 0x0C,
kIce = 0x10,
// XXX: this is mis-named. It is instead an invalid temperature beyond the
// rest
kLastTemperature,
};
+2
View File
@@ -144,7 +144,9 @@ class CompactionOptionsUniversal {
incremental(false),
reduce_file_locking(false) {}
#if __cplusplus >= 202002L
bool operator==(const CompactionOptionsUniversal& rhs) const = default;
#endif
};
} // namespace ROCKSDB_NAMESPACE
+2 -21
View File
@@ -30,7 +30,8 @@ inline const std::string kUserDefinedIndexPrefix =
//
// This is currently supported only for a restricted set of use cases. The
// CF must be ingest only, and only files containing Puts generated by
// SstFileWriter are supported.
// SstFileWriter are supported. The user_comparator used for the CF must
// be BytewiseComparator.
// The interface for building user-defined index.
class UserDefinedIndexBuilder {
@@ -144,11 +145,6 @@ class UserDefinedIndexReader {
virtual size_t ApproximateMemoryUsage() const = 0;
};
// Options for user defined index
struct UserDefinedIndexOption {
const Comparator* comparator = BytewiseComparator();
};
// Factory for creating user-defined index builders.
class UserDefinedIndexFactory : public Customizable {
public:
@@ -167,21 +163,6 @@ class UserDefinedIndexFactory : public Customizable {
// block
virtual std::unique_ptr<UserDefinedIndexReader> NewReader(
Slice& index_block) const = 0;
// New API for allowing customized comparator
virtual Status NewBuilder(
const UserDefinedIndexOption& /*option*/,
std::unique_ptr<UserDefinedIndexBuilder>& builder) const {
builder.reset(NewBuilder());
return Status::OK();
};
virtual Status NewReader(
const UserDefinedIndexOption& /*option*/, Slice& index_block,
std::unique_ptr<UserDefinedIndexReader>& reader) const {
reader = NewReader(index_block);
return Status::OK();
};
};
} // namespace ROCKSDB_NAMESPACE
+1 -1
View File
@@ -90,7 +90,7 @@ class CacheDumper {
public:
virtual ~CacheDumper() = default;
// Only dump the blocks in the block cache that belong to the DBs in this list
virtual Status SetDumpFilter(const std::vector<DB*>& db_list) {
virtual Status SetDumpFilter(std::vector<DB*> db_list) {
(void)db_list;
return Status::NotSupported("SetDumpFilter is not supported");
}
+1 -6
View File
@@ -653,12 +653,7 @@ class Transaction {
// Change the value of TransactionOptions.lock_timeout (in milliseconds) for
// this transaction.
// Has no effect on OptimisticTransactions.
virtual void SetLockTimeout(int64_t timeout_ms) = 0;
// Change the value of deadlock_timeout (in milliseconds) for this
// transaction.
// Has no effect on OptimisticTransactions.
virtual void SetDeadlockTimeout(int64_t timeout_ms) = 0;
virtual void SetLockTimeout(int64_t timeout) = 0;
// Return the WriteOptions that will be used during Commit()
virtual WriteOptions* GetWriteOptions() = 0;
@@ -217,11 +217,6 @@ struct TransactionDBOptions {
// Other value means the user provides a custom lock manager.
std::shared_ptr<LockManagerHandle> lock_mgr_handle;
// EXPERIMENTAL
//
// Flag to enable/disable the per key point lock manager.
bool use_per_key_point_lock_mgr = false;
// If true, the TransactionDB implementation might skip concurrency control
// unless it is overridden by TransactionOptions or
// TransactionDBWriteOptimizations. This can be used in conjunction with
@@ -324,22 +319,6 @@ struct TransactionOptions {
// If negative, TransactionDBOptions::transaction_lock_timeout will be used.
int64_t lock_timeout = -1;
// Timeout in microseconds before perform dead lock detection.
// If 0, deadlock detection will be performed immediately.
//
// To optimize performance, this parameter could be tuned.
//
// When deadlock happens very frequently, deadlock timeout should be set to 0,
// so deadlock will be detected immediately.
//
// When deadlock happen very rarely, this timeout could be turned to be
// slightly longer than the typical transaction execution time, so that
// transaction will be waked up to take the lock before this timeout, which
// will allow the transaction to save the CPU time on deadlock detection.
//
// Deadlock timeout is always smaller than lock_timeout.
int64_t deadlock_timeout_us = 500;
// Expiration duration in milliseconds. If non-negative, transactions that
// last longer than this many milliseconds will fail to commit. If not set,
// a forgotten transaction that is never committed, rolled back, or deleted
+2 -2
View File
@@ -12,8 +12,8 @@
// NOTE: in 'main' development branch, this should be the *next*
// minor or major version number planned for release.
#define ROCKSDB_MAJOR 10
#define ROCKSDB_MINOR 7
#define ROCKSDB_PATCH 6
#define ROCKSDB_MINOR 6
#define ROCKSDB_PATCH 2
// Do not use these. We made the mistake of declaring macros starting with
// double underscore. Now we have to live with our choice. We'll deprecate these
-25
View File
@@ -5275,18 +5275,6 @@ class TickerTypeJni {
return -0x57;
case ROCKSDB_NAMESPACE::Tickers::FIFO_CHANGE_TEMPERATURE_COMPACTIONS:
return -0x58;
case ROCKSDB_NAMESPACE::Tickers::ICE_FILE_READ_BYTES:
return -0x59;
case ROCKSDB_NAMESPACE::Tickers::ICE_FILE_READ_COUNT:
return -0x5A;
case ROCKSDB_NAMESPACE::Tickers::COOL_FILE_READ_BYTES:
return -0x5B;
case ROCKSDB_NAMESPACE::Tickers::COOL_FILE_READ_COUNT:
return -0x5C;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_WBWI_INGEST:
return -0x5D;
case ROCKSDB_NAMESPACE::Tickers::SST_USER_DEFINED_INDEX_LOAD_FAIL_COUNT:
return -0x5E;
case ROCKSDB_NAMESPACE::Tickers::TICKER_ENUM_MAX:
// -0x54 is the max value at this time. Since these values are exposed
// directly to Java clients, we'll keep the value the same till the next
@@ -5751,19 +5739,6 @@ class TickerTypeJni {
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT;
case -0x58:
return ROCKSDB_NAMESPACE::Tickers::FIFO_CHANGE_TEMPERATURE_COMPACTIONS;
case -0x59:
return ROCKSDB_NAMESPACE::Tickers::ICE_FILE_READ_BYTES;
case -0x5A:
return ROCKSDB_NAMESPACE::Tickers::ICE_FILE_READ_COUNT;
case -0x5B:
return ROCKSDB_NAMESPACE::Tickers::COOL_FILE_READ_BYTES;
case -0x5C:
return ROCKSDB_NAMESPACE::Tickers::COOL_FILE_READ_COUNT;
case -0x5D:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_WBWI_INGEST;
case -0x5E:
return ROCKSDB_NAMESPACE::Tickers::
SST_USER_DEFINED_INDEX_LOAD_FAIL_COUNT;
case -0x54:
// -0x54 is the max value at this time. Since these values are exposed
// directly to Java clients, we'll keep the value the same till the next
@@ -764,14 +764,10 @@ public enum TickerType {
*/
HOT_FILE_READ_BYTES((byte) -0x31),
WARM_FILE_READ_BYTES((byte) -0x32),
COOL_FILE_READ_BYTES((byte) -0x5B),
COLD_FILE_READ_BYTES((byte) -0x33),
ICE_FILE_READ_BYTES((byte) -0x59),
HOT_FILE_READ_COUNT((byte) -0x34),
WARM_FILE_READ_COUNT((byte) -0x35),
COOL_FILE_READ_COUNT((byte) -0x5C),
COLD_FILE_READ_COUNT((byte) -0x36),
ICE_FILE_READ_COUNT((byte) -0x5A),
/**
* (non-)last level read statistics
@@ -874,8 +870,6 @@ public enum TickerType {
FIFO_TTL_COMPACTIONS((byte) -0x50),
FIFO_CHANGE_TEMPERATURE_COMPACTIONS((byte) -0x58),
PREFETCH_BYTES((byte) -0x51),
PREFETCH_BYTES_USEFUL((byte) -0x52),
@@ -888,19 +882,6 @@ public enum TickerType {
FILE_READ_CORRUPTION_RETRY_SUCCESS_COUNT((byte) -0x57),
/**
* Counter for the number of times a WBWI is ingested into the DB. This
* happens when IngestWriteBatchWithIndex() is used and when large
* transaction optimization is enabled through
* TransactionOptions::large_txn_commit_optimize_threshold.
*/
NUMBER_WBWI_INGEST((byte) -0x5D),
/**
* Failure to load the UDI during SST table open
*/
SST_USER_DEFINED_INDEX_LOAD_FAIL_COUNT((byte) -0x5E),
TICKER_ENUM_MAX((byte) -0x54);
private final byte value;
@@ -217,8 +217,6 @@ public class SstFileReaderTest {
assertThat(iterator.isValid()).isTrue();
assertThat(iterator.key()).isEqualTo("key1".getBytes());
assertThat(iterator.value()).isEqualTo("value1".getBytes());
iterator.close();
}
}
}
+32 -61
View File
@@ -180,11 +180,8 @@ class InlineSkipList {
// Advance to the first entry with a key >= target
void Seek(const char* target);
[[nodiscard]] Status SeekAndValidate(
const char* target, bool allow_data_in_errors,
bool detect_key_out_of_order,
const std::function<Status(const char*, bool)>&
key_validation_callback);
[[nodiscard]] Status SeekAndValidate(const char* target,
bool allow_data_in_errors);
// Retreat to the last entry with a key <= target
void SeekForPrev(const char* target);
@@ -246,23 +243,20 @@ class InlineSkipList {
bool KeyIsAfterNode(const DecodedKey& key, Node* n) const;
// Returns the earliest node with a key >= key.
// Returns OK, if no corruption is found.
// node is set to the found node, or to nullptr if no node is found.
// Returns Corruption if a corruption is found.
Status FindGreaterOrEqual(const char* key, Node** node,
bool detect_key_out_of_order,
bool allow_data_in_errors,
const std::function<Status(const char*, bool)>&
key_validation_callback) const;
// Returns nullptr if there is no such node.
// @param out_of_order_node If not null, will validate the order of visited
// nodes. If a pair of out-of-order nodes n1 and n2 are found, n1 will be
// returned and *out_of_order_node will be set to n2.
Node* FindGreaterOrEqual(const char* key, Node** out_of_order_node) const;
// Returns the latest node with a key < key.
// Returns head_ if there is no such node.
// Fills prev[level] with pointer to previous node at "level" for every
// level in [0..max_height_-1], if prev is non-null.
// @param corrupted_node If not null, will validate the order of visited
// @param out_of_order_node If not null, will validate the order of visited
// nodes. If a pair of out-of-order nodes n1 and n2 are found, n1 will be
// returned and *corrupted_node will be set to n2.
Node* FindLessThan(const char* key, Node** corrupted_node) const;
// returned and *out_of_order_node will be set to n2.
Node* FindLessThan(const char* key, Node** out_of_order_node) const;
// Return the last node in the list.
// Return head_ if list is empty.
@@ -402,12 +396,6 @@ inline const char* InlineSkipList<Comparator>::Iterator::key() const {
template <class Comparator>
inline void InlineSkipList<Comparator>::Iterator::Next() {
assert(Valid());
// Capture the key before move on to next node
TEST_SYNC_POINT_CALLBACK(
"InlineSkipList::Iterator::Next::key",
static_cast<void*>(const_cast<char*>((node_->Key()))));
node_ = node_->Next(0);
}
@@ -415,12 +403,6 @@ template <class Comparator>
inline Status InlineSkipList<Comparator>::Iterator::NextAndValidate(
bool allow_data_in_errors) {
assert(Valid());
// Capture the key before move on to next node
TEST_SYNC_POINT_CALLBACK(
"InlineSkipList::Iterator::Next::key",
static_cast<void*>(const_cast<char*>((node_->Key()))));
Node* prev_node = node_;
node_ = node_->Next(0);
// Verify that keys are increasing.
@@ -450,12 +432,12 @@ inline Status InlineSkipList<Comparator>::Iterator::PrevAndValidate(
const bool allow_data_in_errors) {
assert(Valid());
// Skip list validation is done in FindLessThan().
Node* corrupted_node = nullptr;
node_ = list_->FindLessThan(node_->Key(), &corrupted_node);
if (corrupted_node) {
Node* out_of_order_node = nullptr;
node_ = list_->FindLessThan(node_->Key(), &out_of_order_node);
if (out_of_order_node) {
Node* node = node_;
node_ = nullptr;
return Corruption(node, corrupted_node, allow_data_in_errors);
return Corruption(node, out_of_order_node, allow_data_in_errors);
}
if (node_ == list_->head_) {
node_ = nullptr;
@@ -465,19 +447,20 @@ inline Status InlineSkipList<Comparator>::Iterator::PrevAndValidate(
template <class Comparator>
inline void InlineSkipList<Comparator>::Iterator::Seek(const char* target) {
auto status =
list_->FindGreaterOrEqual(target, &node_, false, false, nullptr);
assert(status.ok());
node_ = list_->FindGreaterOrEqual(target, nullptr);
}
template <class Comparator>
inline Status InlineSkipList<Comparator>::Iterator::SeekAndValidate(
const char* target, const bool allow_data_in_errors,
bool check_key_out_of_order,
const std::function<Status(const char*, bool)>& key_validation_callback) {
return list_->FindGreaterOrEqual(target, &node_, allow_data_in_errors,
check_key_out_of_order,
key_validation_callback);
const char* target, const bool allow_data_in_errors) {
Node* out_of_order_node = nullptr;
node_ = list_->FindGreaterOrEqual(target, &out_of_order_node);
if (out_of_order_node) {
Node* node = node_;
node_ = nullptr;
return Corruption(node, out_of_order_node, allow_data_in_errors);
}
return Status::OK();
}
template <class Comparator>
@@ -544,18 +527,15 @@ bool InlineSkipList<Comparator>::KeyIsAfterNode(const DecodedKey& key,
}
template <class Comparator>
Status InlineSkipList<Comparator>::FindGreaterOrEqual(
const char* key, Node** node, bool allow_data_in_errors,
bool detect_key_out_of_order,
const std::function<Status(const char*, bool)>& key_validation_callback)
const {
typename InlineSkipList<Comparator>::Node*
InlineSkipList<Comparator>::FindGreaterOrEqual(
const char* key, Node** const out_of_order_node) const {
// Note: It looks like we could reduce duplication by implementing
// this function as FindLessThan(key)->Next(0), but we wouldn't be able
// to exit early on equality and the result wouldn't even be correct.
// A concurrent insert might occur after FindLessThan(key) but before
// we get a chance to call Next(0).
Node* x = head_;
*node = nullptr;
int level = GetMaxHeight() - 1;
Node* last_bigger = nullptr;
const DecodedKey key_decoded = compare_.decode_key(key);
@@ -563,16 +543,10 @@ Status InlineSkipList<Comparator>::FindGreaterOrEqual(
Node* next = x->Next(level);
if (next != nullptr) {
PREFETCH(next->Next(level), 0, 1);
if (detect_key_out_of_order && x != head_ &&
if (out_of_order_node && x != head_ &&
compare_(x->Key(), next->Key()) >= 0) {
return Corruption(x, next, allow_data_in_errors);
}
if (key_validation_callback != nullptr) {
auto status =
key_validation_callback(next->Key(), allow_data_in_errors);
if (!status.ok()) {
return status;
}
*out_of_order_node = next;
return x;
}
}
// Make sure the lists are sorted
@@ -583,8 +557,7 @@ Status InlineSkipList<Comparator>::FindGreaterOrEqual(
? 1
: compare_(next->Key(), key_decoded);
if (cmp == 0 || (cmp > 0 && level == 0)) {
*node = next;
return Status::OK();
return next;
} else if (cmp < 0) {
// Keep searching in this list
x = next;
@@ -1140,9 +1113,7 @@ bool InlineSkipList<Comparator>::Insert(const char* key, Splice* splice,
template <class Comparator>
bool InlineSkipList<Comparator>::Contains(const char* key) const {
Node* x = nullptr;
auto status = FindGreaterOrEqual(key, &x, false, false, nullptr);
assert(status.ok());
Node* x = FindGreaterOrEqual(key, nullptr);
if (x != nullptr && Equal(key, x->Key())) {
return true;
} else {
+7 -16
View File
@@ -94,14 +94,11 @@ class SkipListRep : public MemTableRep {
Status GetAndValidate(const LookupKey& k, void* callback_args,
bool (*callback_func)(void* arg, const char* entry),
bool allow_data_in_errors, bool detect_key_out_of_order,
const std::function<Status(const char*, bool)>&
key_validation_callback) override {
bool allow_data_in_errors) override {
SkipListRep::Iterator iter(&skip_list_);
Slice dummy_slice;
Status status = iter.SeekAndValidate(
dummy_slice, k.memtable_key().data(), allow_data_in_errors,
detect_key_out_of_order, key_validation_callback);
Status status = iter.SeekAndValidate(dummy_slice, k.memtable_key().data(),
allow_data_in_errors);
for (; iter.Valid() && status.ok() &&
callback_func(callback_args, iter.key());
status = iter.NextAndValidate(allow_data_in_errors)) {
@@ -247,18 +244,12 @@ class SkipListRep : public MemTableRep {
}
Status SeekAndValidate(const Slice& user_key, const char* memtable_key,
bool allow_data_in_errors,
bool detect_key_out_of_order,
const std::function<Status(const char*, bool)>&
key_validation_callback) override {
bool allow_data_in_errors) override {
if (memtable_key != nullptr) {
return iter_.SeekAndValidate(memtable_key, allow_data_in_errors,
detect_key_out_of_order,
key_validation_callback);
return iter_.SeekAndValidate(memtable_key, allow_data_in_errors);
} else {
return iter_.SeekAndValidate(
EncodeKey(&tmp_, user_key), allow_data_in_errors,
detect_key_out_of_order, key_validation_callback);
return iter_.SeekAndValidate(EncodeKey(&tmp_, user_key),
allow_data_in_errors);
}
}
+4 -9
View File
@@ -85,10 +85,7 @@ class VectorRep : public MemTableRep {
// Seek and do some memory validation
Status SeekAndValidate(const Slice& internal_key, const char* memtable_key,
bool allow_data_in_errors,
bool detect_key_out_of_order,
const std::function<Status(const char*, bool)>&
key_validation_callback) override;
bool allow_data_in_errors) override;
// Advance to the first entry with a key <= target
void SeekForPrev(const Slice& user_key, const char* memtable_key) override;
@@ -269,11 +266,9 @@ void VectorRep::Iterator::Seek(const Slice& user_key,
.first;
}
Status VectorRep::Iterator::SeekAndValidate(
const Slice& /* internal_key */, const char* /* memtable_key */,
bool /* allow_data_in_errors */, bool /* detect_key_out_of_order */,
const std::function<Status(const char*, bool)>&
/* key_validation_callback */) {
Status VectorRep::Iterator::SeekAndValidate(const Slice& /* internal_key */,
const char* /* memtable_key */,
bool /* allow_data_in_errors */) {
if (vrep_) {
WriteLock l(&vrep_->rwlock_);
if (bucket_->begin() == bucket_->end()) {
-2
View File
@@ -65,11 +65,9 @@ std::string IOStatsContext::ToString(bool exclude_zero_counters) const {
IOSTATS_CONTEXT_OUTPUT(cpu_read_nanos);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.hot_file_bytes_read);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.warm_file_bytes_read);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.cool_file_bytes_read);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.cold_file_bytes_read);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.hot_file_read_count);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.warm_file_read_count);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.cool_file_read_count);
IOSTATS_CONTEXT_OUTPUT(file_io_stats_by_temperature.cold_file_read_count);
std::string str = ss.str();
str.erase(str.find_last_not_of(", ") + 1);
Loaded 100 of 165 files, more files were not shown because too many files have changed in this diff. Show more