Compare commits

..
6 Commits
Author SHA1 Message Date
Hui Xiao 5fbc1cd5bc Update for 10.9.1 patch 2025-12-11 19:04:28 -08:00
Hui Xiao 60f24d394d Fix resumable compaction to prevent resumption at truncated range deletion boundaries (#14184)
Summary:
**Context/Summary:**

Truncated range deletion in input files can be output by CompactionIterator with type kMaxValid instead of kTypeRangeDeletion, to satisfy ordering requirement between the truncated range deletion start key and a file's point keys. There was a plan to skip such key in https://github.com/facebook/rocksdb/pull/14122 but blockers remain to fulfill the plan.

Resumable compaction is not able to handle resumption from range deletion well at this point and should consider kMaxValid type same as kTypeRangeDeletion for resumption. Previously, it didn't and mistakenly allow resumption from a delete range. That led to an assertion failure, complaining about lacking information to update file boundaries in the presence of range deletion needed during cutting an output file, after the compaction resumes from that delete range and happens to cut the output file shortly after without any point keys in between.

```
frame https://github.com/facebook/rocksdb/issues/9: 0x00007f4f4743bc93 libc.so.6`__GI___assert_fail(assertion="meta.smallest.size() > 0", file="db/compaction/compaction_outputs.cc", line=530, function="rocksdb::Status rocksdb::CompactionOutputs::AddRangeDels(rocksdb::CompactionRangeDelAggregator&, const rocksdb::Slice*, const rocksdb::Slice*, rocksdb::CompactionIterationStats&, bool, const rocksdb::InternalKeyComparator&, rocksdb::SequenceNumber, std::pair<long unsigned int, long unsigned int>, const rocksdb::Slice&, const string&)") at assert.c:101:3
frame https://github.com/facebook/rocksdb/issues/10: 0x00007f4f4808c68c librocksdb.so.10.9`rocksdb::CompactionOutputs::AddRangeDels(this=0x00007f4f0c27e1a0, range_del_agg=0x00007f4f0c21ecc0, comp_start_user_key=0x0000000000000000, comp_end_user_key=0x0000000000000000, range_del_out_stats=0x00007f4f0dffa140, bottommost_level=false, icmp=0x00007f4ef4c93040, earliest_snapshot=13108729, keep_seqno_range=<unavailable>, next_table_min_key=0x00007f4ef4c8f540, full_history_ts_low="") at compaction_outputs.cc:530:7
frame https://github.com/facebook/rocksdb/issues/11: 0x00007f4f480480dd librocksdb.so.10.9`rocksdb::CompactionJob::FinishCompactionOutputFile(this=0x00007f4f0dffb890, input_status=<unavailable>, prev_table_last_internal_key=0x00007f4f0dffa650, next_table_min_key=0x00007f4ef4c8f540, comp_start_user_key=0x0000000000000000, comp_end_user_key=0x0000000000000000, c_iter=0x00007f4ef4c8f400, sub_compact=0x00007f4f0c27e000, outputs=0x00007f4f0c27e1a0) at compaction_job.cc:1917:31
```

This PR simply prevents  MaxValid from being a resumption point like regular range deletion - see commit 842d66eb18ea67e965d6acb1fce12c18eeb778d2

Besides that, the PR also improves the testing, variable naming, logging in resumable compaction codes that were needed to debug this assertion failure - see commit https://github.com/facebook/rocksdb/pull/14184/commits/aecd4e7f971f6dd4df672d9e5f1409fe4747c561. These improvements are covered by existing tests.

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

Test Plan:
- The stress initially surfaced the error. Using the exact same LSM shapes and files that were used in stress test but in a unit test, I'm able to get a deterministic repro and confirmed the fix resolves the error.  This is the repro test https://github.com/hx235/rocksdb/commit/1075936e693c68c960761855900c53f5b894f57a
```
./compaction_service_test --gtest_filter=ResumableCompactionServiceTest.CompactSpecificFilesFromExistingDBWithCancelAndResume
# Before fix
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from ResumableCompactionServiceTest
[ RUN      ] ResumableCompactionServiceTest.CompactSpecificFilesFromExistingDBWithCancelAndResume
compaction_service_test: db/compaction/compaction_outputs.cc:530: rocksdb::Status rocksdb::CompactionOutputs::AddRangeDels(rocksdb::CompactionRangeDelAggregator&, const rocksdb::Slice*, const rocksdb::Slice*, rocksdb::CompactionIterationStats&, bool, const rocksdb::InternalKeyComparator&, rocksdb::SequenceNumber, std::pair<long unsigned int, long unsigned int>, const rocksdb::Slice&, const string&): Assertion `meta.smallest.size() > 0' failed.
Received signal 6 (Aborted)
Invoking GDB for stack trace...
[New LWP 2621610]
[New LWP 2621611]
[New LWP 2621612]
[New LWP 2621613]
[New LWP 2621614]
[New LWP 2621630]
[New LWP 2621631]

# After fix
Note: Google Test filter = ResumableCompactionServiceTest.CompactSpecificFilesFromExistingDBWithCancelAndResume
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from ResumableCompactionServiceTest
[ RUN      ] ResumableCompactionServiceTest.CompactSpecificFilesFromExistingDBWithCancelAndResume
[       OK ] ResumableCompactionServiceTest.CompactSpecificFilesFromExistingDBWithCancelAndResume (4722 ms)
[----------] 1 test from ResumableCompactionServiceTest (4722 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4722 ms total)
[  PASSED  ] 1 test.

```
- Follow-up: I tried a couple time to coerce the truncated range delete from scratch in the unit test but failed doing so. Considering kMaxValid may not be outputted by compaction iterator anymore after https://github.com/facebook/rocksdb/pull/14122/files gets landed again (and obsolete the bug) ADN the simple nature of this fix 842d66eb18ea67e965d6acb1fce12c18eeb778d2 AND the worst case of such fix going wrong is just less resumption, I decided to leave writing a unit test to coerce truncated ranged deletion from scratch a follow-up. Maybe I will draw inspiration from https://github.com/facebook/rocksdb/pull/14122/files.

Reviewed By: jaykorean

Differential Revision: D88912663

Pulled By: hx235

fbshipit-source-id: 80a01135684c8fea659650faaa00c2dc452c482a
2025-12-11 18:39:27 -08:00
Xingbo Wang 268a719a30 Fix missing const for arg of OptionChangeMigration (#14173)
Summary:
Fix missing const for arg of OptionChangeMigration

We switched from std::string to std::string & for API OptionChangeMigration, which caused const qualifier to be lost at call site, which causes compilation failure.

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

Test Plan: Unit test

Reviewed By: pdillinger

Differential Revision: D88431457

Pulled By: xingbowang

fbshipit-source-id: a705f3b80cc5ff56dab73aa6a31c940798d8df45
2025-12-04 19:06:26 -08:00
Xingbo Wang 9791103976 Revert #14122 "Fix a bug where compaction ..." (#14170)
Summary:
Revert "Fix a bug where compaction with range deletion can persist kTypeMaxValid in file metadata (https://github.com/facebook/rocksdb/issues/14122)"

Add a new unit test to capture the situation found by stress test

This reverts commit 8c7c8b8dab.

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

Test Plan: Unit Test

Reviewed By: anand1976

Differential Revision: D88395956

Pulled By: xingbowang

fbshipit-source-id: 226649dc79a86010ad326ffb2eae35109dc96bc4
2025-12-04 13:30:39 -08:00
Peter Dillinger 4982688c21 Fix AutoSkipCompressorWrapper with new logic (#14150)
Summary:
... from https://github.com/facebook/rocksdb/issues/14140. The assertion in the default implementation of CompressorWrapper::MaybeCloneSpecialized() could fail because this wrapper wasn't overriding it when it should. (See the NOTE on that implementation.)

Because this release already has a breaking modification to the Compressor API (adding Clone()), I took this opportunity to add 'const' to MaybeCloneSpecialized(). Also marked some compression classes as 'final' that could be marked as such.

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

Test Plan: unit test expanded to cover this case (verified failing before). Audited the rest of our CompressorWrappers.

Reviewed By: archang19

Differential Revision: D87793987

Pulled By: pdillinger

fbshipit-source-id: 61c4469b84e4a47451a9942df09277faeeccfe63
2025-11-24 13:40:36 -08:00
Xingbo Wang ef5a37aca8 Cut 10.9.0 branch.
Summary:
  Cut 10.9.0 branch.

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
2025-11-24 12:53:27 -08:00
875 changed files with 23271 additions and 181892 deletions

No files matched your search

-86
View File
@@ -1,86 +0,0 @@
# When making changes, verify the output of:
# clang-tidy -list-checks
---
Checks: "-*,\
bugprone-argument-comment,\
bugprone-dangling-handle,\
bugprone-fold-init-type,\
bugprone-forward-declaration-namespace,\
bugprone-forwarding-reference-overload,\
bugprone-shadow,\
bugprone-sizeof-*,\
bugprone-string-constructor,\
bugprone-undefined-memory-manipulation,\
bugprone-unused-return-value,\
bugprone-use-after-move,\
cert-env33-c,\
cert-err58-cpp,\
cert-msc30-c,\
cert-msc50-cpp,\
clang-analyzer-*,\
clang-diagnostic-*,\
-clang-diagnostic-missing-designated-field-initializers,\
concurrency-mt-unsafe,\
cppcoreguidelines-avoid-non-const-global-variables,\
cppcoreguidelines-missing-std-forward,\
cppcoreguidelines-pro-type-member-init,\
cppcoreguidelines-special-member-functions,\
cppcoreguidelines-virtual-class-destructor,\
google-build-using-namespace,\
google-explicit-constructor,\
google-readability-avoid-underscore-in-googletest-name,\
misc-definitions-in-headers,\
misc-redundant-expression,\
modernize-make-shared,\
modernize-use-emplace,\
modernize-use-noexcept,\
modernize-use-override,\
modernize-use-using,\
performance-faster-string-find,\
performance-for-range-copy,\
performance-implicit-conversion-in-loop,\
performance-inefficient-algorithm,\
performance-inefficient-string-concatenation,\
performance-inefficient-vector-operation,\
performance-move-const-arg,\
performance-move-constructor-init,\
performance-no-automatic-move,\
performance-no-int-to-ptr,\
performance-noexcept-move-constructor,\
performance-noexcept-swap,\
performance-trivially-destructible,\
performance-type-promotion-in-math-fn,\
performance-unnecessary-copy-initialization,\
performance-unnecessary-value-param,\
readability-braces-around-statements,\
readability-duplicate-include,\
readability-isolate-declaration,\
readability-operators-representation,\
readability-redundant-string-init"
WarningsAsErrors: "bugprone-use-after-move"
CheckOptions:
- key: bugprone-easily-swappable-parameters.MinimumLength
value: 4
- key: cppcoreguidelines-avoid-non-const-global-variables.AllowThreadLocal
value: true
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: true
- key: cppcoreguidelines-special-member-functions.AllowImplicitlyDeletedCopyOrMove
value: true
- key: modernize-use-using.IgnoreExternC
value: true
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: false
- key: performance-unnecessary-value-param.AllowedTypes
value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$'
- key: performance-unnecessary-copy-initialization.AllowedTypes
value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$'
- key: readability-operators-representation.BinaryOperators
value: '&&;&=;&;|;~;!;!=;||;|=;^;^='
- key: readability-redundant-string-init.StringNames
value: '::std::basic_string'
- key: readability-named-parameter.InsertPlainNamesInForwardDecls
value: true
...
+1 -10
View File
@@ -9,16 +9,7 @@ runs:
steps:
- name: Build folly and dependencies
if: ${{ inputs.cache-hit != 'true' }}
run: |
clean_path=()
IFS=: read -ra path_entries <<< "$PATH"
for entry in "${path_entries[@]}"; do
if [[ "$entry" != "/usr/lib/ccache" ]]; then
clean_path+=("$entry")
fi
done
export PATH="$(IFS=:; echo "${clean_path[*]}")"
make build_folly
run: make build_folly
shell: bash
- name: Skip folly build (using cached version)
if: ${{ inputs.cache-hit == 'true' }}
+1 -1
View File
@@ -30,4 +30,4 @@ runs:
# - The docker image, which may not always be specified/known
# - Hash of folly.mk, which includes the folly repository commit hash
# NOTE: this is still only intended for DEBUG folly builds
key: folly-build-${{ runner.os }}-${{ runner.arch }}-${{ github.job_container.image }}-${{ steps.extract-folly-hash.outputs.hash }}-${{ env.PORTABLE == '1' && 'portable' || 'native' }}
key: folly-build-${{ runner.os }}-${{ runner.arch }}-${{ github.job_container.image }}-${{ steps.extract-folly-hash.outputs.hash }}
@@ -1,21 +0,0 @@
name: cache-getdeps-downloads
description: Cache getdeps downloads to avoid unreliable mirrors and speed up builds
outputs:
cache-hit:
description: Whether the cache was hit
value: ${{ steps.cache-downloads.outputs.cache-hit }}
runs:
using: composite
steps:
- name: Cache getdeps downloads
id: cache-downloads
uses: actions/cache@v4
with:
# Use a fixed path that we control - folly.mk will sync with getdeps downloads dir
path: /tmp/rocksdb-getdeps-cache
# Use a rolling cache key - the cache accumulates downloads over time
# The key includes a weekly timestamp to ensure periodic refresh
key: getdeps-downloads-${{ runner.os }}-${{ runner.arch }}-week-${{ github.run_id }}
restore-keys: |
getdeps-downloads-${{ runner.os }}-${{ runner.arch }}-week-
getdeps-downloads-${{ runner.os }}-${{ runner.arch }}-
@@ -0,0 +1,9 @@
name: install-jdk8-on-macos
runs:
using: composite
steps:
- name: Install JDK 8 on macos
run: |-
HOMEBREW_NO_AUTO_UPDATE=1 brew tap bell-sw/liberica
HOMEBREW_NO_AUTO_UPDATE=1 brew install --cask liberica-jdk8
shell: bash
+5 -21
View File
@@ -2,16 +2,6 @@ name: pre-steps
runs:
using: composite
steps:
- name: Dump ulimits for diagnostics
run: |
echo "=== ulimits (soft) ==="
ulimit -a -S || true
echo "=== ulimits (hard) ==="
ulimit -a -H || true
shell: bash
- name: Install lld linker for faster builds
run: apt-get update -y && apt-get install -y lld 2>/dev/null || true
shell: bash
- name: Setup Environment Variables
run: |-
echo "GTEST_THROW_ON_FAILURE=0" >> "$GITHUB_ENV"
@@ -20,15 +10,9 @@ runs:
echo "GTEST_COLOR=1" >> "$GITHUB_ENV"
echo "CTEST_OUTPUT_ON_FAILURE=1" >> "$GITHUB_ENV"
echo "CTEST_TEST_TIMEOUT=300" >> "$GITHUB_ENV"
# These third-party sources are mirrored on the "third-party-deps" GitHub
# release. To add one, upload the asset here (intentionally hidden):
# https://github.com/facebook/rocksdb/releases/edit/third-party-deps
# Note how file names are generated below (vs. from the original source)
# before uploading. Removing or modifying files will break builds for
# older releases/revisions (not found or checksum mismatch).
echo "ZLIB_DOWNLOAD_PREFIX=https://github.com/facebook/rocksdb/releases/download/third-party-deps/zlib-" >> "$GITHUB_ENV"
echo "BZIP2_DOWNLOAD_PREFIX=https://github.com/facebook/rocksdb/releases/download/third-party-deps/bzip2-" >> "$GITHUB_ENV"
echo "SNAPPY_DOWNLOAD_PREFIX=https://github.com/facebook/rocksdb/releases/download/third-party-deps/snappy-" >> "$GITHUB_ENV"
echo "LZ4_DOWNLOAD_PREFIX=https://github.com/facebook/rocksdb/releases/download/third-party-deps/lz4-" >> "$GITHUB_ENV"
echo "ZSTD_DOWNLOAD_PREFIX=https://github.com/facebook/rocksdb/releases/download/third-party-deps/zstd-" >> "$GITHUB_ENV"
echo "ZLIB_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zlib" >> "$GITHUB_ENV"
echo "BZIP2_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/bzip2" >> "$GITHUB_ENV"
echo "SNAPPY_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/snappy" >> "$GITHUB_ENV"
echo "LZ4_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/lz4" >> "$GITHUB_ENV"
echo "ZSTD_DOWNLOAD_BASE=https://rocksdb-deps.s3.us-west-2.amazonaws.com/pkgs/zstd" >> "$GITHUB_ENV"
shell: bash
-54
View File
@@ -1,54 +0,0 @@
name: setup-ccache
description: Setup ccache for faster C++ compilation caching
inputs:
cache-key-prefix:
description: Unique prefix for the cache key (e.g., 'build-linux')
required: true
portable:
description: Set PORTABLE=1 to disable -march=native (set to "false" for jobs linking pre-built Folly)
required: false
default: "true"
runs:
using: composite
steps:
- name: Set ccache environment variables
run: |
echo "CCACHE_DIR=${{ github.workspace }}/.ccache" >> $GITHUB_ENV
echo "CCACHE_BASEDIR=${{ github.workspace }}" >> $GITHUB_ENV
echo "CCACHE_NOHASHDIR=true" >> $GITHUB_ENV
echo "CCACHE_COMPILERCHECK=content" >> $GITHUB_ENV
echo "CCACHE_SLOPPINESS=clang_index_store,file_stat_matches,include_file_ctime,include_file_mtime,ivfsoverlay,pch_defines,modules,system_headers,time_macros" >> $GITHUB_ENV
echo "CCACHE_MAXSIZE=4G" >> $GITHUB_ENV
if [ "${{ inputs.portable }}" = "true" ]; then
echo "PORTABLE=1" >> $GITHUB_ENV
fi
shell: bash
- name: Restore ccache
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.ccache
key: ccache-${{ inputs.cache-key-prefix }}-${{ github.head_ref || github.ref }}-${{ github.sha }}
restore-keys: |-
ccache-${{ inputs.cache-key-prefix }}-${{ github.head_ref || github.ref }}-
ccache-${{ inputs.cache-key-prefix }}-refs/heads/main-
- name: Install ccache
run: |
if [ "$RUNNER_OS" = "macOS" ]; then
which ccache || brew install ccache
else
which ccache || (apt-get update && apt-get install -y ccache)
fi
shell: bash
- name: Add ccache to PATH
run: |
if [ "$RUNNER_OS" = "macOS" ]; then
echo "$(brew --prefix ccache)/libexec" >> $GITHUB_PATH
else
echo "/usr/lib/ccache" >> $GITHUB_PATH
fi
shell: bash
- name: Zero ccache stats and set build marker
run: |
ccache -z
touch "$CCACHE_DIR/.build_marker"
shell: bash
+2 -2
View File
@@ -6,6 +6,6 @@ runs:
run: |
make checkout_folly
shell: bash
- name: Install patchelf and libaio
run: apt-get update -y && apt-get install -y patchelf libaio-dev
- name: Install patchelf
run: apt-get update -y && apt-get install -y patchelf
shell: bash
@@ -1,17 +0,0 @@
name: setup-jdk-on-macos
runs:
using: composite
steps:
- name: Set up JDK on macos
run: |-
set -euo pipefail
JAVA_HOME="$(/usr/libexec/java_home -v 21)"
echo "JAVA_HOME=${JAVA_HOME}" >> "$GITHUB_ENV"
echo "JAVAC_ARGS=--release 8" >> "$GITHUB_ENV"
echo "${JAVA_HOME}/bin" >> "$GITHUB_PATH"
echo "Using JDK at ${JAVA_HOME}"
"${JAVA_HOME}/bin/java" -version
"${JAVA_HOME}/bin/javac" -version
shell: bash
@@ -1,15 +0,0 @@
name: teardown-ccache
description: Trim stale ccache entries and print stats
runs:
using: composite
steps:
- name: Trim and print ccache stats
run: |
if [ -z "$CCACHE_DIR" ]; then
echo "teardown-ccache: CCACHE_DIR not set, skipping (setup-ccache may not have run)"
exit 0
fi
.github/scripts/ccache-trim.sh || true
ccache -s || echo "teardown-ccache: ccache not found, skipping stats"
if: always()
shell: bash
+18 -89
View File
@@ -1,95 +1,34 @@
name: windows-build-steps
inputs:
suite-run:
description: Comma-separated list of test suites to run (empty to skip C++ tests)
required: false
default: arena_test,db_basic_test,db_test,db_etc2_test,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test
run-java:
description: Whether to run Java tests
required: false
default: "true"
runs:
using: composite
steps:
- name: Detect Visual Studio generator
id: detect_vs
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$vswhere = Join-Path ([Environment]::GetFolderPath("ProgramFilesX86")) "Microsoft Visual Studio\Installer\vswhere.exe"
if (!(Test-Path $vswhere)) {
throw "vswhere.exe was not found at $vswhere"
}
$vsInstallationsJson = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json -utf8
$vsInstallations = @($vsInstallationsJson | ConvertFrom-Json)
if ($vsInstallations.Count -eq 0) {
throw "No Visual Studio instance with C++ tools was found."
}
$vsInstallation = $vsInstallations[0]
$vsMajor = [int]$vsInstallation.catalog.productLineVersion
if ($vsMajor -eq 0) {
$vsMajor = [int]($vsInstallation.installationVersion.Split(".")[0])
}
$generatorLine = cmake --help | Where-Object {
$_ -match "^\*?\s*Visual Studio $vsMajor\s+\d{4}\s*="
} | Select-Object -First 1
if (!$generatorLine) {
throw "CMake does not support a Visual Studio generator for VS major version $vsMajor."
}
$cmakeGenerator = ($generatorLine -replace "^\*?\s*", "" -replace "\s*=.*$", "").Trim()
$vsVersionRange = "[{0}.0,{1}.0)" -f $vsMajor, ($vsMajor + 1)
echo "Detected Visual Studio at $($vsInstallation.installationPath)"
echo "Using CMake generator: $cmakeGenerator"
echo "Using setup-msbuild vs-version: $vsVersionRange"
"CMAKE_GENERATOR=$cmakeGenerator" >> $env:GITHUB_ENV
"vs_version=$vsVersionRange" >> $env:GITHUB_OUTPUT
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@v1.3.1
- name: Cache ccache directory
id: ccache-cache
uses: actions/cache@v4
with:
vs-version: ${{ steps.detect_vs.outputs.vs_version }}
path: C:\a\rocksdb\rocksdb\.ccache
key: rocksdb-build-${{ runner.os }}-${{ runner.arch }}-ccache-${{ hashFiles('CMakeLists.txt', 'cmake/**/*.cmake') }}-v1
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
max-size: "10GB"
key: ccache-windows-${{ github.workflow }}
restore-keys: |
ccache-windows-
- name: Configure ccache
shell: pwsh
run: |
ccache --set-config=base_dir=C:\a\rocksdb\rocksdb
ccache --set-config=hash_dir=false
ccache --set-config=compiler_check=content
- name: Custom steps
env:
THIRDPARTY_HOME: ${{ github.workspace }}/thirdparty
CMAKE_HOME: C:/Program Files/CMake
CMAKE_BIN: C:/Program Files/CMake/bin/cmake.exe
CTEST_BIN: C:/Program Files/CMake/bin/ctest.exe
JAVA_HOME: C:/Program Files/BellSoft/LibericaJDK-8
SNAPPY_HOME: ${{ github.workspace }}/thirdparty/snappy-1.2.2
SNAPPY_INCLUDE: ${{ github.workspace }}/thirdparty/snappy-1.2.2;${{ github.workspace }}/thirdparty/snappy-1.2.2/build
SNAPPY_LIB_DEBUG: ${{ github.workspace }}/thirdparty/snappy-1.2.2/build/Debug/snappy.lib
run: |-
# NOTE: if ... Exit $LASTEXITCODE lines needed to exit and report failure
echo ===================== Install Dependencies =====================
if (!$env:JAVA_HOME -or !(Test-Path (Join-Path $env:JAVA_HOME "bin\javac.exe"))) {
$javac = Get-Command javac -ErrorAction SilentlyContinue
if (!$javac) {
Write-Error "javac was not found on PATH and JAVA_HOME is not set."
Exit 1
}
$env:JAVA_HOME = Split-Path (Split-Path $javac.Source -Parent) -Parent
}
echo "JAVA_HOME=$env:JAVA_HOME"
& "$env:JAVA_HOME\bin\java.exe" -version
& "$env:JAVA_HOME\bin\javac.exe" -version
choco install liberica8jdk -y
if(!$?) { Exit $LASTEXITCODE }
mkdir $Env:THIRDPARTY_HOME
cd $Env:THIRDPARTY_HOME
echo "Building Snappy dependency..."
@@ -102,11 +41,11 @@ runs:
cd build
& cmake -G "$Env:CMAKE_GENERATOR" .. -DSNAPPY_BUILD_TESTS=OFF -DSNAPPY_BUILD_BENCHMARKS=OFF
if(!$?) { Exit $LASTEXITCODE }
cmake --build . --config Debug --parallel 32 -- /p:Platform=x64
msbuild Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
if(!$?) { Exit $LASTEXITCODE }
echo ======================== Build RocksDB =========================
cd ${{ github.workspace }}
$env:Path = "$env:JAVA_HOME\bin;" + $env:Path
$env:Path = $env:JAVA_HOME + ";" + $env:Path
mkdir build
cd build
& cmake -G "$Env:CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE=Debug -DWIN_CI=1 -DPORTABLE="$Env:CMAKE_PORTABLE" -DSNAPPY=1 -DXPRESS=1 -DJNI=1 ..
@@ -114,25 +53,15 @@ runs:
cd ..
echo "Building with VS version: $Env:CMAKE_GENERATOR"
# use more parallel processes than the number of processes available, as most of the compile command would be cache hit
cmake --build build --config Debug --parallel 32 -- /p:LinkIncremental=false /p:Platform=x64
msbuild build/rocksdb.sln /m:32 /p:LinkIncremental=false -property:Configuration=Debug -property:Platform=x64
if(!$?) { Exit $LASTEXITCODE }
echo ========================= Test RocksDB =========================
$suiteRun = "${{ inputs.suite-run }}"
if ($suiteRun -ne "") {
$suiteArray = $suiteRun -split ','
build_tools\run_ci_db_test.ps1 -SuiteRun $suiteArray -Concurrency 16
if(!$?) { Exit $LASTEXITCODE }
} else {
echo "Skipping C++ tests (suite-run is empty)"
}
if ("${{ inputs.run-java }}" -eq "true") {
echo ======================== Test RocksJava ========================
cd build\java
& ctest -C Debug -j 16
if(!$?) { Exit $LASTEXITCODE }
} else {
echo "Skipping Java tests"
}
build_tools\run_ci_db_test.ps1 -SuiteRun arena_test,db_basic_test,db_test,db_test2,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test -Concurrency 16
if(!$?) { Exit $LASTEXITCODE }
echo ======================== Test RocksJava ========================
cd build\java
& ctest -C Debug -j 16
if(!$?) { Exit $LASTEXITCODE }
shell: pwsh
- name: Show ccache stats
shell: pwsh
@@ -1,44 +0,0 @@
// Shared markdown builder for AI review comment bodies.
//
// Usage:
// const build = require('./build-ai-review-comment.js');
// return build({ icon, headerTitle, triggerLine, responseBody, footerLines
// });
// GitHub rejects issue comments longer than this many characters. The model
// response (responseBody) is the only unbounded input, so we trim it to fit
// while keeping the fixed scaffolding (header, trigger, footer) intact.
const MAX_COMMENT_LENGTH = 65536;
const TRUNCATION_NOTE =
'\n\n*[Truncated — full output in execution log artifact]*';
module.exports = function buildAiReviewComment(
{icon, headerTitle, triggerLine, responseBody, footerLines}) {
const assemble = (body) => [`## ${icon} ${headerTitle}`,
'',
triggerLine,
'',
'---',
'',
body,
'',
'---',
'',
'<details>',
'<summary>ℹ️ About this response</summary>',
'',
...footerLines,
'</details>',
].join('\n');
const body = responseBody || '';
const comment = assemble(body);
if (comment.length <= MAX_COMMENT_LENGTH) {
return comment;
}
// Drop only as much of the body as needed to fit, then re-assemble so the
// footer/<details> block is preserved rather than cut off mid-comment.
const overflow = comment.length - MAX_COMMENT_LENGTH;
const keep = Math.max(0, body.length - overflow - TRUNCATION_NOTE.length);
return assemble(body.substring(0, keep) + TRUNCATION_NOTE);
};
-39
View File
@@ -1,39 +0,0 @@
#!/bin/bash
# Trim ccache to keep only entries accessed during the current build.
#
# Usage:
# 1. Before build: touch "$CCACHE_DIR/.build_marker"
# 2. Run build (ccache updates mtime on hits, creates new files for misses)
# 3. After build: .github/scripts/ccache-trim.sh
#
# This removes cache files not accessed during the build (stale entries from
# previous commits). Only intended for CI where each run builds one commit.
# Do NOT use on local builds where multiple worktrees may share the cache.
set -e
CCACHE_DIR="${CCACHE_DIR:?CCACHE_DIR must be set}"
MARKER="$CCACHE_DIR/.build_marker"
if [ ! -f "$MARKER" ]; then
echo "ccache-trim: No .build_marker found, skipping (was the marker created before build?)"
exit 0
fi
# Count files before cleanup
before=$(find "$CCACHE_DIR" -type f \( -name '*R' -o -name '*M' \) | wc -l)
# Delete cache files (results and manifests) older than the marker
find "$CCACHE_DIR" -type f \( -name '*R' -o -name '*M' \) ! -newer "$MARKER" -delete
# Clean up empty directories
find "$CCACHE_DIR" -mindepth 2 -type d -empty -delete 2>/dev/null || true
# Recalculate size counters
ccache -c 2>/dev/null || true
after=$(find "$CCACHE_DIR" -type f \( -name '*R' -o -name '*M' \) | wc -l)
echo "ccache-trim: $before -> $after cache files (removed $((before - after)) stale entries)"
# Clean up marker
rm -f "$MARKER"
-32
View File
@@ -1,32 +0,0 @@
#!/bin/bash
# Compute test shard for parallel CI execution.
# Distributes tests round-robin across N shards for balanced load.
# Outputs ROCKSDBTESTS_SUBSET — the list of test binaries for this shard.
# The Makefile uses this to build and run only the assigned tests.
#
# Usage: compute-test-shard.sh <shard_index> <num_shards>
set -euo pipefail
shard=${1:?Usage: compute-test-shard.sh <shard_index> <num_shards>}
nshards=${2:?Usage: compute-test-shard.sh <shard_index> <num_shards>}
# Get sorted test list (db_test first since it's the heaviest, then alpha)
make -s list_all_tests 2>/dev/null | tr ' ' '\n' | grep '_test$' | sort -u > /tmp/sorted.txt
(echo db_test; grep -v '^db_test$' /tmp/sorted.txt) > /tmp/all_tests.txt
total=$(wc -l < /tmp/all_tests.txt)
# Round-robin: assign test i to shard (i % nshards).
# This spreads heavy tests (which are scattered alphabetically) evenly.
awk -v s="$shard" -v n="$nshards" 'NR > 0 && (NR - 1) % n == s' /tmp/all_tests.txt > /tmp/include.txt
included=$(wc -l < /tmp/include.txt)
first=$(head -1 /tmp/include.txt)
last=$(tail -1 /tmp/include.txt)
# Output space-separated list for ROCKSDBTESTS_SUBSET
subset=$(tr '\n' ' ' < /tmp/include.txt)
echo "subset=${subset}" >> "$GITHUB_OUTPUT"
echo "Shard $shard/$nshards: $included tests (round-robin), first=$first last=$last (total $total)"
-118
View File
@@ -1,118 +0,0 @@
// Parse Claude Code execution log and produce a markdown review comment.
//
// Usage from actions/github-script:
// const parse = require('./.github/scripts/parse-claude-review.js');
// const markdown = parse({ executionFile, conclusion, meta });
//
// Parameters:
// executionFile - path to the JSON execution log from claude-code-base-action
// conclusion - 'success' or 'failure' from the action output
// meta - { trigger, autoMode, headSha, reviewer, isQuery, isPartial
// }
const fs = require('fs');
const buildComment = require('./build-ai-review-comment.js');
module.exports = function parseClaude({executionFile, conclusion, meta}) {
function getTriggerLine() {
if (meta.trigger !== 'auto') {
return `*Requested by @${meta.reviewer}*`;
}
const shortSha = meta.headSha ? meta.headSha.substring(0, 7) : 'unknown';
if (meta.autoMode === 'early') {
return `*Auto-triggered after CI reached the early-review threshold — reviewing commit ${
shortSha}*`;
}
return `*Auto-triggered after CI passed — reviewing commit ${shortSha}*`;
}
let responseBody = '';
try {
const executionLog = JSON.parse(fs.readFileSync(executionFile, 'utf8'));
if (!Array.isArray(executionLog)) {
throw new Error('Expected array format from claude-code-base-action');
}
const resultMessage = executionLog.find(m => m.type === 'result');
// Helper: extract the last substantial assistant text from the log.
// Used as a fallback when Claude ran out of turns and the recovery
// session also failed to produce a result.
function getLastAssistantText(log, minLength = 200) {
for (let i = log.length - 1; i >= 0; i--) {
const m = log[i];
if (m.type !== 'assistant') continue;
const content = m.message && m.message.content;
if (!Array.isArray(content)) continue;
for (let j = content.length - 1; j >= 0; j--) {
if (content[j].type === 'text' && content[j].text &&
content[j].text.trim().length >= minLength) {
const text = content[j].text.trim();
// Truncate to avoid enormous PR comments
return text.length > 50000 ? text.substring(0, 50000) +
'\n\n*[Truncated — full output in execution log artifact]*' :
text;
}
}
}
return null;
}
if (!resultMessage) {
responseBody = '⚠️ No result message found in execution log.';
} else if (resultMessage.subtype === 'success' && resultMessage.result) {
responseBody = resultMessage.result;
} else if (resultMessage.is_error || resultMessage.subtype === 'error') {
const errorInfo =
resultMessage.result || resultMessage.error || 'Unknown error';
responseBody = `❌ **Claude encountered an error:**\n\n${errorInfo}`;
} else if (resultMessage.subtype === 'error_max_turns') {
// The workflow runs a recovery session when this happens, so this
// branch is typically only hit if recovery wasn't attempted (e.g.,
// no findings file was written). Extract what we can.
const partial = getLastAssistantText(executionLog);
if (partial) {
responseBody =
`⚠️ **Review incomplete — Claude hit the turn limit.**\n\nBelow is the last partial output. You can request a fresh review with \`/claude-review\`.\n\n---\n\n${
partial}`;
} else {
responseBody =
'⚠️ **Review incomplete — Claude hit the turn limit before producing output.** You can request a fresh review with `/claude-review`.';
}
} else if (resultMessage.result) {
responseBody = `⚠️ **Completed with status: ${
resultMessage.subtype}**\n\n${resultMessage.result}`;
} else {
responseBody = '⚠️ Claude completed but produced no output.';
}
} catch (error) {
responseBody = `❌ Error parsing Claude response: ${error.message}`;
}
const isPartial = !!meta.isPartial;
const icon = isPartial ? '🟡' : (conclusion === 'success' ? '✅' : '⚠️');
const headerTitle = meta.isQuery ? 'Claude Response' : 'Claude Code Review';
const triggerLine = getTriggerLine();
return buildComment({
icon,
headerTitle,
triggerLine,
responseBody,
footerLines: [
'Generated by [Claude Code](https://github.com/anthropics/claude-code-action).',
'Review methodology: `claude_md/ci_review_prompt.md`',
'',
'**Limitations:**',
'- Claude may miss context from files not in the diff',
'- Large PRs may be truncated',
'- Always apply human judgment to AI suggestions',
'',
'**Commands:**',
'- `/claude-review [context]` — Request a code review',
'- `/claude-query <question>` — Ask about the PR or codebase',
],
});
};
-98
View File
@@ -1,98 +0,0 @@
// Parse Codex review artifacts and produce a markdown review comment.
//
// Usage from actions/github-script:
// const parse = require('./.github/scripts/parse-codex-review.js');
// const markdown = parse({ responseFile, recoveryFile, findingsFile, logFile,
// exitCode, meta });
//
// Parameters:
// responseFile - path to Codex final response output
// recoveryFile - path to recovery output formatted from review-findings.md
// findingsFile - path to incremental findings file written during review
// logFile - path to Codex stdout/stderr log
// exitCode - Codex process exit code
// meta - { trigger, autoMode, headSha, reviewer, isQuery, isPartial }
const fs = require('fs');
const buildComment = require('./build-ai-review-comment.js');
module.exports = function parseCodex(
{responseFile, recoveryFile, findingsFile, logFile, exitCode, meta}) {
function getTriggerLine() {
if (meta.trigger !== 'auto') {
return `*Requested by @${meta.reviewer}*`;
}
const shortSha = meta.headSha ? meta.headSha.substring(0, 7) : 'unknown';
if (meta.autoMode === 'early') {
return `*Auto-triggered after CI reached the early-review threshold — reviewing commit ${
shortSha}*`;
}
return `*Auto-triggered after CI passed — reviewing commit ${shortSha}*`;
}
function readIfPresent(path) {
if (!path || !fs.existsSync(path)) {
return '';
}
const text = fs.readFileSync(path, 'utf8').trim();
return text;
}
function tailFile(path, maxChars = 12000) {
const text = readIfPresent(path);
if (!text) {
return '';
}
if (text.length <= maxChars) {
return text;
}
return text.slice(text.length - maxChars);
}
let responseBody = '';
const recovered = readIfPresent(recoveryFile);
const direct = readIfPresent(responseFile);
const findings = readIfPresent(findingsFile);
if (recovered) {
responseBody = recovered;
} else if (direct) {
responseBody = direct;
} else if (findings) {
responseBody =
'⚠️ **Review incomplete — Codex did not produce a final response.**\n\n' +
'Below are the incremental findings recovered from `review-findings.md`.\n\n---\n\n' +
findings;
} else {
const logTail = tailFile(logFile);
responseBody = logTail ?
`❌ **Codex review failed before producing findings.**\n\n\`\`\`\n${
logTail}\n\`\`\`` :
'❌ Codex review failed before producing any output.';
}
const isPartial = !!meta.isPartial;
const code = Number.parseInt(exitCode || '1', 10);
const icon = isPartial ? '🟡' : (code === 0 ? '✅' : '⚠️');
const triggerLine = getTriggerLine();
return buildComment({
icon,
headerTitle: meta.isQuery ? 'Codex Response' : 'Codex Code Review',
triggerLine,
responseBody,
footerLines: [
'Generated by Codex CLI.',
'Review methodology: `claude_md/ci_review_prompt.md`',
'',
'**Limitations:**',
'- Codex may miss context from files not in the diff',
'- Large PRs may be truncated',
'- Always apply human judgment to AI suggestions',
'',
'**Commands:**',
'- `/codex-review [context]` — Request a code review',
'- `/codex-query <question>` — Ask about the PR or codebase',
],
});
};
-204
View File
@@ -1,204 +0,0 @@
// Shared PR comment posting utility.
// Used by both clang-tidy-comment.yml and claude-review-comment.yml.
//
// Usage from actions/github-script:
// const post = require('./.github/scripts/post-pr-comment.js');
// await post({ github, context, core, prNumber, body, marker });
//
// Parameters:
// github - octokit instance from actions/github-script
// context - GitHub Actions context
// core - @actions/core for logging
// prNumber - PR number to comment on
// body - comment body (markdown string)
// marker - HTML comment marker for dedup (e.g. '<!-- claude-review -->')
// If an existing comment with this marker is found, it is updated.
// If not found, a new comment is created.
// legacyMarkers - optional list of legacy markers that should be migrated by
// being considered part of the same comment family.
// prunePrefix - optional marker prefix whose older comments should be
// superseded. If obsoleteTitle is set, older comments are
// collapsed instead of deleted.
// preserveLatest - optional count of active comments to keep when
// prunePrefix is set.
// obsoleteMarker - optional HTML marker used to detect already-obsolete
// comments.
// obsoleteTitle - optional heading to use when collapsing superseded
// comments into a details block.
module.exports = async function postPrComment({
github,
context,
core,
prNumber,
body,
marker,
legacyMarkers = [],
prunePrefix = '',
preserveLatest = 0,
obsoleteMarker = '',
obsoleteTitle = '',
}) {
if (!prNumber || !body) {
core.warning('Missing prNumber or body; skipping comment.');
return;
}
const owner = context.repo.owner;
const repo = context.repo.repo;
// Ensure marker is embedded in the body
const markedBody = body.includes(marker) ? body : `${marker}\n${body}`;
async function listComments() {
return await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
}
function commentActivityTime(comment) {
const timestamp =
Date.parse(comment.updated_at || comment.created_at || '');
return Number.isNaN(timestamp) ? 0 : timestamp;
}
function commentSortDescending(left, right) {
const timeDelta = commentActivityTime(right) - commentActivityTime(left);
if (timeDelta !== 0) {
return timeDelta;
}
return Number(right.id || 0) - Number(left.id || 0);
}
function isObsoleteComment(comment) {
return !!obsoleteMarker && typeof comment.body === 'string' &&
comment.body.includes(obsoleteMarker);
}
function buildObsoleteBody(comment) {
const originalBody =
typeof comment.body === 'string' && comment.body.trim() ?
comment.body :
'*No original review body preserved.*';
const title = obsoleteTitle || 'AI Review - OBSOLETE';
return `${obsoleteMarker}\n## ${
title}\n\n<details>\n<summary>Superseded by a newer AI review. Expand to see the original review.</summary>\n\n${
originalBody}\n\n</details>`;
}
async function deleteCommentIfPresent(comment, reason) {
try {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: comment.id,
});
core.info(`${reason} ${comment.id}`);
} catch (error) {
if (error.status === 404) {
core.info(`Comment ${comment.id} was already deleted by another run.`);
return;
}
throw error;
}
}
async function supersedeCommentIfPresent(comment, reason) {
if (!obsoleteTitle) {
await deleteCommentIfPresent(comment, reason);
return;
}
if (isObsoleteComment(comment)) {
return;
}
try {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: comment.id,
body: buildObsoleteBody(comment),
});
core.info(`${reason} ${comment.id}`);
} catch (error) {
if (error.status === 404) {
core.info(`Comment ${comment.id} was already deleted by another run.`);
return;
}
throw error;
}
}
let comments = await listComments();
const existing = comments.find(
comment =>
typeof comment.body === 'string' && comment.body.includes(marker));
let currentCommentId = null;
if (existing) {
try {
const response = await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body: markedBody,
});
currentCommentId = existing.id;
core.info(`Updated existing comment ${existing.id}`);
} catch (error) {
if (error.status !== 404) {
throw error;
}
core.info(
`Comment ${existing.id} disappeared before update; ` +
'creating a fresh comment instead.');
}
}
if (!currentCommentId) {
const response = await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: markedBody,
});
currentCommentId = response.data.id;
core.info('Created new PR comment');
}
if (prunePrefix || legacyMarkers.length > 0) {
comments = await listComments();
const relatedComments = comments.filter(
comment => comment.id !== currentCommentId &&
typeof comment.body === 'string' &&
((prunePrefix && comment.body.includes(prunePrefix)) ||
legacyMarkers.some(
legacyMarker => comment.body.includes(legacyMarker))));
const activeRelatedComments =
comments
.filter(
comment => typeof comment.body === 'string' &&
!isObsoleteComment(comment) &&
(comment.id === currentCommentId ||
relatedComments.some(
relatedComment => relatedComment.id === comment.id)))
.sort(commentSortDescending);
const keep =
new Set(activeRelatedComments.slice(0, Math.max(preserveLatest, 1))
.map(comment => comment.id));
const supersedeCandidates = obsoleteTitle ?
activeRelatedComments.filter(comment => !keep.has(comment.id)) :
relatedComments.filter(comment => !keep.has(comment.id));
for (const comment of supersedeCandidates) {
if (keep.has(comment.id)) {
continue;
}
await supersedeCommentIfPresent(comment, 'Superseded old AI review');
}
}
};
-347
View File
@@ -1,347 +0,0 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const postPrComment = require('./post-pr-comment.js');
const OBSOLETE_MARKER = '<!-- claude-review-obsolete -->';
const OBSOLETE_TITLE = 'Claude Code Review - OBSOLETE';
function makeComment(id, body, createdAt, updatedAt) {
return {
id,
body,
created_at: createdAt,
updated_at: updatedAt || createdAt,
};
}
function createHarness(initialComments, options = {}) {
let comments = initialComments.map(comment => ({...comment}));
let nextCommentId = options.nextCommentId || 1000;
let paginateCount = 0;
const calls = {
update: [],
create: [],
delete: [],
};
const github = {
paginate: async () => {
paginateCount++;
if (options.onPaginate) {
const updated = options.onPaginate({
paginateCount,
comments: comments.map(comment => ({...comment})),
});
if (updated) {
comments = updated.map(comment => ({...comment}));
}
}
return comments.map(comment => ({...comment}));
},
rest: {
issues: {
listComments: () => {
throw new Error('listComments should only be used through paginate');
},
updateComment: async ({comment_id, body}) => {
calls.update.push({comment_id, body});
const error =
options.updateErrors && options.updateErrors[comment_id];
if (error) {
throw error;
}
const index =
comments.findIndex(comment => comment.id === comment_id);
if (index === -1) {
const notFound = new Error(`Comment ${comment_id} not found`);
notFound.status = 404;
throw notFound;
}
const updated = {
...comments[index],
body,
updated_at: options.updateTimestamp || '2026-04-24T00:00:00Z',
};
comments[index] = updated;
return {data: {...updated}};
},
createComment: async ({issue_number, body}) => {
calls.create.push({issue_number, body});
const created = makeComment(
nextCommentId++, body,
options.createTimestamp || '2026-04-24T00:00:00Z');
comments.push(created);
return {data: {id: created.id}};
},
deleteComment: async ({comment_id}) => {
calls.delete.push({comment_id});
const error =
options.deleteErrors && options.deleteErrors[comment_id];
if (error) {
throw error;
}
comments = comments.filter(comment => comment.id !== comment_id);
},
},
},
};
return {
github,
calls,
getComments: () => comments.map(comment => ({...comment})),
};
}
function createCore() {
return {
info: () => {},
warning: () => {},
};
}
function escapeRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function assertObsoleteComment(comment, originalBody) {
assert.ok(comment);
assert.match(comment.body, new RegExp(escapeRegExp(OBSOLETE_MARKER)));
assert.match(comment.body, new RegExp(`## ${escapeRegExp(OBSOLETE_TITLE)}`));
assert.match(comment.body, /<details>/);
assert.match(comment.body, /Superseded by a newer AI review/);
assert.match(comment.body, new RegExp(escapeRegExp(originalBody)));
}
const context = {
repo: {
owner: 'facebook',
repo: 'rocksdb',
},
};
test(
'creates a fresh review comment and supersedes legacy comments',
async () => {
const harness = createHarness(
[
makeComment(
1, '<!-- claude-review-auto -->\nold legacy', 'not-a-date'),
makeComment(
2, '<!-- claude-review-auto -->\nnew legacy',
'2026-04-21T00:00:00Z'),
],
{
updateTimestamp: '2026-04-24T00:00:00Z',
});
await postPrComment({
github: harness.github,
context,
core: createCore(),
prNumber: 14659,
body: 'review body',
marker: '<!-- claude-review-auto-run-500 -->',
legacyMarkers: ['<!-- claude-review-auto -->'],
prunePrefix: '<!-- claude-review-auto-',
preserveLatest: 1,
obsoleteMarker: OBSOLETE_MARKER,
obsoleteTitle: OBSOLETE_TITLE,
});
assert.equal(harness.calls.create.length, 1);
assert.deepEqual(
harness.calls.update.map(call => call.comment_id), [2, 1]);
assert.equal(harness.calls.delete.length, 0);
const comments = harness.getComments();
assert.equal(comments.length, 3);
assert.match(
comments.find(comment => comment.id === 1000).body,
/<!-- claude-review-auto-run-500 -->/);
assertObsoleteComment(
comments.find(comment => comment.id === 2),
'<!-- claude-review-auto -->\nnew legacy');
assertObsoleteComment(
comments.find(comment => comment.id === 1),
'<!-- claude-review-auto -->\nold legacy');
});
test(
'updates an exact-match comment and supersedes leftover legacy comments',
async () => {
const harness = createHarness(
[
makeComment(
3, '<!-- claude-review-auto-abcdef0 -->\ncurrent body',
'2026-04-24T00:00:00Z'),
makeComment(
4, '<!-- claude-review-auto -->\nlegacy body',
'2026-04-20T00:00:00Z'),
],
{
updateTimestamp: '2026-04-24T01:00:00Z',
});
await postPrComment({
github: harness.github,
context,
core: createCore(),
prNumber: 14659,
body: 'refreshed body',
marker: '<!-- claude-review-auto-abcdef0 -->',
legacyMarkers: ['<!-- claude-review-auto -->'],
prunePrefix: '<!-- claude-review-auto-',
preserveLatest: 1,
obsoleteMarker: OBSOLETE_MARKER,
obsoleteTitle: OBSOLETE_TITLE,
});
assert.deepEqual(
harness.calls.update.map(call => call.comment_id), [3, 4]);
assert.equal(harness.calls.create.length, 0);
assert.equal(harness.calls.delete.length, 0);
const comments = harness.getComments();
assert.match(
comments.find(comment => comment.id === 3).body,
/<!-- claude-review-auto-abcdef0 -->\nrefreshed body/);
assertObsoleteComment(
comments.find(comment => comment.id === 4),
'<!-- claude-review-auto -->\nlegacy body');
});
test(
'creates a new comment if the target disappears before update',
async () => {
const missing = new Error('gone');
missing.status = 404;
const harness = createHarness(
[
makeComment(
10, '<!-- claude-review-auto-abcdef0 -->\nold body',
'2026-04-20T00:00:00Z'),
],
{
updateErrors: {
10: missing,
},
});
await postPrComment({
github: harness.github,
context,
core: createCore(),
prNumber: 14659,
body: 'replacement body',
marker: '<!-- claude-review-auto-abcdef0 -->',
});
assert.equal(harness.calls.update.length, 1);
assert.equal(harness.calls.create.length, 1);
assert.match(
harness.calls.create[0].body, /<!-- claude-review-auto-abcdef0 -->/);
});
test(
'ignores 404 when superseding a comment already deleted by another run',
async () => {
const missing = new Error('gone');
missing.status = 404;
const harness = createHarness(
[
makeComment(
20, '<!-- claude-review-auto-oldest -->\noldest',
'2026-04-20T00:00:00Z'),
makeComment(
21, '<!-- claude-review-auto-newer -->\nnewer',
'2026-04-21T00:00:00Z'),
],
{
nextCommentId: 30,
createTimestamp: '2026-04-24T00:00:00Z',
deleteErrors: {
20: missing,
},
});
await postPrComment({
github: harness.github,
context,
core: createCore(),
prNumber: 14659,
body: 'fresh body',
marker: '<!-- claude-review-auto-latest -->',
prunePrefix: '<!-- claude-review-auto-',
preserveLatest: 1,
obsoleteMarker: OBSOLETE_MARKER,
obsoleteTitle: OBSOLETE_TITLE,
});
assert.equal(harness.calls.create.length, 1);
assert.equal(harness.calls.delete.length, 0);
assert.deepEqual(
harness.calls.update.map(call => call.comment_id), [21, 20]);
const comments = harness.getComments();
assertObsoleteComment(
comments.find(comment => comment.id === 21),
'<!-- claude-review-auto-newer -->\nnewer');
});
test(
'supersedes the current review when a newer concurrent one appears',
async () => {
const harness = createHarness(
[
makeComment(
40, '<!-- claude-review-auto-current -->\ncurrent',
'2026-04-20T00:00:00Z'),
makeComment(
41, '<!-- claude-review-auto-older -->\nolder',
'2026-04-19T00:00:00Z'),
],
{
updateTimestamp: '2026-04-24T00:00:00Z',
onPaginate: ({paginateCount, comments}) => {
if (paginateCount !== 2) {
return comments;
}
return comments.concat([
makeComment(
42, '<!-- claude-review-auto-newer -->\nnewer',
'2026-04-25T00:00:00Z'),
]);
},
});
await postPrComment({
github: harness.github,
context,
core: createCore(),
prNumber: 14659,
body: 'updated current body',
marker: '<!-- claude-review-auto-current -->',
prunePrefix: '<!-- claude-review-auto-',
preserveLatest: 1,
obsoleteMarker: OBSOLETE_MARKER,
obsoleteTitle: OBSOLETE_TITLE,
});
assert.deepEqual(
harness.calls.update.map(call => call.comment_id), [40, 40, 41]);
assert.equal(harness.calls.delete.length, 0);
const comments = harness.getComments();
assert.match(
comments.find(comment => comment.id === 42).body,
/<!-- claude-review-auto-newer -->\nnewer/);
assertObsoleteComment(
comments.find(comment => comment.id === 40),
'<!-- claude-review-auto-current -->\nupdated current body');
assertObsoleteComment(
comments.find(comment => comment.id === 41),
'<!-- claude-review-auto-older -->\nolder');
});
File diff suppressed because it is too large. Load diff
-203
View File
@@ -1,203 +0,0 @@
# Shared comment-posting workflow for AI reviews.
name: AI Review Comment
on:
workflow_call:
inputs:
provider:
description: Provider key, for example "claude" or "codex"
required: true
type: string
result_artifact_name:
description: Artifact name produced by the analysis workflow
required: true
type: string
comment_file:
description: Markdown comment file produced by the analysis workflow
required: true
type: string
permissions:
pull-requests: write
issues: write
jobs:
comment:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Checkout scripts
uses: actions/checkout@v4
with:
sparse-checkout: .github/scripts
sparse-checkout-cone-mode: true
- name: Download review artifact
id: download
uses: actions/download-artifact@v4
with:
name: ${{ inputs.result_artifact_name }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: _artifact
continue-on-error: true
- name: Post or update PR comment
if: steps.download.outcome == 'success'
env:
PROVIDER: ${{ inputs.provider }}
COMMENT_FILE: ${{ inputs.comment_file }}
RUN_ID: ${{ github.event.workflow_run.id }}
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const artifactDir = '_artifact';
const commentFile = path.join(
artifactDir,
process.env.COMMENT_FILE
);
const prNumberFile = path.join(artifactDir, 'pr_number.txt');
const triggerTypeFile = path.join(artifactDir, 'trigger_type.txt');
const headShaFile = path.join(artifactDir, 'head_sha.txt');
if (!fs.existsSync(commentFile) ||
!fs.existsSync(prNumberFile)) {
core.info('No review results found; skipping.');
return;
}
const post = require('./.github/scripts/post-pr-comment.js');
const provider = process.env.PROVIDER;
const providerTitle = provider === 'codex' ? 'Codex' : 'Claude';
const body = fs.readFileSync(commentFile, 'utf8');
const prNumber = parseInt(
fs.readFileSync(prNumberFile, 'utf8').trim(),
10
);
const trigger = fs.existsSync(triggerTypeFile) ?
fs.readFileSync(triggerTypeFile, 'utf8').trim() :
'auto';
const headSha = fs.existsSync(headShaFile) ?
fs.readFileSync(headShaFile, 'utf8').trim() :
'';
const shortSha = headSha ? headSha.substring(0, 7) : '';
const runId = process.env.RUN_ID;
let marker = '';
let legacyMarkers = [];
let prunePrefix = '';
let preserveLatest = 0;
let obsoleteMarker = '';
let obsoleteTitle = '';
if (trigger === 'auto') {
if (!shortSha) {
core.warning(
'Missing head_sha.txt for auto review; skipping comment.'
);
return;
}
marker = `<!-- ${provider}-review-auto-run-${runId} -->`;
legacyMarkers = [`<!-- ${provider}-review-auto -->`];
prunePrefix = `<!-- ${provider}-review-auto-`;
preserveLatest = 1;
obsoleteMarker = `<!-- ${provider}-review-obsolete -->`;
obsoleteTitle = `${providerTitle} Code Review - OBSOLETE`;
} else {
marker = `<!-- ${provider}-review-manual-run-${runId} -->`;
}
await post({
github,
context,
core,
prNumber,
body,
marker,
legacyMarkers,
prunePrefix,
preserveLatest,
obsoleteMarker,
obsoleteTitle,
});
- name: Add reaction to trigger comment
if: steps.download.outcome == 'success'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const artifactDir = '_artifact';
const triggerTypeFile = path.join(artifactDir, 'trigger_type.txt');
const commentIdFile = path.join(artifactDir, 'comment_id.txt');
if (!fs.existsSync(triggerTypeFile)) return;
const trigger = fs.readFileSync(triggerTypeFile, 'utf8').trim();
if (trigger !== 'manual') return;
if (!fs.existsSync(commentIdFile)) return;
const commentId = parseInt(
fs.readFileSync(commentIdFile, 'utf8').trim(),
10
);
if (!commentId) return;
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: commentId,
content: 'rocket'
});
failure-notice:
if: github.event.workflow_run.conclusion == 'failure'
runs-on: ubuntu-latest
steps:
- name: Download artifact for PR number
id: download
uses: actions/download-artifact@v4
with:
name: ${{ inputs.result_artifact_name }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: _artifact
continue-on-error: true
- name: React with failure
if: steps.download.outcome == 'success'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const commentIdFile = path.join('_artifact', 'comment_id.txt');
if (!fs.existsSync(commentIdFile)) return;
const commentId = parseInt(
fs.readFileSync(commentIdFile, 'utf8').trim(),
10
);
if (!commentId) return;
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: commentId,
content: 'confused'
});
unauthorized-notice:
runs-on: ubuntu-latest
if: >-
github.event.workflow_run.event == 'issue_comment' &&
github.event.workflow_run.conclusion == 'skipped'
steps:
- name: Log skipped unauthorized request
uses: actions/github-script@v7
with:
script: |
core.info(
'Analysis workflow was skipped, which usually means the ' +
'issue_comment requester was not in the authorized list.'
);
-59
View File
@@ -1,59 +0,0 @@
name: Post clang-tidy PR comment
on:
workflow_run:
workflows: ["clang-tidy"]
types: [completed]
permissions:
pull-requests: write
jobs:
comment:
if: github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout scripts
uses: actions/checkout@v4
with:
sparse-checkout: .github/scripts
sparse-checkout-cone-mode: true
- name: Download clang-tidy results
id: download
uses: actions/download-artifact@v4.1.3
with:
name: clang-tidy-result
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: _artifact
continue-on-error: true
- name: Post or update PR comment
if: steps.download.outcome == 'success'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (!fs.existsSync('_artifact/clang-tidy-comment.md') ||
!fs.existsSync('_artifact/pr_number.txt')) {
core.info('No clang-tidy results found; skipping.');
return;
}
const body = fs.readFileSync(
'_artifact/clang-tidy-comment.md',
'utf8'
);
const prNumber = parseInt(
fs.readFileSync('_artifact/pr_number.txt', 'utf8').trim(),
10
);
const post = require('./.github/scripts/post-pr-comment.js');
await post({
github,
context,
core,
prNumber,
body,
marker: '<!-- clang-tidy-bot -->',
});
-74
View File
@@ -1,74 +0,0 @@
name: clang-tidy
on:
push:
pull_request:
permissions: {}
jobs:
clang-tidy:
if: github.repository_owner == 'facebook'
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
steps:
- uses: actions/checkout@v4.1.0
with:
fetch-depth: 2
- name: Mark workspace as safe for git
run: git config --global --add safe.directory $GITHUB_WORKSPACE
- name: Determine diff base
id: diff-base
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
git fetch --depth=1 origin "$BASE"
else
BASE="${{ github.event.before }}"
if echo "$BASE" | grep -q '^0\{40\}$'; then
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "New branch push; skipping clang-tidy."
exit 0
fi
fi
echo "ref=$BASE" >> "$GITHUB_OUTPUT"
echo "skip=false" >> "$GITHUB_OUTPUT"
- name: Install clang-tidy
if: steps.diff-base.outputs.skip != 'true'
run: apt-get update && apt-get install -y clang-tidy-21 && ln -sf /usr/bin/clang-tidy-21 /usr/local/bin/clang-tidy
- name: Generate compile_commands.json
if: steps.diff-base.outputs.skip != 'true'
run: |
mkdir build && cd build
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_C_COMPILER=clang-21 \
-DCMAKE_CXX_COMPILER=clang++-21 ..
cd ..
ln -sf build/compile_commands.json compile_commands.json
- name: Run clang-tidy on changed files
id: clang-tidy
if: steps.diff-base.outputs.skip != 'true'
run: |
python3 tools/run_clang_tidy.py \
-j 4 \
--diff-base ${{ steps.diff-base.outputs.ref }} \
--github-annotations \
--github-step-summary \
--comment-output clang-tidy-comment.md
continue-on-error: true
- name: Save PR number
if: github.event_name == 'pull_request' && always()
run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
- name: Upload clang-tidy results
if: always()
uses: actions/upload-artifact@v4.0.0
with:
name: clang-tidy-result
path: |
clang-tidy-comment.md
pr_number.txt
if-no-files-found: ignore
- name: Fail if clang-tidy found issues
if: steps.clang-tidy.outcome == 'failure'
run: exit 1
@@ -1,24 +0,0 @@
# Claude Code Review — Comment Posting Workflow
#
# Thin wrapper around .github/workflows/ai-review-comment.yml so the provider
# specific workflow name stays stable while the shared implementation lives in
# one reusable workflow.
name: Post Claude Review Comment
on:
workflow_run:
workflows: ["Claude Code Review"]
types: [completed]
permissions:
pull-requests: write
issues: write
jobs:
review-comment:
uses: ./.github/workflows/ai-review-comment.yml
with:
provider: claude
result_artifact_name: claude-review-result
comment_file: claude-review-comment.md
-69
View File
@@ -1,69 +0,0 @@
# Claude Code Review — Analysis Workflow
#
# Thin wrapper around .github/workflows/ai-review-analysis.yml so provider
# specific triggers and workflow_dispatch inputs stay stable while the shared
# implementation lives in one reusable workflow.
name: Claude Code Review
on:
workflow_run:
workflows: ["facebook/rocksdb/pr-jobs"]
types: [completed]
# The early pull_request_target path is limited to same-repo PRs by the job
# condition below. Fork PRs skip this path and rely on workflow_run instead.
pull_request_target:
types: [opened, reopened, synchronize]
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: PR number to review
required: true
type: number
model:
description: Claude model to use (defaults to latest Opus)
required: false
type: choice
options:
- claude-opus-4-6
- claude-sonnet-4-6
default: claude-opus-4-6
thinking_budget:
description: Override MAX_THINKING_TOKENS (blank = auto-classify, capped at 24000)
required: false
type: string
default: ""
permissions:
contents: read
# The shared analysis workflow polls check state, inspects prior runs, and
# reads PR metadata. Keep those permissions read-only in the caller.
actions: read
checks: read
pull-requests: read
jobs:
review:
if: >-
github.event_name != 'pull_request_target' ||
github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/workflows/ai-review-analysis.yml
with:
provider: claude
display_name: Claude
review_command: /claude-review
query_command: /claude-query
result_artifact_name: claude-review-result
comment_file: claude-review-comment.md
default_model: claude-opus-4-6
selected_model: ${{ github.event_name == 'workflow_dispatch' && inputs.model || '' }}
classifier_model: claude-sonnet-4-6
recovery_model: claude-sonnet-4-6
thinking_budget: ${{ github.event_name == 'workflow_dispatch' && inputs.thinking_budget || '' }}
dispatch_pr_number: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || '' }}
secrets: inherit
@@ -1,24 +0,0 @@
# Codex Code Review — Comment Posting Workflow
#
# Thin wrapper around .github/workflows/ai-review-comment.yml so the provider
# specific workflow name stays stable while the shared implementation lives in
# one reusable workflow.
name: Post Codex Review Comment
on:
workflow_run:
workflows: ["Codex Code Review"]
types: [completed]
permissions:
pull-requests: write
issues: write
jobs:
review-comment:
uses: ./.github/workflows/ai-review-comment.yml
with:
provider: codex
result_artifact_name: codex-review-result
comment_file: codex-review-comment.md
-63
View File
@@ -1,63 +0,0 @@
# Codex Code Review — Analysis Workflow
#
# Thin wrapper around .github/workflows/ai-review-analysis.yml so provider
# specific triggers and workflow_dispatch inputs stay stable while the shared
# implementation lives in one reusable workflow.
name: Codex Code Review
on:
# Automatic PR reviews are temporarily disabled while Codex authentication is
# repaired. Manual review requests remain available through issue comments
# and workflow_dispatch.
issue_comment:
types: [created]
workflow_dispatch:
inputs:
pr_number:
description: PR number to review
required: true
type: number
model:
description: Codex model to use
required: false
type: choice
options:
- gpt-5.5
- gpt-5.3-codex
- gpt-5.2-codex
default: gpt-5.5
thinking_budget:
description: Override MAX_THINKING_TOKENS (blank = auto-classify)
required: false
type: string
default: ""
permissions:
contents: read
# The shared analysis workflow polls check state, inspects prior runs, and
# reads PR metadata. Keep those permissions read-only in the caller.
actions: read
checks: read
pull-requests: read
jobs:
review:
if: >-
github.event_name != 'pull_request_target' ||
github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/workflows/ai-review-analysis.yml
with:
provider: codex
display_name: Codex
review_command: /codex-review
query_command: /codex-query
result_artifact_name: codex-review-result
comment_file: codex-review-comment.md
default_model: gpt-5.5
selected_model: ${{ github.event_name == 'workflow_dispatch' && inputs.model || '' }}
thinking_budget: ${{ github.event_name == 'workflow_dispatch' && inputs.thinking_budget || '' }}
dispatch_pr_number: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || '' }}
secrets: inherit
+10 -56
View File
@@ -41,41 +41,21 @@ jobs:
- uses: "./.github/actions/pre-steps"
- run: make V=1 -j32 check
- uses: "./.github/actions/post-steps"
build-linux-clang-21-asan-ubsan-with-folly:
build-linux-clang-18-asan-ubsan-with-folly:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
env:
CC: clang-21
CXX: clang++-21
CC: clang-18
CXX: clang++-18
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- name: Build folly and dependencies
run: |
clean_path=()
IFS=: read -ra path_entries <<< "$PATH"
for entry in "${path_entries[@]}"; do
if [[ "$entry" != "/usr/lib/ccache" ]]; then
clean_path+=("$entry")
fi
done
export PATH="$(IFS=:; echo "${clean_path[*]}")"
ccache_bin="$(command -v ccache || true)"
if [[ -n "$ccache_bin" && -x "$ccache_bin" ]]; then
mv "$ccache_bin" "${ccache_bin}.disabled"
fi
export CC=gcc
export CXX=g++
export USE_CCACHE=0
export CCACHE_DISABLE=1
make build_folly
shell: bash
- uses: "./.github/actions/build-folly"
- run: LIB_MODE=static USE_CLANG=1 USE_FOLLY=1 COMPILE_WITH_UBSAN=1 COMPILE_WITH_ASAN=1 make -j32 check
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-folly:
@@ -88,7 +68,6 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- uses: "./.github/actions/cache-folly"
id: cache-folly
@@ -107,16 +86,16 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- run: "DEBUG_LEVEL=0 make -j20 build_folly"
- run: "USE_FOLLY=1 LIB_MODE=static DEBUG_LEVEL=0 V=1 make -j20 release"
- run: "(mkdir build && cd build && cmake -DUSE_FOLLY=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 -DCMAKE_BUILD_TYPE=Release .. && make VERBOSE=1 -j20 && ctest -j20)"
- uses: "./.github/actions/post-steps"
build-windows-msvc-avx2:
build-windows-vs2022-avx2:
if: ${{ github.repository_owner == 'facebook' }}
runs-on: windows-8-core
runs-on: windows-2022
env:
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_PORTABLE: AVX2
steps:
- uses: actions/checkout@v4.1.0
@@ -131,30 +110,6 @@ jobs:
- run: sudo apt-get update && sudo apt-get install -y build-essential libgflags-dev
- run: make V=1 J=4 -j4 check
- uses: "./.github/actions/post-steps"
build-linux-arm-crashtest:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu-arm
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: sudo apt-get update && sudo apt-get install -y build-essential libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
- run: sudo mount -o remount,size=16G /dev/shm
- name: Ensure swap space
run: |-
if sudo swapon --show=NAME --noheadings --raw | grep -Fxq /swapfile; then
echo "/swapfile is already active"
else
sudo dd bs=1048576 count=4096 if=/dev/zero of=/swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
fi
sudo swapon --show
- run: ulimit -S -n `ulimit -H -n` && make V=1 -j8 CRASH_TEST_EXT_ARGS='--duration=1800 --max_key=2500000' blackbox_crash_test_with_atomic_flush
- run: rm -rf /dev/shm/rocksdb.*
- run: ulimit -S -n `ulimit -H -n` && make V=1 -j8 CRASH_TEST_EXT_ARGS='--duration=1800 --max_key=2500000' blackbox_crash_test_with_multiops_wc_txn
- uses: "./.github/actions/post-steps"
build-examples:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
@@ -173,13 +128,13 @@ jobs:
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- name: Build rocksdb lib
run: CC=clang-21 CXX=clang++-21 USE_CLANG=1 make -j4 static_lib
run: CC=clang-18 CXX=clang++-18 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"
@@ -193,7 +148,6 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- 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 VERBOSE=1 -j20 && ctest -j20)"
- uses: "./.github/actions/post-steps"
+107 -340
View File
@@ -1,18 +1,7 @@
name: facebook/rocksdb/pr-jobs
on: [push, pull_request]
permissions: {}
env:
# Set to a job name to run only that job (on any repo), or leave empty for
# normal behavior (all jobs on facebook repo only).
ONLY_JOB: ''
jobs:
config:
runs-on: ubuntu-latest
outputs:
only_job: ${{ steps.set.outputs.only_job }}
steps:
- id: set
run: echo "only_job=$ONLY_JOB" >> "$GITHUB_OUTPUT"
# NOTE: multiple workflows would be recommended, but the current GHA UI in
# PRs doesn't make it clear when there's an overall error with a workflow,
# making it easy to overlook something broken. Grouping everything into one
@@ -30,10 +19,6 @@ jobs:
# increasing the risk of misconfiguration, especially on forks that might
# want to run with this GHA setup.
#
# SELECTIVE JOB EXECUTION: Set the ONLY_JOB env var at the top of this file
# to a job name (e.g. "build-linux-clang-tidy") to run only that job,
# bypassing the repository owner check. Leave it empty for normal behavior.
#
# DEBUGGING WITH SSH: Temporarily add this as a job step, either before the
# step of interest without the "if:" line or after the failing step with the
# "if:" line. Then use ssh command printed in CI output.
@@ -45,8 +30,7 @@ jobs:
# ======================== Fast Initial Checks ====================== #
check-format-and-targets:
if: needs.config.outputs.only_job == 'check-format-and-targets' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4.1.0
@@ -60,22 +44,14 @@ jobs:
run: python -m pip install --upgrade pip
- name: Install argparse
run: pip install argparse
- name: Install clang-format
run: |
pip install https://files.pythonhosted.org/packages/fb/ac/3c04772acc0257f5730e83adb542b2603c1a62d1315010ab593a980af404/clang_format-21.1.2-py2.py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
clang-format --version
- name: Download clang-format-diff.py
# Mirrored on the "third-party-deps" GitHub release; add/update via
# https://github.com/facebook/rocksdb/releases/edit/third-party-deps
run: wget --tries=3 --retry-on-host-error https://github.com/facebook/rocksdb/releases/download/third-party-deps/clang-format-diff.py
run: wget https://rocksdb-deps.s3.us-west-2.amazonaws.com/llvm/llvm-project/release/12.x/clang/tools/clang-format/clang-format-diff.py
- name: Check format
run: VERBOSE_CHECK=1 make check-format
- name: Compare buckify output
run: make check-buck-targets
- name: Simple source code checks
run: make check-sources
- name: Validate GitHub Actions YAML
run: make check-workflow-yaml
- name: Sanity check check_format_compatible.sh
run: |-
export TEST_TMPDIR=/dev/shm/rocksdb
@@ -86,8 +62,7 @@ jobs:
SANITY_CHECK=1 LONG_TEST=1 tools/check_format_compatible.sh
# ========================= Linux With Tests ======================== #
build-linux:
if: needs.config.outputs.only_job == 'build-linux' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
@@ -96,27 +71,18 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: build-linux
- run: make V=1 J=32 -j32 check
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-cmake-mingw:
if: needs.config.outputs.only_job == 'build-linux-cmake-mingw' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: cmake-mingw
- run: update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
- name: Build cmake-mingw
run: |-
@@ -125,37 +91,27 @@ jobs:
which java && java -version
which javac && javac -version
mkdir build && cd build && cmake -DJNI=1 -DWITH_GFLAGS=OFF .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb rocksdbjni
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-make-with-folly:
if: needs.config.outputs.only_job == 'build-linux-make-with-folly' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: make-with-folly
- uses: "./.github/actions/cache-folly"
id: cache-folly
- uses: "./.github/actions/build-folly"
with:
cache-hit: ${{ steps.cache-folly.outputs.cache-hit }}
- run: USE_FOLLY=1 LIB_MODE=static V=1 make -j64 check
- uses: "./.github/actions/teardown-ccache"
if: always()
- run: USE_FOLLY=1 LIB_MODE=static V=1 make -j32 check
- uses: "./.github/actions/post-steps"
build-linux-make-with-folly-lite-no-test:
if: needs.config.outputs.only_job == 'build-linux-make-with-folly-lite-no-test' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
@@ -164,70 +120,41 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: make-folly-lite
- run: USE_FOLLY_LITE=1 EXTRA_CXXFLAGS=-DGLOG_USE_GLOG_EXPORT V=1 make -j32 all
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-folly-coroutines:
if: needs.config.outputs.only_job == 'build-linux-cmake-with-folly-coroutines' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: cmake-folly-coroutines
- uses: "./.github/actions/cache-folly"
id: cache-folly
- uses: "./.github/actions/build-folly"
with:
cache-hit: ${{ steps.cache-folly.outputs.cache-hit }}
- run: "(mkdir build && cd build && cmake -DUSE_COROUTINES=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 -DPORTABLE=ON .. && make VERBOSE=1 -j64 && ctest -j64)"
- uses: "./.github/actions/teardown-ccache"
if: always()
- run: "(mkdir build && cd build && cmake -DUSE_COROUTINES=1 -DWITH_GFLAGS=1 -DROCKSDB_BUILD_SHARED=0 .. && make VERBOSE=1 -j20 && ctest -j20)"
- uses: "./.github/actions/post-steps"
build-linux-cmake-with-benchmark-no-thread-status:
if: needs.config.outputs.only_job == 'build-linux-cmake-with-benchmark-no-thread-status' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2, 3]
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: cmake-benchmark
- name: Build
run: mkdir build && cd build && cmake -DWITH_GFLAGS=1 -DWITH_BENCHMARK=1 -DPORTABLE=ON -DCMAKE_CXX_FLAGS=-DNROCKSDB_THREAD_STATUS .. && make VERBOSE=1 -j20
- name: Test shard ${{ matrix.shard }} of 4
run: cd build && ctest -j20 -I ${{ matrix.shard }},,4
- uses: "./.github/actions/teardown-ccache"
if: always()
- run: mkdir build && cd build && cmake -DWITH_GFLAGS=1 -DWITH_BENCHMARK=1 -DCMAKE_CXX_FLAGS=-DNROCKSDB_THREAD_STATUS .. && make VERBOSE=1 -j20 && ctest -j20
- uses: "./.github/actions/post-steps"
with:
artifact-prefix: "${{ github.job }}-shard${{ matrix.shard }}"
build-linux-encrypted_env-no_compression:
if: needs.config.outputs.only_job == 'build-linux-encrypted_env-no_compression' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
@@ -236,18 +163,12 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: encrypted-env-no-compression
- run: ENCRYPTED_ENV=1 ROCKSDB_DISABLE_SNAPPY=1 ROCKSDB_DISABLE_ZLIB=1 ROCKSDB_DISABLE_BZIP=1 ROCKSDB_DISABLE_LZ4=1 ROCKSDB_DISABLE_ZSTD=1 make V=1 J=32 -j32 check
- run: "./sst_dump --help | grep -E -q 'Supported built-in compression types: kNoCompression$' # Verify no compiled in compression\n"
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
# ======================== Linux No Test Runs ======================= #
build-linux-release:
if: needs.config.outputs.only_job == 'build-linux-release' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
@@ -255,9 +176,6 @@ jobs:
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: release
- run: make V=1 -j32 LIB_MODE=shared release
- run: ls librocksdb.so
- run: "./trace_analyzer --version" # A tool dependent on gflags that can run in release build
@@ -274,12 +192,9 @@ jobs:
- run: USE_RTTI=1 make V=1 -j32 release
- run: ls librocksdb.a
- run: if ./trace_analyzer --version; then false; else true; fi
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-clang-13-no_test_run:
if: needs.config.outputs.only_job == 'build-linux-clang-13-no_test_run' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 8-core-ubuntu
container:
@@ -288,108 +203,61 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: clang-13
# 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
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-clang-21-no_test_run:
if: needs.config.outputs.only_job == 'build-linux-clang-21-no_test_run' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
build-linux-clang-18-no_test_run:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: clang-21
- run: CC=clang-21 CXX=clang++-21 USE_CLANG=1 make -j32 all microbench
- run: CC=clang-18 CXX=clang++-18 USE_CLANG=1 make -j32 all microbench
- run: make clean
- run: CC=clang-21 CXX=clang++-21 USE_CLANG=1 DEBUG_LEVEL=0 make -j32 release
- name: Install clang-format-21 for C API gen checks
run: apt-get update && apt-get install -y clang-format-21
- name: Check C API codegen (link-complete, backward-compatible, up to date)
# Run the make target in STRICT mode so this core CI job HARD-FAILS rather
# than silently skipping if a prerequisite (clang++, clang-format, or the
# compat baseline ref) is ever missing. See `make check-c-api-gen`.
env:
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
run: |
# The container checkout is owned by a different user, so git refuses to
# operate on it ("dubious ownership") -- mark it safe for the `git fetch`
# and the `git show` the compat checker runs.
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global --add safe.directory '*'
# A PR must preserve the API of its merge target, while a push must
# preserve the API of the branch before the push. Comparing every event
# with main produces false removals when a release branch predates APIs
# added to main.
case "$GITHUB_EVENT_NAME" in
pull_request) api_compat_ref="$PR_BASE_SHA" ;;
push) api_compat_ref="$PUSH_BEFORE_SHA" ;;
*)
echo "ERROR: unsupported event for C API compatibility: $GITHUB_EVENT_NAME" >&2
exit 1
;;
esac
if [ -z "$api_compat_ref" ]; then
echo "ERROR: C API compatibility baseline is empty" >&2
exit 1
fi
zero_sha=0000000000000000000000000000000000000000
if [ "$api_compat_ref" = "$zero_sha" ]; then
# A newly created branch or tag has no prior ref state to preserve.
api_compat_ref=HEAD
else
git fetch --no-tags --depth=1 origin "$api_compat_ref"
api_compat_ref=FETCH_HEAD
fi
CXX=clang++-21 make check-c-api-gen \
CHECK_C_API_GEN_STRICT=1 \
API_COMPAT_REF="$api_compat_ref" \
CLANG_FORMAT_BINARY=clang-format-21
- uses: "./.github/actions/teardown-ccache"
if: always()
- run: CC=clang-18 CXX=clang++-18 USE_CLANG=1 DEBUG_LEVEL=0 make -j32 release
- uses: "./.github/actions/post-steps"
build-linux-gcc-14-no_test_run:
if: needs.config.outputs.only_job == 'build-linux-gcc-14-no_test_run' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: gcc-14
- run: CC=gcc-14 CXX=g++-14 V=1 make -j32 all microbench
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
# ======================== Linux Other Checks ======================= #
build-linux-clang18-clang-analyze:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
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
- uses: "./.github/actions/post-steps"
- name: compress test report
run: tar -cvzf scan_build_report.tar.gz scan_build_report
if: failure()
- uses: actions/upload-artifact@v4.0.0
with:
name: scan-build-report
path: scan_build_report.tar.gz
build-linux-unity-and-headers:
if: needs.config.outputs.only_job == 'build-linux-unity-and-headers' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
@@ -398,111 +266,49 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- run: apt-get update -y && apt-get install -y libgflags-dev
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: unity-headers
- name: Unity build
run: make V=1 -j8 unity_test
- run: make V=1 -j8 -k check-headers
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-mini-crashtest:
if: needs.config.outputs.only_job == 'build-linux-mini-crashtest' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
strategy:
fail-fast: false
matrix:
include:
- crash_test_target: blackbox_crash_test_with_atomic_flush
crash_duration: 480
- crash_test_target: blackbox_crash_test
crash_duration: 240
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb --ulimit nofile=1048576:1048576
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/cache-getdeps-downloads"
- uses: "./.github/actions/setup-folly"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: mini-crashtest
- uses: "./.github/actions/cache-folly"
id: cache-folly
- uses: "./.github/actions/build-folly"
with:
cache-hit: ${{ steps.cache-folly.outputs.cache-hit }}
- run: |
ulimit -S -n $(ulimit -Hn) # Raise open files soft limit to hard limit
echo "Updated ulimit -Hn: $(ulimit -Hn) -Sn: $(ulimit -Sn)"
USE_COROUTINES=1 USE_FOLLY=1 LIB_MODE=static make V=1 -j8 CRASH_TEST_EXT_ARGS='--duration=${{ matrix.crash_duration }} --max_key=2500000' ${{ matrix.crash_test_target }}
- uses: "./.github/actions/teardown-ccache"
if: always()
- 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"
with:
artifact-prefix: "${{ github.job }}-${{ matrix.crash_test_target }}"
# ======================= Linux with Sanitizers ===================== #
build-linux-clang21-asan-ubsan:
if: needs.config.outputs.only_job == 'build-linux-clang21-asan-ubsan' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
build-linux-clang18-asan-ubsan:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2]
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: clang21-asan-ubsan
- run: COMPILE_WITH_ASAN=1 COMPILE_WITH_UBSAN=1 CC=clang-21 CXX=clang++-21 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j40 check
env:
CI_SHARD_INDEX: ${{ matrix.shard }}
CI_TOTAL_SHARDS: 3
- uses: "./.github/actions/teardown-ccache"
if: always()
- 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
- uses: "./.github/actions/post-steps"
with:
artifact-prefix: "${{ github.job }}-shard${{ matrix.shard }}"
build-linux-clang21-mini-tsan:
if: needs.config.outputs.only_job == 'build-linux-clang21-mini-tsan' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
build-linux-clang18-mini-tsan:
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 32-core-ubuntu
strategy:
fail-fast: false
matrix:
shard: [0, 1, 2]
container:
image: ghcr.io/facebook/rocksdb_ubuntu:24.1
image: ghcr.io/facebook/rocksdb_ubuntu:24.0
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: clang21-tsan
- run: COMPILE_WITH_TSAN=1 CC=clang-21 CXX=clang++-21 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
env:
CI_SHARD_INDEX: ${{ matrix.shard }}
CI_TOTAL_SHARDS: 3
- uses: "./.github/actions/teardown-ccache"
if: always()
- run: COMPILE_WITH_TSAN=1 CC=clang-18 CXX=clang++-18 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check
- uses: "./.github/actions/post-steps"
with:
artifact-prefix: "${{ github.job }}-shard${{ matrix.shard }}"
build-linux-static_lib-alt_namespace-status_checked:
if: needs.config.outputs.only_job == 'build-linux-static_lib-alt_namespace-status_checked' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 16-core-ubuntu
container:
@@ -511,17 +317,11 @@ jobs:
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: static-alt-namespace
- 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
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
# ========================= MacOS build only ======================== #
build-macos:
if: needs.config.outputs.only_job == 'build-macos' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: macos-15-xlarge
env:
ROCKSDB_DISABLE_JEMALLOC: 1
@@ -530,21 +330,15 @@ jobs:
- uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: 16.4.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: macos
- uses: "./.github/actions/increase-max-open-files-on-macos"
- uses: "./.github/actions/install-gflags-on-macos"
- uses: "./.github/actions/pre-steps-macos"
- name: Build
run: ulimit -S -n `ulimit -H -n` && make V=1 J=16 -j8 all
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
# ========================= MacOS with Tests ======================== #
build-macos-cmake:
if: needs.config.outputs.only_job == 'build-macos-cmake' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: macos-15-xlarge
strategy:
matrix:
@@ -554,9 +348,6 @@ jobs:
- uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: 16.4.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: macos-cmake
- uses: "./.github/actions/increase-max-open-files-on-macos"
- uses: "./.github/actions/install-gflags-on-macos"
- uses: "./.github/actions/pre-steps-macos"
@@ -576,100 +367,95 @@ jobs:
- name: Run shard 3 out of 4 test shards
run: ulimit -S -n `ulimit -H -n` && cd build && ctest -j8 -I 3,,4
if: ${{ matrix.run_sharded_tests == 3 }}
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
# ======================== Windows with Tests ======================= #
# NOTE: some windows jobs are in "nightly" to save resources
build-windows-msvc:
if: needs.config.outputs.only_job == 'build-windows-msvc' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
build-windows-vs2022:
if: ${{ github.repository_owner == 'facebook' }}
runs-on: windows-8-core
strategy:
fail-fast: false
matrix:
include:
- test_shard: db_test
suite_run: db_test
run_java: "false"
- test_shard: other
suite_run: arena_test,db_basic_test,db_etc2_test,db_merge_operand_test,bloom_test,c_test,coding_test,crc32c_test,dynamic_bloom_test,env_basic_test,env_test,hash_test,random_test
run_java: "false"
- test_shard: java
suite_run: ""
run_java: "true"
env:
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_PORTABLE: 1
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/windows-build-steps"
with:
suite-run: ${{ matrix.suite_run }}
run-java: ${{ matrix.run_java }}
# ============================ Java Jobs ============================ #
build-linux-java:
if: needs.config.outputs.only_job == 'build-linux-java' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
# 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 }}
run: |
chown `whoami` . || true
git clone --no-checkout https://oath2:$GH_TOKEN@github.com/${{ github.repository }}.git .
git -c protocol.version=2 fetch --update-head-ok --no-tags --prune --no-recurse-submodules --depth=1 origin +${{ github.sha }}:${{ github.ref }}
git checkout --progress --force ${{ github.ref }}
git log -1 --format='%H'
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: java
- name: Set Java Environment
run: |-
echo "JAVA_HOME=${JAVA_HOME}"
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
- uses: "./.github/actions/teardown-ccache"
if: always()
# post-steps skipped because of compatibility issues with docker image
build-linux-java-static:
if: needs.config.outputs.only_job == 'build-linux-java-static' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
image: ghcr.io/facebook/rocksdb_ubuntu:22.1
options: --shm-size=16gb
steps:
- uses: actions/checkout@v4.1.0
# 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 }}
run: |
chown `whoami` . || true
git clone --no-checkout https://oath2:$GH_TOKEN@github.com/${{ github.repository }}.git .
git -c protocol.version=2 fetch --update-head-ok --no-tags --prune --no-recurse-submodules --depth=1 origin +${{ github.sha }}:${{ github.ref }}
git checkout --progress --force ${{ github.ref }}
git log -1 --format='%H'
- uses: "./.github/actions/pre-steps"
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: java-static
- name: Set Java Environment
run: |-
echo "JAVA_HOME=${JAVA_HOME}"
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
- uses: "./.github/actions/teardown-ccache"
if: always()
# post-steps skipped because of compatibility issues with docker image
build-macos-java:
if: needs.config.outputs.only_job == 'build-macos-java' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: macos-15-xlarge
env:
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
ROCKSDB_DISABLE_JEMALLOC: 1
steps:
- uses: actions/checkout@v4.1.0
- uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: 16.4.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: macos-java
- uses: "./.github/actions/increase-max-open-files-on-macos"
- uses: "./.github/actions/install-gflags-on-macos"
- uses: "./.github/actions/setup-jdk-on-macos"
- uses: "./.github/actions/install-jdk8-on-macos"
- uses: "./.github/actions/pre-steps-macos"
- name: Set Java Environment
run: |-
@@ -678,24 +464,20 @@ jobs:
which javac && javac -version
- name: Test RocksDBJava
run: make V=1 J=16 -j16 jtest
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-macos-java-static:
if: needs.config.outputs.only_job == 'build-macos-java-static' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: macos-15-xlarge
env:
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
steps:
- uses: actions/checkout@v4.1.0
- uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: 16.4.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: macos-java-static
- uses: "./.github/actions/increase-max-open-files-on-macos"
- uses: "./.github/actions/install-gflags-on-macos"
- uses: "./.github/actions/setup-jdk-on-macos"
- uses: "./.github/actions/install-jdk8-on-macos"
- uses: "./.github/actions/pre-steps-macos"
- name: Set Java Environment
run: |-
@@ -704,24 +486,20 @@ jobs:
which javac && javac -version
- name: Build RocksDBJava x86 and ARM Static Libraries
run: make V=1 J=16 -j16 rocksdbjavastaticosx
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-macos-java-static-universal:
if: needs.config.outputs.only_job == 'build-macos-java-static-universal' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on: macos-15-xlarge
env:
JAVA_HOME: "/Library/Java/JavaVirtualMachines/liberica-jdk-8.jdk/Contents/Home"
steps:
- uses: actions/checkout@v4.1.0
- uses: maxim-lobanov/setup-xcode@v1.6.0
with:
xcode-version: 16.4.0
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: macos-java-static-universal
- uses: "./.github/actions/increase-max-open-files-on-macos"
- uses: "./.github/actions/install-gflags-on-macos"
- uses: "./.github/actions/setup-jdk-on-macos"
- uses: "./.github/actions/install-jdk8-on-macos"
- uses: "./.github/actions/pre-steps-macos"
- name: Set Java Environment
run: |-
@@ -730,12 +508,9 @@ jobs:
which javac && javac -version
- name: Build RocksDBJava Universal Binary Static Library
run: make V=1 J=16 -j16 rocksdbjavastaticosx_ub
- uses: "./.github/actions/teardown-ccache"
if: always()
- uses: "./.github/actions/post-steps"
build-linux-java-pmd:
if: needs.config.outputs.only_job == 'build-linux-java-pmd' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu
container:
@@ -761,20 +536,12 @@ jobs:
name: maven-site
path: "${{ github.workspace }}/java/target/site"
build-linux-arm:
if: needs.config.outputs.only_job == 'build-linux-arm' || (needs.config.outputs.only_job == '' && github.repository_owner == 'facebook')
needs: config
if: ${{ github.repository_owner == 'facebook' }}
runs-on:
labels: 4-core-ubuntu-arm
steps:
- uses: actions/checkout@v4.1.0
- uses: "./.github/actions/pre-steps"
- run: sudo apt-get update && sudo apt-get install -y build-essential ccache
- uses: "./.github/actions/setup-ccache"
with:
cache-key-prefix: arm
- run: sudo apt-get update && sudo apt-get install -y build-essential
- run: ROCKSDBTESTS_PLATFORM_DEPENDENT=only make V=1 J=4 -j4 all_but_some_tests check_some
- name: Print ccache stats
run: ccache -s
if: always()
shell: bash
- uses: "./.github/actions/post-steps"
+1 -13
View File
@@ -1,7 +1,5 @@
make_config.mk
rocksdb.pc
.build_signature
build_tools/__pycache__/
*.a
*.arc
@@ -54,7 +52,7 @@ GRTAGS
GTAGS
rocksdb_dump
rocksdb_undump
db_etc2_test
db_test2
trace_analyzer
block_cache_trace_analyzer
io_tracer_parser
@@ -90,8 +88,6 @@ fbcode/
fbcode
buckifier/*.pyc
buckifier/__pycache__
tools/__pycache__/
tools/c_api_gen/__pycache__/
.arcconfig
compile_commands.json
@@ -106,11 +102,3 @@ cmake-build-*
third-party/folly/
.cache
*.sublime-*
# Claude Code local settings
.claude/settings.local.json
tools/__pycache__/
# Keep documentation trackable even if broader ignores match names like "*_test".
!docs/
!docs/**
-9
View File
@@ -1,9 +0,0 @@
# Agent Instructions
This repository's authoritative agent instructions live in `CLAUDE.md`.
Read and follow [`CLAUDE.md`](./CLAUDE.md) in full before making changes or
reviewing code in this checkout.
If there is any ambiguity between this file and `CLAUDE.md`, `CLAUDE.md` takes
precedence.
+11 -110
View File
@@ -32,15 +32,12 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"db/blob/blob_file_cache.cc",
"db/blob/blob_file_garbage.cc",
"db/blob/blob_file_meta.cc",
"db/blob/blob_file_partition_manager.cc",
"db/blob/blob_file_reader.cc",
"db/blob/blob_garbage_meter.cc",
"db/blob/blob_gen2_format.cc",
"db/blob/blob_log_format.cc",
"db/blob/blob_log_sequential_reader.cc",
"db/blob/blob_log_writer.cc",
"db/blob/blob_source.cc",
"db/blob/blob_write_batch_transformer.cc",
"db/blob/prefetch_buffer_collection.cc",
"db/builder.cc",
"db/c.cc",
@@ -59,7 +56,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"db/compaction/sst_partitioner.cc",
"db/compaction/subcompaction_state.cc",
"db/convenience.cc",
"db/coro_db.cc",
"db/db_filesnapshot.cc",
"db/db_impl/compacted_db_impl.cc",
"db/db_impl/db_impl.cc",
@@ -104,17 +100,14 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"db/snapshot_impl.cc",
"db/table_cache.cc",
"db/table_properties_collector.cc",
"db/transaction_log_impl.cc",
"db/trim_history_scheduler.cc",
"db/version_builder.cc",
"db/version_edit.cc",
"db/version_edit_handler.cc",
"db/version_set.cc",
"db/version_util.cc",
"db/wal_edit.cc",
"db/wal_iterator_impl.cc",
"db/wal_manager.cc",
"db/wide/lazy_wide_columns.cc",
"db/wide/read_path_blob_resolver.cc",
"db/wide/wide_column_serialization.cc",
"db/wide/wide_columns.cc",
"db/wide/wide_columns_helper.cc",
@@ -214,7 +207,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"table/block_based/hash_index_reader.cc",
"table/block_based/index_builder.cc",
"table/block_based/index_reader_common.cc",
"table/block_based/multi_scan_index_iterator.cc",
"table/block_based/parsed_full_filter_block.cc",
"table/block_based/partitioned_filter_block.cc",
"table/block_based/partitioned_index_iterator.cc",
@@ -270,14 +262,12 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"util/compression.cc",
"util/compression_context_cache.cc",
"util/concurrent_task_limiter_impl.cc",
"util/coro_stats_util.cc",
"util/crc32c.cc",
"util/crc32c_arm64.cc",
"util/data_structure.cc",
"util/dynamic_bloom.cc",
"util/file_checksum_helper.cc",
"util/hash.cc",
"util/io_dispatcher_imp.cc",
"util/murmurhash.cc",
"util/random.cc",
"util/rate_limiter.cc",
@@ -309,7 +299,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"utilities/compaction_filters.cc",
"utilities/compaction_filters/remove_emptyvalue_compactionfilter.cc",
"utilities/convenience/info_log_finder.cc",
"utilities/copy_engine/copy_engine.cc",
"utilities/counted_fs.cc",
"utilities/debug.cc",
"utilities/env_mirror.cc",
@@ -339,7 +328,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"utilities/secondary_index/simple_secondary_index.cc",
"utilities/simulator_cache/cache_simulator.cc",
"utilities/simulator_cache/sim_cache.cc",
"utilities/sorted_run_builder/sorted_run_builder.cc",
"utilities/table_properties_collectors/compact_for_tiering_collector.cc",
"utilities/table_properties_collectors/compact_on_deletion_collector.cc",
"utilities/trace/file_trace_reader_writer.cc",
@@ -373,9 +361,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"utilities/transactions/write_prepared_txn_db.cc",
"utilities/transactions/write_unprepared_txn.cc",
"utilities/transactions/write_unprepared_txn_db.cc",
"utilities/trie_index/bitvector.cc",
"utilities/trie_index/louds_trie.cc",
"utilities/trie_index/trie_index_factory.cc",
"utilities/ttl/db_ttl_impl.cc",
"utilities/types_util.cc",
"utilities/wal_filter.cc",
@@ -383,21 +368,11 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"utilities/write_batch_with_index/write_batch_with_index_internal.cc",
], deps=[
"//folly/container:f14_hash",
"//folly/coro:baton",
"//folly/coro:blocking_wait",
"//folly/coro:collect",
"//folly/coro:coroutine",
"//folly/coro:nothrow",
"//folly/coro:task",
"//folly/executors/thread_factory:named_thread_factory",
"//folly/executors:io_executor",
"//folly/executors:io_thread_pool_executor",
"//folly/io/async:async_base",
"//folly/io/async:event_base_manager",
"//folly/io/async:io_uring_backend",
"//folly/io/async:request_context",
"//folly/experimental/coro:blocking_wait",
"//folly/experimental/coro:collect",
"//folly/experimental/coro:coroutine",
"//folly/experimental/coro:task",
"//folly/synchronization:distributed_mutex",
"//folly:executor",
], headers=glob(["**/*.h"]), link_whole=False, extra_test_libs=False)
cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[], deps=[":rocksdb_lib"], headers=[], link_whole=True, extra_test_libs=False)
@@ -4757,12 +4732,6 @@ cpp_unittest_wrapper(name="configurable_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="copy_engine_test",
srcs=["utilities/copy_engine/copy_engine_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="corruption_test",
srcs=["db/corruption_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -4829,12 +4798,6 @@ cpp_unittest_wrapper(name="db_blob_corruption_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_blob_direct_write_test",
srcs=["db/blob/db_blob_direct_write_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_blob_index_test",
srcs=["db/blob/db_blob_index_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -4859,12 +4822,6 @@ cpp_unittest_wrapper(name="db_clip_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_compaction_abort_test",
srcs=["db/db_compaction_abort_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_compaction_filter_test",
srcs=["db/db_compaction_filter_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -4889,12 +4846,6 @@ cpp_unittest_wrapper(name="db_encryption_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_etc2_test",
srcs=["db/db_etc2_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_etc3_test",
srcs=["db/db_etc3_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -4949,12 +4900,6 @@ cpp_unittest_wrapper(name="db_kv_checksum_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_lazy_entity_test",
srcs=["db/wide/db_lazy_entity_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_log_iter_test",
srcs=["db/db_log_iter_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -4985,12 +4930,6 @@ cpp_unittest_wrapper(name="db_merge_operator_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_open_with_config_test",
srcs=["db/db_open_with_config_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_options_test",
srcs=["db/db_options_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5057,6 +4996,12 @@ cpp_unittest_wrapper(name="db_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_test2",
srcs=["db/db_test2.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_universal_compaction_test",
srcs=["db/db_universal_compaction_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5075,12 +5020,6 @@ cpp_unittest_wrapper(name="db_wide_basic_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_wide_blob_direct_write_test",
srcs=["db/wide/db_wide_blob_direct_write_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="db_with_timestamp_basic_test",
srcs=["db/db_with_timestamp_basic_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5191,12 +5130,6 @@ cpp_unittest_wrapper(name="faiss_ivf_index_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="fault_injection_fs_test",
srcs=["utilities/fault_injection_fs_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="fault_injection_test",
srcs=["db/fault_injection_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5281,12 +5214,6 @@ cpp_unittest_wrapper(name="interval_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="io_dispatcher_test",
srcs=["util/io_dispatcher_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="io_posix_test",
srcs=["env/io_posix_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5581,12 +5508,6 @@ cpp_unittest_wrapper(name="slice_transform_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="sorted_run_builder_test",
srcs=["utilities/sorted_run_builder/sorted_run_builder_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="sst_dump_test",
srcs=["tools/sst_dump_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5689,18 +5610,6 @@ cpp_unittest_wrapper(name="transaction_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="trie_index_db_test",
srcs=["utilities/trie_index/trie_index_db_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="trie_index_test",
srcs=["utilities/trie_index/trie_index_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="ttl_test",
srcs=["utilities/ttl/ttl_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5803,12 +5712,6 @@ cpp_unittest_wrapper(name="write_controller_test",
extra_compiler_flags=[])
cpp_unittest_wrapper(name="write_prepared_transaction_seqno_test",
srcs=["utilities/transactions/write_prepared_transaction_seqno_test.cc"],
deps=[":rocksdb_test_lib"],
extra_compiler_flags=[])
cpp_unittest_wrapper(name="write_prepared_transaction_test",
srcs=["utilities/transactions/write_prepared_transaction_test.cc"],
deps=[":rocksdb_test_lib"],
@@ -5822,5 +5725,3 @@ cpp_unittest_wrapper(name="write_unprepared_transaction_test",
export_file(name = "tools/db_crashtest.py")
export_file(name = "tools/fault_injection_log_parser.py")
-461
View File
@@ -1,461 +0,0 @@
# RocksDB Code Generation and Review Guidance
This document provides guidance for generating and reviewing code in the RocksDB project, derived from analysis of code review feedback across hundreds of complex merged Pull Requests. Use this as a reference when writing code with AI assistants or conducting code reviews.
---
## General Best Practices
### Code Quality and Maintainability
**Clarity and Readability:** Write clear, self-documenting code. Use meaningful variable names, add comments for complex logic, and structure code to minimize cognitive load. Avoid clever tricks that sacrifice readability for marginal performance gains unless absolutely necessary. Avoid static_cast, reinterpret_cast, and C-style casts; static_cast_with_check, up_cast, and lossless_cast from cast_util.h are preferred.
**Consistent Style:** Follow existing code style conventions. RocksDB uses `.clang-format` for formatting, specific naming conventions, and structural patterns. Deviations from these patterns are frequently flagged in reviews.
**Error Handling:** Ensure robust error handling throughout the codebase. Use RocksDB's `Status` type consistently, propagate errors appropriately, and avoid silently ignoring failures. Reviewers pay close attention to edge cases and failure modes.
### Testing Philosophy
**Comprehensive Coverage:** Every change should include appropriate test coverage. This includes unit tests for isolated functionality, integration tests for component interactions, and stress tests for concurrency and performance validation. Reviewers will ask for additional tests if coverage is insufficient.
**Edge Cases and Failure Modes:** Tests should explicitly cover edge cases, boundary conditions, and potential failure scenarios. This is especially important for changes affecting core database operations, compaction, or recovery logic.
**Platform-Specific Testing:** RocksDB supports multiple platforms (Linux, Windows, macOS) and compilers (GCC, Clang, MSVC). Changes should be tested across relevant platforms, particularly when touching platform-specific code or using compiler-specific features.
### Performance Considerations
**⚠️ PERFORMANCE IS CRITICAL:** RocksDB is a high-performance storage engine where every CPU cycle and memory access matters. When writing code, always evaluate from a performance perspective. This is not optional—performance-aware coding is a fundamental requirement for all contributions.
**Benchmarking and Profiling:** Performance claims should be backed by empirical evidence. Use RocksDB's benchmarking tools (e.g., `db_bench`) to validate improvements. Reviewers will request benchmark results for changes that could impact performance.
**Memory Allocation:** Minimize dynamic memory allocations, especially in hot paths. Prefer stack allocation over heap allocation. Reuse buffers when possible. Consider using arena allocators or memory pools for frequent small allocations. Every `new`, `malloc`, or container resize has a cost.
**Memory Copy:** Avoid unnecessary memory copies. Use move semantics, `std::string_view`, `Slice`, and pass-by-reference where appropriate. Be aware of implicit copies in STL containers and function returns. Prefer in-place operations over copy-and-modify patterns.
**CPU Cache Efficiency:** Design data structures and access patterns to be cache-friendly. Keep frequently accessed data together (data locality). Prefer sequential memory access over random access. Be mindful of cache line sizes (typically 64 bytes) and avoid false sharing in concurrent code. Consider struct packing and field ordering to improve cache utilization.
**Loop Optimization:** Look for opportunities to collapse nested loops, reduce loop overhead, and minimize branch mispredictions. Hoist invariant computations out of loops. Consider loop unrolling for tight inner loops. Batch operations when possible to amortize per-operation overhead.
**SIMD and Vectorization:** Leverage SIMD instructions (SSE, AVX) for data-parallel operations when appropriate. Structure data to enable auto-vectorization by the compiler. Consider explicit SIMD intrinsics for critical hot paths like checksum computation, encoding/decoding, and bulk data processing.
**Branch Prediction:** Minimize unpredictable branches in hot paths. Use `LIKELY`/`UNLIKELY` macros to hint branch prediction, e.g. for error cases and other rare or otherwise costly cases, but NOT for predicting popular configurations. Consider branchless alternatives for simple conditionals. Order switch cases and if-else chains by frequency.
**Memory and Resource Management:** Be mindful of memory allocations, especially in hot paths. Use RAII patterns, smart pointers, and RocksDB's memory management utilities appropriately.
**Hot Path Analysis:** When deciding how aggressively to optimize code, consider whether it's on a hot path:
- **Hot path** (executed thousands+ times, e.g., data access, iteration, compaction loops): Performance is paramount. Apply all optimization techniques—loop collapsing, SIMD, cache optimization, pre-allocation, etc. The cost of each operation is multiplied by execution frequency.
- **Cold path** (executed rarely, e.g., DB open, configuration parsing, error handling): Maintainability and clarity are more important. Prefer readable code over micro-optimizations. Complex optimizations here add maintenance burden with negligible performance benefit.
- **Warm path** (moderate frequency): Balance both concerns. Use profiling data to guide optimization decisions.
**Avoid Premature Optimization:** While performance is critical, focus on correctness first, then optimize based on profiling data. However, be performance-aware from the start—choosing the right algorithm and data structure upfront is not premature optimization. Use the hot path analysis above to decide how much optimization effort is warranted.
### API Design and Compatibility
**Backwards Compatibility:** RocksDB maintains strong backwards compatibility guarantees. Breaking changes are rare and require extensive justification. When deprecating features, follow the project's deprecation policy (typically spanning multiple releases).
**API Consistency:** New APIs should be consistent with existing patterns. Use similar naming conventions, parameter ordering, and return types. Reviewers will suggest changes to improve consistency with the broader codebase.
**Documentation:** Public APIs must be thoroughly documented, without unnecessary embelishment nor dwelling on implementation details nor project planning. When non-obvious, include usage examples, parameter descriptions, known bugs or limitations, notes on thread safety, performance characteristics, and compatibility considerations. Re-read comments for ambiguous terminology and phrasing, such as ambiguously re-purposed programming jargon.
---
## Component-Specific Guidance
### Database Core (`db`)
The database core handles write-ahead logging (WAL), memtables, compaction, and recovery. This component receives the most scrutiny in code reviews.
**Concurrency and Thread Safety:** Database operations are highly concurrent. Reviewers carefully examine locking strategies, atomic operations, and memory ordering. Document synchronization assumptions clearly. Use appropriate memory ordering semantics (`acquire`/`release` vs. `seq_cst`).
**Compaction Logic:** Changes to compaction are complex and high-risk. Ensure that compaction logic respects configured parameters, handles edge cases (empty databases, single-file compactions), and maintains correctness under concurrent operations.
**Error Propagation:** Database operations can fail in many ways (I/O errors, corruption, resource exhaustion). Ensure that errors are properly propagated, logged, and handled. Avoid assertions in production code paths.
**Testing:** Database core changes require extensive testing, including unit tests, integration tests, and stress tests. Test with various configurations, compaction styles, and concurrent workloads.
### Public Headers (`include`)
Public headers define RocksDB's API surface. Changes here have the highest compatibility impact.
**API Design:** New APIs should be intuitive, consistent with existing patterns, and well-documented. Consider how the API will be used in practice and avoid adding unnecessary complexity.
**Backwards Compatibility:** Breaking changes to public APIs require extensive justification and a deprecation plan. Maintain ABI compatibility for bug fixes and patch releases.
**Documentation:** Every public API must be thoroughly documented with usage examples, parameter descriptions, and notes on thread safety and performance characteristics.
**Deprecation:** When deprecating APIs, follow the project's policy. Mark deprecated APIs clearly, provide migration guidance, and maintain support for at least one major release.
### Internal Utilities (`util`)
Internal utilities provide common functionality used throughout the codebase.
**Code Reuse:** Utilities should be general-purpose and reusable. Avoid duplicating functionality that already exists elsewhere in the codebase.
**Error Handling:** Utility functions should handle errors robustly and propagate them appropriately. Consider edge cases like overflow, underflow, and invalid inputs.
**Testing:** Utility functions should have comprehensive test coverage, including edge cases and failure modes. Consider adding death tests for assertions.
**Performance:** Utilities are often used in hot paths. Ensure that implementations are efficient and avoid unnecessary allocations or copies.
### Table Management (`table`)
Table management handles SST file format, block-based tables, and table readers/writers.
**Block Format and Checksums:** Changes to block format require extreme care. Ensure that checksums are computed and verified correctly. Test with various compression algorithms and block sizes.
**Iterator Correctness:** Table iterators are used throughout the codebase. Ensure that iterator semantics (Seek, Next, Prev) are correct, especially at boundaries and with deletions.
**Caching and Prefetching:** Table readers interact with the block cache and prefetching logic. Ensure that cache keys are unique and that prefetching respects configured limits.
**Performance:** Table operations are performance-critical. Benchmark changes that could impact read or write performance.
### Utilities (`utilities`)
Utilities include optional features like transactions, backup engine, and checkpoint.
**Feature Isolation:** Utilities should be self-contained and not introduce unnecessary dependencies on core database internals.
**Deprecation and Cleanup:** Legacy features are being phased out. When removing deprecated code, ensure that migration paths are documented and that users have sufficient warning.
**Cross-Platform Compatibility:** Utilities often interact with OS-specific APIs. Ensure that code works on all supported platforms.
### Options and Configuration (`options`)
Options define RocksDB's configuration system.
**Type Safety:** Use appropriate types for options (e.g., `uint32_t` for flags, scoped enums for enumerated values).
**Deprecation Policy:** When deprecating options, follow the project's policy. Document the deprecation, provide migration guidance, and maintain support for at least one major release.
**Dynamic Configuration:** Some options can be changed dynamically. Ensure that dynamic changes are thread-safe and take effect correctly.
**Validation:** Validate option values and provide clear error messages for invalid configurations.
### Cache (`cache`)
Cache management is critical for RocksDB's performance.
**Concurrency:** Cache operations are highly concurrent. Ensure that implementations are thread-safe and use appropriate synchronization primitives.
**Performance:** Cache operations are in the hot path. Optimize for low latency and high throughput. Benchmark changes carefully.
**Memory Management:** Cache implementations must manage memory carefully to avoid leaks and excessive allocations.
**Eviction Policies:** Changes to eviction policies should be well-tested and benchmarked to ensure they improve overall performance.
---
## Code Review Checklist
When reviewing RocksDB code (or preparing code for review), use this checklist:
### Contract Boundaries
- [ ] Is each behavior owned by the right layer? High-level policy (for example,
"compaction wants this I/O mode") should live at the caller/policy layer, while
lower layers should expose generic mechanisms (for example, "open a fresh
reader", "skip shared cache insertion", or "use these FileOptions").
- [ ] Do comments and names describe local contracts rather than leaking a
specific caller's rationale into reusable APIs? Generic code should not need to
know about one current use case unless the API itself is intentionally
use-case-specific.
- [ ] Does each flag or parameter control one coherent behavior? If one boolean
starts implying ownership, cache policy, I/O mode, prefetching, and caller
identity, split it into explicit flags or an options struct.
- [ ] Could a future caller use this lower-level API without accidentally
inheriting assumptions from compaction, backup, user reads, or a particular
table format? If not, tighten the contract with assertions, clearer names, or
a narrower API.
- [ ] Are implementation details not being used as policy signals? Prefer an
explicit contract over inferring behavior from incidental fields such as file
options, cache handles, or current table-reader state.
### Correctness
- [ ] Does the change preserve database semantics (e.g., snapshot isolation, key ordering)?
- [ ] Are all error cases handled appropriately?
- [ ] Is the change thread-safe? Are synchronization primitives used correctly?
- [ ] Are there any potential data races or deadlocks?
### Testing
- [ ] Does the change include appropriate test coverage?
- [ ] Are edge cases and failure modes tested?
- [ ] Have the tests been run on all supported platforms?
- [ ] Are stress tests passing?
### Performance
- [ ] Are there benchmark results for performance-sensitive changes?
- [ ] Does the change avoid unnecessary allocations or copies?
- [ ] Are hot paths optimized appropriately?
### API and Compatibility
- [ ] Is the change backwards compatible?
- [ ] Are new APIs consistent with existing patterns?
- [ ] Is the public API documented?
- [ ] Are deprecated features handled according to policy?
### Code Quality
- [ ] Does the code follow RocksDB's style conventions?
- [ ] Is the code clear and maintainable?
- [ ] Are comments and documentation sufficient?
- [ ] Are there any code smells or anti-patterns?
---
## Common Review Feedback Patterns
The following patterns emerged as frequent sources of review feedback:
1. **Test Coverage:** Reviewers frequently request additional tests for edge cases, platform-specific behavior, and failure modes. Complex changes require comprehensive test coverage including unit tests, integration tests, and stress tests.
2. **Error Handling:** Ensure proper error propagation using RocksDB's `Status` type. Avoid silent failures and provide clear error messages that include context about what failed and why.
3. **API Design:** New APIs should be consistent with existing patterns. Use descriptive names that follow established conventions. Avoid breaking changes without strong justification and a clear deprecation plan.
4. **Documentation:** Public APIs must be documented with usage examples and notes on thread safety, performance characteristics, and compatibility considerations. Complex internal logic should also be well-commented.
5. **Performance:** Performance-sensitive changes require benchmark results to validate improvements. Use `db_bench` and other profiling tools to measure impact. Avoid premature optimization that adds complexity without measurable benefit.
6. **Concurrency:** Thread safety is critical in RocksDB. Document synchronization assumptions clearly. Use appropriate memory ordering semantics. Consider potential race conditions and deadlocks.
7. **Code Style:** Follow existing conventions for naming, formatting, and structure. Use `.clang-format` for consistent formatting. Prefer scoped enums (`enum class`) over unscoped enums.
8. **Backwards Compatibility:** RocksDB maintains strong compatibility guarantees. Breaking changes require extensive justification. When deprecating features, provide migration guidance and maintain support across multiple releases.
9. **Refactoring:** Reviewers appreciate refactoring that improves code readability and maintainability. Look for opportunities to deduplicate code and simplify complex logic.
10. **Platform Compatibility:** Ensure changes work correctly on all supported platforms (Linux, Windows, macOS) and with all supported compilers (GCC, Clang, MSVC).
11. **Contract Boundary Leaks:** When a change plumbs a new option or use-case
specific behavior through multiple subsystems, review the call chain for
contract leaks. Caller-specific rationale belongs at the call site or public API
documentation; reusable layers should expose precise, layer-local capabilities.
Watch especially for comments mentioning one caller in generic code, booleans
that silently bundle several behaviors, and downstream code inferring policy
from an implementation detail instead of an explicit option.
---
## Important tips
### Build system
* There are 3 build system. Make for git clones, BUCK (meta internal) for hg
clones, and CMake for some special cases.
* When a new .cc file is added, update Makefile, CMakeLists.txt, src.mk, BUCK.
* Don't manually edit BUCK file, after updating src.mk, run
/usr/local/bin/python3 buckifier/buckify_rocksdb.py to update it
* For -j in make command, use the number of CPU cores to decide it.
* When searching for references to something (a symbol, library, etc.), do not
restrict or truncate your search based on presumed relevance or scope. It is
important and time-saving to keep the repo reasonably consistent across
different build systems, programming languages, and even between
documentation and implementation.
### Avoiding mixed build modes with Make (use `AUTO_CLEAN=1`)
Object files are written to the same paths regardless of build flags, so
reusing objects from a prior build with different flags causes confusing
linker errors, etc. This problem is essentially avoidable by ALWAYS using
`AUTO_CLEAN=1 make -j<n> <something>` for manual make invocations. This
will automatically clean object files if the build parameters/flavor have
changed. The `build_tools/rockstest.sh` / `rocksptest.sh` helpers described
below set `AUTO_CLEAN=1` for you.
`AUTO_CLEAN=1` does not fix Make failures associated with stale .d files
referring to removed files. Resolve that manually or with `make clean`
without complaining to the user.
### Source checks
* Run `make check-sources` before committing. This catches non-ASCII
characters in source files and other source-level issues that CI will
reject. In particular, **do not use Unicode characters** (em dashes,
smart quotes, etc.) in comments or strings -- use ASCII equivalents
(`--` instead of em dash, `'` instead of smart quote, etc.).
### License headers
* Every new source file needs a license header. For a file that does **not**
carry an outside/third-party copyright, use the standard Meta dual-licensed
header (the dual-license designation is required -- a bare
"All Rights Reserved" copyright is not an acceptable open-source header):
```
// 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).
```
Use a `#` comment prefix instead of `//` for shell, Python, and Makefile
fragments.
* Files derived from an external source (e.g. LevelDB) keep their original
upstream copyright line in addition to the header above.
### RTTI and dynamic_cast
* Production code and `db_stress` must build in **release mode
(`-fno-rtti`)**. Do not use `dynamic_cast` anywhere except unit tests.
Use `static_cast_with_check` from `util/cast_util.h` (validates with
`dynamic_cast` in debug builds, plain `static_cast` in release).
* Unit tests (`*_test.cc`) are built in debug mode with RTTI enabled.
### Cross-platform / portability
Local `make` only exercises Linux with GCC/Clang, but CI
(`.github/workflows/pr-jobs.yml` and `nightly.yml`) gates on a much wider
matrix, so portability breaks are invisible locally until CI fails. Code must
build (and where noted, run tests) across:
| Axis | Must support |
|------|--------------|
| OS | Linux (x86_64 + ARM), macOS, Windows |
| Architecture | Little-endian and big-endian targets, including Linux on s390x |
| Compiler | GCC, Clang (libstdc++ **and** libc++), AppleClang, **MSVC (VS2022)**, MinGW (Linux cross-compile, build-only, no gflags) |
| Build system | Make, CMake, and BUCK (internal) -- keep all in sync (see "Build system" above) |
| Config | release (`-fno-rtti`), `ASSERT_STATUS_CHECKED`, ASAN/UBSAN/TSAN, folly, unity build, JNI/Java |
Treat these as constraints to satisfy and infer the specifics from them before
adding any system header, libc call, or compiler-specific construct. The most
common trap: anything that compiles under GCC/Clang on Linux but not under
**MSVC/MinGW** -- e.g. unguarded POSIX-only headers/functions (`<unistd.h>`,
`<sys/*.h>`, `getpid`, `_exit`, ...) or GCC/Clang extensions
(`__attribute__`, `__builtin_*`, VLAs, `alloca`). Prefer the `port::`/`Env`
abstractions; otherwise guard with `#ifdef OS_WIN` (POSIX `<unistd.h>` ->
Windows `<process.h>`). Because libc++ is also tested, include what you use
rather than relying on libstdc++ transitive includes.
Do not use `static_assert` to reject a supported architecture for an optional
feature. Check an existing `port::` capability such as `port::kLittleEndian`
and disable only the unsupported feature so the rest of RocksDB still builds.
Use a portable representation when the feature itself must work across
architectures.
### Unit Test
* After all of the unit tests are added, review them and try to extract common
reusable utility functions to reduce code duplication due to copy past between
unit tests. This should be done every time unit test is updated.
* Don't use sleep to wait for certain events to happen. This will cause test to
be flaky. Instead, use sync point to synchronize thread progress.
* Cap unit test execution with 60 seconds timeout.
* To build and run unit tests locally, prefer these helper scripts:
* `build_tools/rocksptest.sh <test_binary> [more_binaries...] [args...]`
builds the binary(ies) with parallel make and `AUTO_CLEAN=1` and runs
them under gtest-parallel, sharding the test cases across CPUs. Prefer
this whenever running more than a couple of test cases, e.g.
`build_tools/rocksptest.sh table_test` or
`build_tools/rocksptest.sh db_test env_test --gtest_filter=*Foo*`.
* `build_tools/rockstest.sh <test_binary> [args...]` builds with parallel
make and `AUTO_CLEAN=1` and runs the binary directly (serially).
Use it only for a very small number of test cases, e.g.
`build_tools/rockstest.sh db_test --gtest_filter=*MixedSlowdown*`.
* After writing a test, stress-test for flakiness (AUTO_CLEAN handles the
rebuild needed by the `COERCE_CONTEXT_SWITCH=1` flag change):
```bash
COERCE_CONTEXT_SWITCH=1 build_tools/rockstest.sh {test_binary} -r100 \
--gtest_filter="*YourTestName*"
```
* For CI-style flaky tests that do not reproduce with `gtest_parallel.py`,
`--gtest_repeat`, or normal coerce-mode runs, inspect
`tools/gtest_parallel_repro.py --help`.
* Each unit test file has overheads, so avoid creating new unit test files
for random minor features. Consider adding to slice_test, db_etc3_test, or
others.
### Unit test dedup guidelines
* Extract helper functions for repeated patterns such as object
construction, round-trip (encode → decode → verify), and common
assertion sequences.
* Use table-driven tests (struct array + loop) when multiple test cases
share the same logic but differ only in input/expected data.
* Prefer randomized tests over exhaustive parameter permutations. Use
`Random` from `util/random.h` (not `std::mt19937`). Use a time-based
seed with `SCOPED_TRACE("seed=" + std::to_string(seed))` so failures
are reproducible.
* Keep deterministic edge-case tests separate from randomized tests
(error paths, boundary conditions, format verification).
* Methods only used in tests should be private with `friend class` +
`TEST_F` fixture wrappers. In wrappers, always fully qualify the
target method to avoid infinite recursion.
### Adding new public API
Refer to claude_md/add_public_api.md
### Adding new option
Refer to claude_md/add_option.md
### Removing deprecated option
Refer to claude_md/remove_option.md
### Metrics
* When adding a new feature, evaluate whether there is opportunity to add
metrics. Try to avoid causing performance regression on hot path when adding
metrics.
### Stress test
* When adding a new feature, make sure stress test covers the new option.
### Component docs
* For component-level design notes and implementation walkthroughs, start with
`docs/components/index.md`.
* Documentation under `docs/components/` is organized by subsystem in
`docs/components/<area>/`.
* Each subsystem directory should have an `index.md` entry point plus focused
chapter files for deeper topics.
### DB bench update
* When adding a performance related feature, support it in db_bench
### Adding release note
* Release note should be kept short at high level for external user consumption.
Release notes identify what users might care about most in a release. They
are not exhaustive and are not a guide. PLEASE learn from past agents who
ried to build elaborate release notes with implementation details and
elsewhere-documented nuance. That wastes time. Fight the bias that
"my change" is important so must be worthy of release note mention.
* If more than single markdown line, consider how their formatting will be
integrated into HISTORY.md.
### Blog posts (docs/_posts)
* Blog post authors must be defined in `docs/_data/authors.yml` to be displayed
### Final verification of the change
* Execute `AUTO_CLEAN=1 make check` to build all of the changes and execute all
of the tests. `AUTO_CLEAN=1` ensures a clean rebuild if your previous build
used different parameters. Note that executing all of the tests could take
multiple minutes.
* Run `AUTO_CLEAN=1 ASSERT_STATUS_CHECKED=1 make check` to verify all Status
objects are properly checked. This catches missing error handling that can
lead to silent data corruption.
### Monitoring make check progress
* Use `make check-progress` to get machine-parseable JSON progress while
`make check` is running. This is useful for Claude Code to monitor long
builds without timeout issues.
* Run `make check` in background, then poll progress:
```bash
AUTO_CLEAN=1 make check &
# Poll periodically:
make check-progress
```
* The output shows current phase and progress:
```json
{"status":"running","phase":"compiling","completed":300,"total":919,...}
{"status":"running","phase":"testing","completed":1500,"total":29962,"failed":0,"percent":5,...}
{"status":"completed","phase":"testing","completed":29962,"total":29962,"failed":0,"percent":100,...}
```
* Phases: `compiling` -> `linking` -> `generating` -> `testing` -> `completed`
* Key fields: `status`, `phase`, `completed`, `total`, `failed`, `percent`
* When tests fail, `failed_tests` array shows details (up to 10 failures):
```json
{"status":"running",...,"failed":3,"failed_tests":[
{"test":"cache_test-CacheTest.Usage","exit_code":1,"signal":0,"output":"...test log..."},
{"test":"env_test-EnvTest.Open","exit_code":0,"signal":11,"output":"...Segmentation fault..."}
]}
```
* `exit_code`: non-zero means test assertion failed
* `signal`: non-zero means test was killed (e.g., 9=SIGKILL, 6=SIGABRT, 11=SIGSEGV)
* `output`: last 50 lines of test log including error messages and stack traces
### Executing benchmark using db_bench
* Since the goal is to measure performance, we need to build a release binary
using `AUTO_CLEAN=1 DEBUG_LEVEL=0 make db_bench`. If there is an engine
crash due to a bug, switch back to a debug build with
`AUTO_CLEAN=1 make dbg`; `AUTO_CLEAN=1` handles the release<->debug rebuild
automatically.
### Formatting code
* After making change, use `make format-auto` to auto-apply formatting without
interactive prompts (Claude Code friendly).
+16 -157
View File
@@ -82,15 +82,10 @@ if(NOT CMAKE_BUILD_TYPE)
endif()
message(STATUS "CMAKE_BUILD_TYPE is set to ${CMAKE_BUILD_TYPE}")
# Use ccache for compilation if available. Use CMAKE_C/CXX_COMPILER_LAUNCHER
# instead of RULE_LAUNCH_COMPILE to avoid double-wrapping when ccache is also
# injected via PATH (e.g., /usr/lib/ccache or brew --prefix ccache/libexec).
# Note: we intentionally do NOT set RULE_LAUNCH_LINK because ccache cannot
# cache link operations -- it only adds overhead.
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set(CMAKE_C_COMPILER_LAUNCHER ccache)
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)
option(WITH_JEMALLOC "build with JeMalloc" OFF)
@@ -224,10 +219,6 @@ if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W4 /wd4127 /wd4996 /wd4100 /wd4324")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DNDEBUG")
message(STATUS "Setting /DNDEBUG as CMAKE_BUILD_TYPE is set to ${CMAKE_BUILD_TYPE}")
endif()
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall -pthread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers -Wno-strict-aliasing -Wno-invalid-offsetof")
@@ -420,6 +411,13 @@ if(WITH_NUMA)
list(APPEND THIRDPARTY_LIBS NUMA::NUMA)
endif()
option(WITH_TBB "build with Threading Building Blocks (TBB)" OFF)
if(WITH_TBB)
find_package(TBB REQUIRED)
add_definitions(-DTBB)
list(APPEND THIRDPARTY_LIBS TBB::TBB)
endif()
# Stall notifications eat some performance from inserts
option(DISABLE_STALL_NOTIF "Build with stall notifications" OFF)
if(DISABLE_STALL_NOTIF)
@@ -513,15 +511,6 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "iOS")
add_definitions(-DOS_MACOSX -DIOS_CROSS_COMPILE)
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-DOS_LINUX)
# Use lld linker if available for faster linking (12x faster than ld.bfd)
if(NOT ROCKSDB_NO_FAST_LINKER)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=lld -Wl,--version
OUTPUT_VARIABLE LLD_VERSION_OUTPUT ERROR_QUIET RESULT_VARIABLE LLD_RESULT)
if(LLD_RESULT EQUAL 0 AND LLD_VERSION_OUTPUT MATCHES "LLD")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld")
endif()
endif()
elseif(CMAKE_SYSTEM_NAME MATCHES "SunOS")
add_definitions(-DOS_SOLARIS)
elseif(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
@@ -647,8 +636,6 @@ if(USE_FOLLY)
FMT_INST_PATH)
exec_program(ls ARGS -d ${FOLLY_INST_PATH}/../gflags* OUTPUT_VARIABLE
GFLAGS_INST_PATH)
exec_program(ls ARGS -d ${FOLLY_INST_PATH}/../glog* OUTPUT_VARIABLE
GLOG_INST_PATH)
set(Boost_DIR ${BOOST_INST_PATH}/lib/cmake/Boost-1.83.0)
if(EXISTS ${FMT_INST_PATH}/lib64)
set(fmt_DIR ${FMT_INST_PATH}/lib64/cmake/fmt)
@@ -656,96 +643,23 @@ if(USE_FOLLY)
set(fmt_DIR ${FMT_INST_PATH}/lib/cmake/fmt)
endif()
set(gflags_DIR ${GFLAGS_INST_PATH}/lib/cmake/gflags)
if(EXISTS ${GLOG_INST_PATH}/lib64/cmake/glog)
set(GLOG_CMAKE_DIR ${GLOG_INST_PATH}/lib64/cmake/glog)
elseif(EXISTS ${GLOG_INST_PATH}/lib/cmake/glog)
set(GLOG_CMAKE_DIR ${GLOG_INST_PATH}/lib/cmake/glog)
endif()
if(NOT GLOG_CMAKE_DIR)
find_library(GETDEPS_GLOG_LIBRARY NAMES glogd glog
PATHS ${GLOG_INST_PATH}/lib64 ${GLOG_INST_PATH}/lib
NO_DEFAULT_PATH)
if(NOT GETDEPS_GLOG_LIBRARY OR
NOT EXISTS ${GLOG_INST_PATH}/include/glog/logging.h)
message(FATAL_ERROR "Could not find getdeps glog under "
"${GLOG_INST_PATH}")
endif()
set(GLOG_CMAKE_DIR ${CMAKE_CURRENT_BINARY_DIR}/getdeps-glog-cmake)
file(MAKE_DIRECTORY ${GLOG_CMAKE_DIR})
file(WRITE ${GLOG_CMAKE_DIR}/glog-config.cmake
"if(NOT TARGET glog::glog)\n"
" add_library(glog::glog UNKNOWN IMPORTED)\n"
" set_target_properties(glog::glog PROPERTIES\n"
" IMPORTED_LOCATION \"${GETDEPS_GLOG_LIBRARY}\"\n"
" INTERFACE_INCLUDE_DIRECTORIES \"${GLOG_INST_PATH}/include\")\n"
"endif()\n"
"set(glog_FOUND TRUE)\n"
"set(Glog_FOUND TRUE)\n"
"set(GLOG_FOUND TRUE)\n"
"set(GLOG_LIBRARY \"${GETDEPS_GLOG_LIBRARY}\")\n"
"set(GLOG_LIBRARIES \"${GETDEPS_GLOG_LIBRARY}\")\n"
"set(GLOG_INCLUDE_DIR \"${GLOG_INST_PATH}/include\")\n")
endif()
set(glog_DIR ${GLOG_CMAKE_DIR})
set(Glog_DIR ${GLOG_CMAKE_DIR})
# Unlike gflags, glog may also be installed system-wide. Pre-resolve the
# getdeps copy so folly-config.cmake cannot fall back to another version.
find_package(glog CONFIG REQUIRED PATHS ${GLOG_CMAKE_DIR}
NO_DEFAULT_PATH)
exec_program(sed ARGS -i 's/gflags_shared//g'
${FOLLY_INST_PATH}/lib/cmake/folly/folly-targets.cmake)
include(${FOLLY_INST_PATH}/lib/cmake/folly/folly-config.cmake)
# Fix gflags library name for debug builds. The getdeps gflags shared
# library is versioned (e.g. libgflags_debug.so.2.3), so resolve the
# actual file by glob rather than hard-coding a version.
# Fix gflags library name for debug builds
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
file(GLOB GFLAGS_DEBUG_SHARED_LIBS
"${GFLAGS_INST_PATH}/lib/libgflags_debug.so.*")
if(NOT GFLAGS_DEBUG_SHARED_LIBS)
message(FATAL_ERROR
"Could not find getdeps libgflags_debug.so under ${GFLAGS_INST_PATH}/lib")
endif()
list(GET GFLAGS_DEBUG_SHARED_LIBS 0 GFLAGS_DEBUG_SHARED_LIB)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath=${GFLAGS_INST_PATH}/lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GFLAGS_DEBUG_SHARED_LIB}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GFLAGS_INST_PATH}/lib/libgflags_debug.so.2.2")
endif()
endif()
# Folly itself uses gflags transitively, but RocksDB tools and benchmarks
# also call gflags APIs directly, so they need an explicit link dependency.
if(WITH_GFLAGS)
if(NOT TARGET gflags::gflags AND NOT TARGET gflags_shared AND
NOT gflags_LIBRARIES)
find_package(gflags CONFIG QUIET)
if(NOT gflags_FOUND)
find_package(gflags REQUIRED)
endif()
endif()
if(TARGET gflags::gflags)
set(GFLAGS_LIB gflags::gflags)
elseif(TARGET gflags_shared)
set(GFLAGS_LIB gflags_shared)
elseif(DEFINED GFLAGS_TARGET AND TARGET ${GFLAGS_TARGET})
set(GFLAGS_LIB ${GFLAGS_TARGET})
elseif(gflags_LIBRARIES)
set(GFLAGS_LIB ${gflags_LIBRARIES})
else()
message(FATAL_ERROR
"WITH_GFLAGS is enabled, but no gflags library could be resolved")
endif()
list(APPEND THIRDPARTY_LIBS ${GFLAGS_LIB})
endif()
add_compile_definitions(USE_FOLLY FOLLY_NO_CONFIG HAVE_CXX11_ATOMIC)
list(APPEND THIRDPARTY_LIBS Folly::folly)
set(FOLLY_LIBS Folly::folly)
# --copy-dt-needed-entries is ld.bfd-specific; lld handles DT_NEEDED transitively
if(NOT CMAKE_EXE_LINKER_FLAGS MATCHES "fuse-ld=lld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--copy-dt-needed-entries")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--copy-dt-needed-entries")
endif()
find_package(Threads REQUIRED)
@@ -772,17 +686,14 @@ set(SOURCES
db/blob/blob_file_addition.cc
db/blob/blob_file_builder.cc
db/blob/blob_file_cache.cc
db/blob/blob_file_partition_manager.cc
db/blob/blob_file_garbage.cc
db/blob/blob_file_meta.cc
db/blob/blob_file_reader.cc
db/blob/blob_garbage_meter.cc
db/blob/blob_gen2_format.cc
db/blob/blob_log_format.cc
db/blob/blob_log_sequential_reader.cc
db/blob/blob_log_writer.cc
db/blob/blob_source.cc
db/blob/blob_write_batch_transformer.cc
db/blob/prefetch_buffer_collection.cc
db/builder.cc
db/c.cc
@@ -801,7 +712,6 @@ set(SOURCES
db/compaction/sst_partitioner.cc
db/compaction/subcompaction_state.cc
db/convenience.cc
db/coro_db.cc
db/db_filesnapshot.cc
db/db_impl/compacted_db_impl.cc
db/db_impl/db_impl.cc
@@ -846,17 +756,14 @@ set(SOURCES
db/snapshot_impl.cc
db/table_cache.cc
db/table_properties_collector.cc
db/transaction_log_impl.cc
db/trim_history_scheduler.cc
db/version_builder.cc
db/version_edit.cc
db/version_edit_handler.cc
db/version_set.cc
db/version_util.cc
db/wal_edit.cc
db/wal_iterator_impl.cc
db/wal_manager.cc
db/wide/lazy_wide_columns.cc
db/wide/read_path_blob_resolver.cc
db/wide/wide_column_serialization.cc
db/wide/wide_columns.cc
db/wide/wide_columns_helper.cc
@@ -931,7 +838,6 @@ set(SOURCES
table/block_based/block_based_table_builder.cc
table/block_based/block_based_table_factory.cc
table/block_based/block_based_table_iterator.cc
table/block_based/multi_scan_index_iterator.cc
table/block_based/block_based_table_reader.cc
table/block_based/block_builder.cc
table/block_based/block_cache.cc
@@ -1004,12 +910,10 @@ set(SOURCES
util/simple_mixed_compressor.cc
util/compression_context_cache.cc
util/concurrent_task_limiter_impl.cc
util/coro_stats_util.cc
util/crc32c.cc
util/data_structure.cc
util/dynamic_bloom.cc
util/hash.cc
util/io_dispatcher_imp.cc
util/murmurhash.cc
util/random.cc
util/rate_limiter.cc
@@ -1026,7 +930,6 @@ set(SOURCES
util/xxhash.cc
utilities/agg_merge/agg_merge.cc
utilities/backup/backup_engine.cc
utilities/copy_engine/copy_engine.cc
utilities/blob_db/blob_compaction_filter.cc
utilities/blob_db/blob_db.cc
utilities/blob_db/blob_db_impl.cc
@@ -1040,7 +943,6 @@ set(SOURCES
utilities/cassandra/merge_operator.cc
utilities/checkpoint/checkpoint_impl.cc
utilities/compaction_filters.cc
utilities/sorted_run_builder/sorted_run_builder.cc
utilities/compaction_filters/remove_emptyvalue_compactionfilter.cc
utilities/counted_fs.cc
utilities/debug.cc
@@ -1092,9 +994,6 @@ set(SOURCES
utilities/transactions/write_prepared_txn_db.cc
utilities/transactions/write_unprepared_txn.cc
utilities/transactions/write_unprepared_txn_db.cc
utilities/trie_index/bitvector.cc
utilities/trie_index/louds_trie.cc
utilities/trie_index/trie_index_factory.cc
utilities/types_util.cc
utilities/ttl/db_ttl_impl.cc
utilities/wal_filter.cc
@@ -1210,23 +1109,8 @@ if(USE_FOLLY_LITE)
FMT_INCLUDE_DIR)
include_directories(${FMT_INCLUDE_DIR})
exec_program(python3 ${PROJECT_SOURCE_DIR}/third-party/folly ARGS
build/fbcode_builder/getdeps.py show-inst-dir glog OUTPUT_VARIABLE
GLOG_INST_PATH)
if(EXISTS ${GLOG_INST_PATH}/lib64)
set(GLOG_LIB_DIR ${GLOG_INST_PATH}/lib64)
else()
set(GLOG_LIB_DIR ${GLOG_INST_PATH}/lib)
endif()
add_definitions(-DUSE_FOLLY -DFOLLY_NO_CONFIG)
find_library(GLOG_LIBRARY NAMES glog PATHS ${GLOG_LIB_DIR} NO_DEFAULT_PATH)
if(NOT GLOG_LIBRARY)
find_library(GLOG_LIBRARY NAMES glog)
endif()
if(GLOG_LIBRARY)
list(APPEND THIRDPARTY_LIBS ${GLOG_LIBRARY})
endif()
list(APPEND THIRDPARTY_LIBS glog)
endif()
set(ROCKSDB_STATIC_LIB rocksdb${ARTIFACT_SUFFIX})
@@ -1472,7 +1356,6 @@ if(WITH_TESTS)
db/blob/blob_garbage_meter_test.cc
db/blob/blob_source_test.cc
db/blob/db_blob_basic_test.cc
db/blob/db_blob_direct_write_test.cc
db/blob/db_blob_compaction_test.cc
db/blob/db_blob_corruption_test.cc
db/blob/db_blob_index_test.cc
@@ -1494,11 +1377,9 @@ if(WITH_TESTS)
db/db_bloom_filter_test.cc
db/db_compaction_filter_test.cc
db/db_compaction_test.cc
db/db_compaction_abort_test.cc
db/db_clip_test.cc
db/db_dynamic_level_test.cc
db/db_encryption_test.cc
db/db_etc2_test.cc
db/db_etc3_test.cc
db/db_flush_test.cc
db/db_inplace_update_test.cc
@@ -1511,7 +1392,6 @@ if(WITH_TESTS)
db/db_memtable_test.cc
db/db_merge_operator_test.cc
db/db_merge_operand_test.cc
db/db_open_with_config_test.cc
db/db_options_test.cc
db/db_properties_test.cc
db/db_range_del_test.cc
@@ -1522,6 +1402,7 @@ if(WITH_TESTS)
db/db_table_properties_test.cc
db/db_tailing_iter_test.cc
db/db_test.cc
db/db_test2.cc
db/db_logical_block_size_cache_test.cc
db/db_universal_compaction_test.cc
db/db_wal_test.cc
@@ -1562,9 +1443,7 @@ if(WITH_TESTS)
db/version_set_test.cc
db/wal_manager_test.cc
db/wal_edit_test.cc
db/wide/db_lazy_entity_test.cc
db/wide/db_wide_basic_test.cc
db/wide/db_wide_blob_direct_write_test.cc
db/wide/wide_column_serialization_test.cc
db/wide/wide_columns_helper_test.cc
db/write_batch_test.cc
@@ -1645,10 +1524,7 @@ if(WITH_TESTS)
utilities/cassandra/cassandra_row_merge_test.cc
utilities/cassandra/cassandra_serialize_test.cc
utilities/checkpoint/checkpoint_test.cc
utilities/copy_engine/copy_engine_test.cc
utilities/sorted_run_builder/sorted_run_builder_test.cc
utilities/env_timed_test.cc
utilities/fault_injection_fs_test.cc
utilities/memory/memory_test.cc
utilities/merge_operators/string_append/stringappend_test.cc
utilities/object_registry_test.cc
@@ -1666,12 +1542,9 @@ if(WITH_TESTS)
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_prepared_transaction_seqno_test.cc
utilities/transactions/write_unprepared_transaction_test.cc
utilities/transactions/lock/range/range_locking_test.cc
utilities/transactions/timestamped_snapshot_test.cc
utilities/trie_index/trie_index_db_test.cc
utilities/trie_index/trie_index_test.cc
utilities/ttl/ttl_test.cc
utilities/types_util_test.cc
utilities/util_merge_operators_test.cc
@@ -1713,21 +1586,7 @@ if(WITH_TESTS)
)
target_link_libraries(${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} testharness gtest ${THIRDPARTY_LIBS} ${ROCKSDB_LIB})
if(NOT "${exename}" MATCHES "db_sanity_test")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
# Discover tests at ctest time instead of during the parallel build.
# POST_BUILD discovery (the default) runs each freshly-built test
# binary while the -j build is still compiling; on resource-constrained
# CI (notably the arm64 macOS runners) that discovery run can yield
# empty output, and CMake's JSON parser then aborts the whole build
# with "Syntax error: value, object or array expected". PRE_TEST moves
# discovery out of the build phase so a slow/empty enumeration no
# longer fails the build.
gtest_discover_tests(${exename}
DISCOVERY_TIMEOUT 120
DISCOVERY_MODE PRE_TEST)
else()
gtest_discover_tests(${exename} DISCOVERY_TIMEOUT 120)
endif()
gtest_discover_tests(${exename} DISCOVERY_TIMEOUT 120)
add_dependencies(rocksdb_check ${exename}${ARTIFACT_SUFFIX})
endif()
endforeach(sourcefile ${TESTS})
+1 -217
View File
@@ -1,225 +1,9 @@
# Rocksdb Change Log
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
## 11.9.1 (08/18/2026)
### Public API Changes
* Added an immutable `external_table_config` option that is persisted in OPTIONS files and passed to external table factories during bootstrap.
## 11.9.0 (08/14/2026)
### New Features
* Added an integrated and improved compression auto-skip feature (new CompressionOptions, still experimental) that saves CPU by skipping compression when and where the overall ratio is inadequate. This improves on the previous auto-skip compression manager by (a) taking achieved compression ratios into account, (b) using a continuously evolving payoff estimate, and (c) combining natively with parallel compression.
* Added the `blob_file_writable_file_max_buffer_size` mutable column family option. When set to a non-zero value, blob-file writers use it as their `WritableFileWriter` max buffer size instead of inheriting `DBOptions::writable_file_max_buffer_size`.
* Added an experimental lazy wide-column read API, `DB::GetEntityLazy()` / `DB::MultiGetEntityLazy()` (see `include/rocksdb/lazy_wide_columns.h`). The returned `LazyWideColumns` leaves blob-backed columns as unresolved references and, like an iterator, stays valid after the call returns, so the caller resolves only the columns -- and only the byte ranges -- it needs; a byte-range read of an uncompressed blob (separate-file or embedded) reads just those bytes from storage. Adds `Env::IOActivity::kLazyResolve` and `rocksdb.blobdb.lazy.*` statistics. Requires `max_open_files == -1`.
* Added DB property `rocksdb.num-running-remote-compactions`, reporting the number of compaction service jobs currently waiting in `CompactionService::Wait()`.
* Added DB property `rocksdb.num-unscheduled-compactions`, reporting compactions waiting in the DB's internal compaction queue but not yet assigned to a background job.
* Added `DB::AbortCompactions()` and `DB::ResumeCompactions()` for per-column-family compaction abort and resume, with the same active-abort semantics as the DB-wide `AbortAllCompactions()`/`ResumeAllCompactions()` but scoped to a single column family. Calls are reference-counted independently per column family and compose with the DB-wide abort.
### Public API Changes
* Add IndexFactory compatibility names for the existing user-defined index API.
* Added the experimental `CoroDB` capability, exposed by `DB::GetCoroDB()`, with lazy native coroutine variants of `Get` and `MultiGet`. The existing `DB::GetAsync()` and `DB::MultiGetAsync()` APIs dispatch through it.
* Added `rocksdb_batched_multi_get_pinned_cf()` to return batch-owned pinned MultiGet values and per-key errors without allocating one wrapper per found value.
* Add `DBOptions::read_io_executor_threads` to increase the maximum thread count of the shared filesystem read I/O executor used for asynchronous reads when opening a DB. Opening a DB never reduces the shared executor thread count. Change the experimental `FSRandomAccessFile::SubmitReadAsync()` API to return whether the asynchronous path was used, and add the `FILE_SUBMIT_ASYNC_READ_FALLBACK` ticker to count calls that fall back to synchronous reads.
* `ReadOptions::table_filter` is now a *pointer* to a caller-owned `std::function` instead of a `std::function` value, to improve efficiency in copying and destroying `ReadOptions` objects (which RocksDB does internally). This is a breaking change for users of this relatively obscure option, who will now need to declare a `std::function` that outlives the read. As a side effect of `ReadOptions` being trivially copyable, new but legitimate compiler warnings may surface.
* Removed the experimental `CreateAutoSkipCompressionManager()`. Auto-skip compression is now a first-class feature of the block-based table builder, controlled by the new experimental `CompressionOptions::auto_skip`.
* Added `CoroStackableDB` for implementing wrappers over native coroutine reads and used it to add coroutine `Get` and `MultiGet` support to `DBWithTTL` and WritePrepared `TransactionDB`. A stackable wrapper advertises coroutine support only when its wrapped DB supports it; TTL value decoding and transaction visibility semantics are preserved.
* Added a `kSstFileWriter` value to `TableFileCreationReason`, which `SstFileWriter` now reports instead of the catch-all `kMisc`. This, along with new `db_name` and `is_remote_compaction` fields in `FilterBuildingContext`, improves the contextual information available to custom filter and compression strategies.
* Renamed `TransactionLogIterator` to `WalIterator` (and `include/rocksdb/transaction_log.h` to `include/rocksdb/wal_iterator.h`), because it iterates the write-ahead log and is unrelated to `TransactionDB`. The old names still work. `DB::GetUpdatesSince()` is unchanged. In Java, `WalIterator` is the new name and `TransactionLogIterator` remains as a subclass. Also documented existing behavior that was previously unstated: only writes that reached the WAL are visible (so `WriteOptions::disableWAL` and `IngestExternalFile()` leave holes that end iteration), what each iterator state means, and that `GetUpdatesSince()` silently starts later when the requested sequence number is unavailable.
## 10.9.1 (12/11/2025)
### Bug Fixes
* Fixed a bug where `BlobFileBuilder` passed an SST path to `OnBlobFileCompleted()` instead of the completed blob path during BlobDB garbage-collection compactions, causing incorrect `SstFileManager` accounting and compaction failures on filesystems where the SST was not yet pathname-visible.
### Performance Improvements
* When `DBOptions::avoid_unnecessary_blocking_io` is true, obsolete `OPTIONS-*` files found during DB open are deleted by background purge instead of synchronously on the opening thread.
## 11.8.0 (07/28/2026)
### Public API Changes
* Add callback-based asynchronous read APIs, `DB::GetAsync()` and `DB::MultiGetAsync()`. The idea is that when IO is required, RocksDB can suspend its internal coroutine read path, allowing the read executor thread to do other work. When the IO is complete, RocksDB invokes the user callback. This requires filesystem support for full performance benefits. A new filesystem API `FSRandomAccessFile::SubmitReadAsync()` is introduced for this. Unlike `ReadAsync`, the filesystem is responsible for eventually calling the callback. `FileSystem::GetReadExecutor()` returns the IO executor whose EventBases run coroutine read processing. In the Posix filesystem, an IO-uring based event loop is used to complete the IO.
* Added `FlushOptions::listener_wait` (default `false`). When set together with `FlushOptions::wait == true`, `DB::Flush()` will not return until the registered `EventListener::OnFlushCompleted` callbacks for the flushed memtables have finished running. By default (`false`), `Flush(wait=true)` may return as soon as the flush result is committed, which can be before (or while) the `OnFlushCompleted` callbacks execute on the background flush thread. Also added the corresponding C API `rocksdb_flushoptions_set_listener_wait()` / `rocksdb_flushoptions_get_listener_wait()`.
* Deprecated `PinnableWideColumns::serialized_size()` in favor of the new `PinnableWideColumns::payload_size()`, which returns the total size of the columns' names and values (for a plain value this equals the value size). Relatedly, wide-column read accounting changed subtly: read statistics for entities (`BYTES_READ`, `BYTES_PER_READ`, and the per-key byte counts for `GetEntity`/`MultiGetEntity`) and the `ReadOptions::value_size_soft_limit` threshold now measure entities by this payload size instead of the serialized entity size. This drops serialization framing bytes from those measurements (so reported/limited sizes for entity reads are slightly smaller than before) and makes plain-value and wide-column accounting consistent.
### Behavior Changes
* `ReadOptions::value_size_soft_limit` now also bounds the blob values resolved from pre-flush blob direct write references during `MultiGet`/`MultiGetEntity` (previously these were resolved after the limit check and read without bound). Enforcement is "always make progress": at least one key is read even if its value alone exceeds the limit, and only once the returned size exceeds the limit do subsequent keys get `Status::Aborted` -- so a caller retrying the aborted keys cannot loop forever on a single value that by itself exceeds the limit.
### Performance Improvements
* Reduced copying when reading wide-column entities that have blob-referenced columns, whether stored in separate blob files or embedded (same-file) as blob records in the same SST. On the point-lookup (`GetEntity`/`MultiGetEntity`) and blob-backed memtable/direct-write read paths, resolving these columns no longer re-serializes the whole entity into a fresh buffer: inline columns are referenced in place in the pinned entity and each resolved blob value is referenced in place from its fetched buffer. This is enabled by an internal change to `PinnableWideColumns` that lets its columns reference multiple backing buffers.
## 11.7.0 (07/16/2026)
### Public API Changes
* Added `RangeLockManagerHandle::SetIsKilledCallback()`, a `std::function<bool()>` predicate polled during range-lock waits. When it returns true, a blocked `GetRangeLock()` wait returns promptly with `Status::Aborted()` instead of waiting for the lock timeout. Range-lock users that install no callback keep the original wait-until-grant-or-timeout behavior.
* Added `MultiScanArgs::reverse` to support reverse MultiScan reads over bounded scan ranges.
### Behavior Changes
* When using `LockWAL()`, live-file capture APIs such as checkpoint and backup now flush WAL-disabled unpersisted data; they can block until `UnlockWAL()` or return `Aborted` when called from the same thread that holds `LockWAL()` to avoid deadlock. `UnlockWAL()` must now also be called from the same thread that called `LockWAL()`.
### Performance Improvements
* Fixed slow DB open with `best_efforts_recovery`, and slow catch-up of secondary and follower (read-only) instances, in which time and memory grew quadratically with the number of files in the DB (so the slowdown was worst for large DBs with long history).
## 11.6.0 (07/02/2026)
### New Features
* Added EXPERIMENTAL embedded blob SST support through `SstFileWriter::OpenWithEmbeddedBlobs()`, storing eligible large values as same-file blob records in block-based SST files and resolving them transparently for reads. This niche feature currently supports uncompressed embedded blobs only; compression options are placeholders and compression support is deferred to follow-up work.
### Public API Changes
* Expanded the C API (`include/rocksdb/c.h`) with a large set of new `rocksdb_*` functions, mostly option getters/setters plus table-properties, job/event-listener, and metadata accessors, a WAL filter, a ReadOptions table filter, and a backup exclude-files callback. Many are now produced by a new semi-automated generator (`tools/c_api_gen/`) from the C++ headers; `include/rocksdb/c.h` remains a single self-contained header and the signatures of pre-existing functions are unchanged.
### Bug Fixes
* Reverted PR14831 that made range_lock_manager aware of reverse-order CF
* Fixed a bug in `RandomAccessFileReader::ReadAsync` where an already-aligned direct-IO read request with a null `scratch` and a caller-provided `aligned_buf` would take the "already aligned" fast path and submit the null buffer to the underlying async read (e.g. a null iovec base to io_uring, failing with EFAULT). This could surface as spurious iterator failures during async prefetch (MultiScan with async IO) on direct-IO databases. The async path now allocates a backing buffer in this case, matching the synchronous `Read` path.
* Fixed a bug where closing a read-only DB instance could delete live SST files created by a concurrent read-write DB sharing the same directory.
## 11.5.0 (06/16/2026)
### New Features
* External table readers that open files through `ExternalTableOptions::fs` now update RocksDB SST/file-read statistics and file IO listener callbacks, making external file IO activity visible in existing read metrics.
* Added `DB::PrepareFileIngestion()`, a two-phase form of `IngestExternalFile`/`IngestExternalFiles`. `PrepareFileIngestion()` performs all of the work that does not require the DB mutex (validating the arguments, reading each external file's metadata, and linking/copying the files into the DB) and returns an opaque `FileIngestionHandle`. `DB::CommitFileIngestionHandle()` (or `DB::CommitFileIngestionHandles()` for several handles at once) then makes the prepared files visible; multiple handles are committed atomically in a single MANIFEST write, or none are. `FileIngestionHandle::Abort()` (or simply destroying the handle) cancels a prepared ingestion and rolls it back. This gives flexibility to the application to Prepare a file separately from when its committed, and may shorten an applications critical path on `IngestExternalFile`.
* Added two stats histograms reporting the per-call latency (in microseconds) of each successful `IngestExternalFile`/`IngestExternalFiles` call, split by phase: `rocksdb.ingest.external.file.prepare.micros` (argument validation and reading/validating/linking the external files, which does not block live writes) and `rocksdb.ingest.external.file.run.micros` (the ingestion performed under the DB mutex while live writes are blocked). Failed ingestions are not recorded.
* Added `DBOptions::use_direct_io_for_compaction_reads` (default false). When enabled, compaction-input SST reads use `O_DIRECT` while user reads remain buffered, avoiding page-cache eviction of hot user-read data by sequential compaction scans. Pair with `use_direct_io_for_flush_and_compaction = true` on write-heavy workloads for direct I/O on both compaction inputs and outputs. Rejected at Open when combined with `allow_mmap_reads = true`. No-op when `use_direct_reads = true` is already set (since all reads are already direct).
### Public API Changes
* `DB::GetPreparedFileInfoForExternalSstIngestion()` can now prepare metadata for a live DB-generated SST file so it can be passed to `IngestExternalFileArg::file_infos`. The input path must exactly match a live table file owned by the source DB, and the returned metadata handle must outlive the ingestion.
* `ExternalSstFileInfo` gained a `prepared_file_info` member produced by `SstFileWriter::Finish`, and `IngestExternalFileArg` gained a `file_infos` field: a vector of borrowed `const PreparedFileInfo*` pointers, parallel to `external_files`. The owning `ExternalSstFileInfo::prepared_file_info` handle must outlive the ingestion. When set, `IngestExternalFiles()` reuses the supplied per-file metadata instead of re-opening and scanning each file to recompute it, avoiding that extra I/O.
* Corrected the public C++ option spelling from `memtable_veirfy_per_key_checksum_on_seek` to `memtable_verify_per_key_checksum_on_seek`. RocksDB continues to accept the old misspelled OPTIONS-file key for compatibility, while newly serialized OPTIONS files use the corrected key.
* Added experimental read-scoped block buffer provider API, configured through `ReadOptions::read_scoped_block_buffer_provider`, for supported block-based table iterator scans and MultiScan reads to use caller-provided read-scoped storage for final data-block contents. When configured, supported provider-backed scan data-block reads bypass the data-block cache. The provider is ignored when mmap reads are enabled. RocksDB may still use ordinary temporary scratch for serialized block bytes, such as when a block may be compressed. Get and MultiGet do not currently provide API guarantees for this provider.
* Added `FileSystem::SyncFile()` and `Env::SyncFile()` public APIs for syncing or fsyncing a file by name without requiring callers to reopen it as writable.
### Behavior Changes
* The default `compression` for column families is now `kLZ4Compression` rather than `kSnappyCompression`. This affects only column families that do not explicitly set `compression`, and only newly-written SST files. The change is fully compatible: existing data remains readable with no migration needed, as RocksDB selects the decompressor per block. LZ4 offers slightly better compression ratios and decompression CPU efficiency vs. Snappy and similar compression CPU, tested across various server CPUs. When support is not compiled in, the fallback path for default compression is LZ4 -> Snappy -> NoCompression.
* Disable parallel compression (ignore `CompressionOptions::parallel_threads`) for fast built-in compressors: Snappy, LZ4 (accelerated, not LZ4HC), and accelerated levels of ZSTD (level < 0). These do not generally benefit from parallel compression. This behavior can be overridden with a custom Compressor from a custom CompressionManager.
* `PosixFileSystem::OptimizeForCompactionTableRead` now delegates to the base `FileSystem::OptimizeForCompactionTableRead` implementation before applying its Linux-only compaction-readahead clamp (added for #12038). The returned `FileOptions::use_direct_reads` therefore reflects `DBOptions::use_direct_reads`, consistent with the base class and with other `FileSystem` implementations. Previously the override ignored the base implementation and keyed both the returned options and the Linux readahead clamp off the incoming `FileOptions` rather than `DBOptions`. At the in-tree call site the incoming `FileOptions::use_direct_reads` already matches `DBOptions::use_direct_reads`, so this is effectively a no-op for existing configurations; it removes a latent inconsistency where a caller passing `FileOptions` whose `use_direct_reads` disagreed with `DBOptions` would have had the global flag silently ignored for compaction-input reads on Linux. (Note: the `#12038` readahead clamp still keys off the global `use_direct_reads`; it is not skipped for the compaction-only `use_direct_io_for_compaction_reads` path, since that flag enables O_DIRECT after this hook runs.)
* Brought more unity to `kLZ4Compression` and `kLZ4HCCompression` by giving each access to the other's compression levels. Negative (fast) values previously only available to LZ4 and positive (slow) values previously only available to LZ4HC are now available to both, so configuring a non-default `compression_opts.level` now selects the LZ4 compressor variant. This is a behavior change for previously tolerated but dubious configurations such as positive compression level with `kLZ4Compression`. `kLZ4Compression` and `kLZ4HCCompression` keep their effective default levels, equivalent to -1 and 9 respectively.
* Removed a discontinuity in `kZSTD` compression levels at `compression_opts.level == 0` by mapping that setting to `level = -1` rather than to `level = 3` as the ZSTD library does internally. This improves the compression auto-tuning landscape.
### Bug Fixes
* Fixed a bug where the range lock manager would crash with an assertion failure when using a reverse comparator column family.
### Performance Improvements
* Reduced commit latency when ingesting many external files by allowing `IngestExternalFileOptions::file_opening_threads` to open table readers for committed ingested files using multiple threads.
* Reduced commit latency for large external file ingestions into the last level by adding `IngestExternalFileOptions::prefetch_lmax_index_and_filter_blocks`, which can skip commit-time index and filter block prefetching for cache-backed table metadata.
## 11.4.0 (06/02/2026)
### Public API Changes
* Added `rocksdb_options_set_memtable_batch_lookup_optimization()` and `rocksdb_options_get_memtable_batch_lookup_optimization()` to the C API, exposing the existing `AdvancedColumnFamilyOptions::memtable_batch_lookup_optimization` field. This allows C API users (and downstream language bindings) to enable the skip-list memtable's batch-lookup optimization for `MultiGet`, which caches the search path between consecutive keys and reduces per-key cost from O(log N) to O(log d) where d is the distance between consecutive keys.
* Added `rocksdb_readoptions_set_optimize_multiget_for_io()` and `rocksdb_readoptions_get_optimize_multiget_for_io()` to the C API, exposing the existing `ReadOptions::optimize_multiget_for_io` field. This allows C API users (and downstream language bindings) to opt out of the multi-level parallel MultiGet path, which only takes effect when the library is built with `USE_COROUTINES`.
* Added `rocksdb_block_based_table_index_block_search_type_auto` enum constant and the `rocksdb_block_based_options_set_uniform_cv_threshold()` setter to the C API. The constant exposes `BlockSearchType::kAuto`, and the setter exposes `BlockBasedTableOptions::uniform_cv_threshold`. Both are required for `kAuto` index-block search to take effect from the C API: without setting `uniform_cv_threshold >= 0`, the per-block `is_uniform` footer bit is never written, and `kAuto` falls back to binary search at read time.
* Added `EventListener::OnDBShutdownBegin`, a callback that fires once when a DB begins shutdown, including when RocksDB cleans up a failed `DB::Open()` attempt.
* Added a new PerfContext counter `blob_cache_read_byte` for blob cache bytes read.
### Behavior Changes
* Remote compaction now falls back to local compaction when the primary cannot deserialize a successful `CompactionServiceResult` before installing any remote output files.
* StringToMap (rocksdb/convenience.h) now preserves the outer braces of nested values so each map entry is in self-contained form and can be embedded directly into another `key=value;` string (e.g. SetOptions) without losing inner ';' delimiters. A new symmetric MapToString utility is provided.
### Bug Fixes
* Fixed a bug where `AbortAllCompactions()` could leave automatic compaction work unscheduled when aborting before the background worker picked it, causing compaction and write stalls until DB restart.
* Fix a bug where db had a false positive compaction corruption error due to remote compaction service result with `has_accurate_num_input_records=false` not being serialized.
* Fixed WritePrepared TransactionDB cleanup after retryable commit or rollback write failures so prepared transactions remain rollbackable instead of leaving unresolved prepared state.
* Fix a rare corruption bug for tiered compaction that incorrectly moved last level range tombstones into proximal level. This corruption error is surfaced when force_consistency_checks is enabled.
### Performance Improvements
* Reduce the likelihood of user-facing metadata operations blocking on MANIFEST rotation when file creation is slow, such as on remote storage. MANIFEST write batches containing foreground edits from `CreateColumnFamily()`, `DropColumnFamily()`, `CreateColumnFamilyWithImport()`, `IngestExternalFile()`, and `DeleteFilesInRanges()` now get a relaxed file size threshold for triggering MANIFEST rotation; background-only MANIFEST write batches, such as compaction and flush, continue to use the normal threshold. This change should make auto-tuning manifest file size more attractive (see `max_manifest_file_size` and `max_manifest_space_amp_pct` options).
## 11.3.0 (05/15/2026)
### New Features
* Add experimental DB option `async_wal_precreate` to precreate the next WAL file in a background thread and reduce foreground WAL rotation latency. The option is sanitized to false when WAL recycling is enabled.
* Added a new `EventListener::OnCompactionPreCommit` callback that fires after a compaction job finishes but before its input files are released (i.e. while `FileMetaData::being_compacted` is still true). Listeners that maintain bookkeeping of which files are currently being compacted can clean up such state in this new callback to avoid races with concurrent compaction picking, where another thread might pick up the same files for a new compaction immediately after `being_compacted` is flipped back to false but before `OnCompactionCompleted` fires. The default implementation is a no-op so this is not a breaking change.
* Add mutable DBOption `optimize_manifest_for_recovery` (default false). When enabled, RocksDB can reduce recovery work after a clean shutdown, which may lower DB::Open latency on warm reopens.
* Added public utility APIs `ParseCompressionNameForDisplay()` to convert `TableProperties::compression_name` into a human-readable compression name for both legacy and format_version 7+ SST metadata, including custom `CompressionManager`-provided display names for custom compression types.
* Add `reuse_manifest_on_open` DBOption (default false). When enabled, DB::Open reuses the existing MANIFEST file for append instead of creating a fresh one, avoiding the cost of serializing the entire database state into a new MANIFEST on the first post-open write. To prevent this feature from interfering with manifest file size auto-tuning, an extra forward-compatible field is now always added to the MANIFEST (to track the last "compacted" size).
### Behavior Changes
* Read-only open with `error_if_wal_file_exists=true` now tolerates empty WAL files so empty precreated WALs do not prevent inspection.
* WriteCommitted TransactionDB now matches WritePrepared and WriteUnprepared compaction filtering in both single- and two-write-queue modes: a compaction filter's FilterMergeOperand will not be invoked on merge operands at or below the latest published sequence number.
### Bug Fixes
* Fixed blob-backed wide-column merge reads to preserve correct status
propagation and resolution across memtable, read-only, and secondary DB
paths.
* Fixed a bug where `DB::GetCreationTimeOfOldestFile()` could return inaccurate results instead of the real creation time when called shortly after opening a legacy DB (one whose manifest lacks `file_creation_time`) with `open_files_async = true`. The API now waits for background SST file loading to complete only when needed; modern DBs are unaffected.
* Fixed merge reads against wide-column/blob-backed base values to preserve precise failure statuses, including `GetMergeOperands()` and direct-write memtable reads.
* Fix bug in range tombstone synthesis that covers live keys added during an IngestExternalFile
* Reject the empty string as a column family name in `DB::CreateColumnFamily` / `DB::CreateColumnFamilies`. Previously such calls returned OK and a usable handle, but the column family was not persisted in the manifest, so any data written to it was silently lost on DB reopen.
* Fixed a bug where a WriteCommitted TransactionDB using commit-bypass WBWI ingestion could drop an entry that is still visible at the published sequence boundary.
## 11.2.0 (04/18/2026)
### New Features
* Added experimental `DBOptions::fast_sst_open` option. When enabled, RocksDB retrieves opaque file system metadata for SST files after flush, compaction, and external file ingestion, persists it in the MANIFEST, and passes it back to the file system on subsequent file opens to accelerate DB open time.
* Added new option `min_tombstones_for_range_conversion` in `AdvancedColumnFamilyOptions`. When set to a non-zero value N, forward or reverse iteration will convert N or more contiguous point tombstones into a range tombstone in the mutable memtable. Future read operations will then be able to benefit from range tombstone optimizations. There are some limitations when it comes to table_filters, prefix_filters, and UDTs. See header comments for more details.
* Added read-triggered compaction: a new column family option `read_triggered_compaction_threshold` (default 0, disabled) that marks SST files for compaction when their read frequency (`num_collapsible_entry_reads_sampled / file_size`) exceeds the threshold. This helps reduce read amplification for frequently-read ("hot") keys. A new DB option `max_compaction_trigger_wakeup_seconds` (default 43200s / 12 hours) controls the maximum interval for periodic compaction score re-evaluation, which is necessary for this feature to work on quiet (no-write) databases.
### Public API Changes
* Added new `WideColumnBlobResolver` interface and `CompactionFilter::FilterV4()` method, including `ResolveColumn()` / `ResolveColumns()` helpers for lazy loading blob column values in wide-column entities during compaction. This allows compaction filters to resolve blob values on-demand, avoiding unnecessary I/O for blob columns they don't need to access.
* Changed experimental feature `ExternalTableReader::Get` and `ExternalTableReader::MultiGet` to use `PinnableSlice` instead of `std::string` for output values, enabling zero-copy pinning. This will break existing implementations.
* Added `SstFileReader::Get` and `SstFileReader::MultiGet` overloads that accept `PinnableSlice`/`std::vector<PinnableSlice>*`, enabling zero-copy reads when the underlying `TableReader` supports pinning.
### Behavior Changes
* Prefix filter changes - when seeking to a key that is out of domain, and total_order_seek is false, total_order_seek is treated as if it were true. When prefix_same_as_start = true, now iterating past a key that is out of domain invalidates the iterator. The existing behavior does not check for InDomain in the DBIter, so Transform() can produce undefined behavior (e.g. key of size 3 on FixedPrefixTransform(4)).
* Wide-column entities with blob-backed columns now use a new V2 on-disk encoding; older RocksDB versions that do not support wide-column blob separation will reject DBs or SSTs containing those entities.
### Bug Fixes
* Fix blob garbage accounting for blob direct-write flushes so flush-time filtering and overwrite elision correctly register obsolete blob bytes in blob metadata.
* Fix a memory accounting leak in IODispatcher where ReadIndex() moved block values out of ReadSet without releasing the associated prefetch memory, causing subsequent prefetches to be blocked when max_prefetch_memory_bytes was set.
* Fix MultiScan to fall back to synchronous coalesced reads when async I/O is unsupported at runtime.
## 11.1.0 (03/23/2026)
### New Features
* Add a new option `open_files_async`. The existing behavior is on DB open, we open all sst files and do basic validations. For very large DBs on remote filesystems with many ssts, this may take very long. This option performs these validations instead in the background. Open errors found by this async background task are surfaced as a new background error kAsyncFileOpen.
* Added `BlockBasedTableOptions::kAuto` index block search type that automatically selects between binary and interpolation search on a per-index-block basis. During SST construction, each index block's key distribution uniformity is analyzed using the coefficient of variation of key gaps, and index blocks with uniform keys use interpolation search while others fall back to binary search. The uniformity threshold is configurable via `BlockBasedTableOptions::uniform_cv_threshold` (default: 0.2).
* Introduced enforce_write_buffer_manager_during_recovery option to allow WriteBufferManager to be enforced during WAL recovery. (Default: true)
* Add `memtable_batch_lookup_optimization` option to use batch lookup optimization for memtable MultiGet. For skip list memtables, after each key lookup, the search path is cached and reused for the next key, reducing per-key cost from O(log N) to O(log d) where d is the distance between consecutive keys. Benchmarks show ~7% improvement in memtable-resident MultiGet throughput.
* Added `BlockBasedTableOptions::PrepopulateBlockCache::kFlushAndCompaction` to prepopulate the block cache during both flush and compaction. Compaction-warmed blocks are inserted at `BOTTOM` priority (vs `LOW` for flush) so they are evicted first under cache pressure. Recommended only for use cases where most or all of the database is expected to reside in cache (e.g., tiered or remote storage where the working set fits in cache).
* Added new mutable DB option `verify_manifest_content_on_close` (default: false). When enabled, on DB close the MANIFEST file is read back and all records are validated (CRC checksums and logical content). If corruption is detected, a fresh MANIFEST is written from in-memory state.
### Behavior Changes
* num_reads_sampled now factors in re-seeks and next/prev() on file iterators for files in L1+. next/prev() is discounted by 64x compared to seek due to being a much cheaper call.
* Remote compaction workers now skip WAL recovery when opening the secondary DB instance, since only the LSM state from MANIFEST is needed for compaction. This reduces I/O and speeds up remote compaction startup.
### Bug Fixes
* Fix a bug in round-robin compaction that missed selecting input files that are needed to guarantee data correctness and cause crashing in debug builds or silent data corruption in release builds for Get().
## 11.0.0 (02/23/2026)
### New Features
* Added support for storing wide-column entity column values in blob files. When `min_blob_size` is configured, large column values in wide-column entities will be stored in blob files, reducing SST file size and improving read performance.
* Added `CompactionOptionsFIFO::max_data_files_size` to support FIFO compaction trimming based on combined SST and blob file sizes. Added `CompactionOptionsFIFO::use_kv_ratio_compaction` to enable a capacity-derived intra-L0 compaction strategy optimized for BlobDB workloads, producing uniform-sized compacted files for predictable FIFO trimming.
* Include interpolation search as an alternative to binary search, which typically performs better when keys are uniformly distributed. This is exposed as a new table option `index_block_search_type`. The default is `binary_search`.
### Public API Changes
* Added new virtual methods `AbortAllCompactions()` and `ResumeAllCompactions()` to the `DB` class. Added new `Status::SubCode::kCompactionAborted` to indicate a compaction was aborted. Added `Status::IsCompactionAborted()` helper method to check if a status represents an aborted compaction.
* Drop support for reading (and writing) SST files using `BlockBasedTableOptions.format_version` < 2, which hasn't been the default format for about 10 years. An upgrade path is still possible with full compaction using a RocksDB version >= 4.6.0 and < 11.0.0 and then using the newer version.
* Remove deprecated raw `DB*` variants of `DB::Open` and related functions. Some other minor public APIs were updated as a result
* Remove deprecated `DB::MaxMemCompactionLevel()`
* Remove useless option `CompressedSecondaryCacheOptions::compress_format_version`
* Remove deprecated DB option `skip_checking_sst_file_sizes_on_db_open`. The option was deprecated in 10.5.0 and has been a no-op since then. File size validation is now always performed in parallel during DB open.
* Remove deprecated `SliceTransform::InRange()` virtual method and the `in_range` callback parameter from `rocksdb_slicetransform_create()` in the C API. `InRange()` was never called by RocksDB and existed only for backward compatibility.
* Remove deprecated, unused APIs and options: `ReadOptions::managed` and `ColumnFamilyOptions::snap_refresh_nanos`. Corresponding C and Java APIs are also removed.
* Remove deprecated `SstFileWriter::Add()` method (use `Put()` instead) and the deprecated `skip_filters` parameter from `SstFileWriter` constructors (use `BlockBasedTableOptions::filter_policy` set to `nullptr` to skip filter generation instead).
### Behavior Changes
* Change the default value of `CompactionOptionsUniversal::reduce_file_locking` from `false` to `true` to improve write stall and reduce read regression
### Bug Fixes
* Fix longstanding failures that can arise from reading and/or compacting old DB dirs with range deletions (likely from version < 5.19.0) in many newer versions.
* Fix a bug where WritePrepared/WriteUnprepared TransactionDB with two_write_queues=true could experience "sequence number going backwards" corruption during recovery from a background error, due to allocated-but-not-published sequence numbers not being synced before creating new WAL files.
### Performance Improvements
* Add a new table option `separate_key_value_in_data_block`. When set to true keys and values will be stored separately in the data block, which can result in higher cpu cache hit rate and better compression. Works best with data blocks with sufficient restart intervals and large values. Previous versions of RocksDB will reject files written using this option.
## 10.11.0 (01/23/2026)
### Public API Changes
* New SetOptions API that allows setting options for multiple CFs, avoiding the need to reserialize OPTIONS file for each CF
* Remove remaining pieces of Lua integration
### Behavior Changes
* The new default for `BlockBasedTableOptions::format_version` is 7, which has been supported since RocksDB 10.4.0 and is required in order to use CompressionManagers supporting custom compression types.
### Bug Fixes
* Fixed a small performance bug with `format_version=7` when decompressing formats other than Snappy and ZSTD.
* Fixed an infinite compaction loop bug with User-Defined Timestamps (UDT) where bottommost files were repeatedly marked for compaction even though their timestamp could not be collapsed.
* Bugfix for persisted UDT record sequence number zeroing logic.
## 10.10.0 (12/16/2025)
### Bug Fixes
* Fixed a bug in best-efforts recovery that causes use-after-free crashes when accessing SST files that were cached during the recovery.
* Fix resumable compaction incorrectly allowing resumption from a truncated range deletion that is not well handled currently.
* Fixed a bug in `PosixRandomFileAccess` IO uring submission queue ownership & management. Fix eliminates the false positive 'Bad cqe data' IO errors in `PosixRandomFileAccess::MultiRead` when interleaved with `PosixRandomFileAccess::ReadAsync` on the same thread.
## 10.9.0 (11/21/2025)
### New Features
+107 -567
View File
@@ -86,20 +86,11 @@ else
LIB_MODE?=shared
endif
# Set by the gen_check_scripts wrappers to mark a recursive make reusing the
# parent's make_config.mk: silence the parse-time banners and skip
# build_detect_platform (below).
$(if $(ROCKSDB_RECURSIVE_MAKE_SAME_CONFIG),,$(info $$DEBUG_LEVEL is $(DEBUG_LEVEL), $$LIB_MODE is $(LIB_MODE)))
$(info $$DEBUG_LEVEL is $(DEBUG_LEVEL), $$LIB_MODE is $(LIB_MODE))
# Detect what platform we're building on.
# Export some common variables that might have been passed as Make variables
# instead of environment variables.
#
# Skipped by the gen_check_scripts wrappers (which run concurrently under
# gnu_parallel): each would otherwise rewrite the shared make_config.mk
# non-atomically and a concurrent reader could catch it mid-write ("missing
# separator"). Requires an existing make_config.mk, so a normal build still detects.
ifeq ($(and $(ROCKSDB_RECURSIVE_MAKE_SAME_CONFIG),$(wildcard make_config.mk)),)
dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; \
export CXXFLAGS="$(EXTRA_CXXFLAGS)"; \
export LDFLAGS="$(EXTRA_LDFLAGS)"; \
@@ -113,9 +104,8 @@ dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; \
export ROCKSDB_CXX_STANDARD="$(ROCKSDB_CXX_STANDARD)"; \
export USE_FOLLY="$(USE_FOLLY)"; \
export USE_FOLLY_LITE="$(USE_FOLLY_LITE)"; \
"$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk" $(if $(ROCKSDB_RECURSIVE_MAKE_SAME_CONFIG),2>/dev/null)))
endif
# this file (generated above, or reused when skipped) sets build flags and sources
"$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk"))
# this file is generated by the previous line to set build flags and sources
include make_config.mk
# Figure out optimize level.
@@ -191,7 +181,7 @@ ifeq ($(filter -DROCKSDB_ASSERT_STATUS_CHECKED,$(OPT)),)
endif
endif
$(if $(ROCKSDB_RECURSIVE_MAKE_SAME_CONFIG),,$(warning Warning: Compiling in debug mode. Don't use the resulting binary in production))
$(warning Warning: Compiling in debug mode. Don't use the resulting binary in production)
endif
# `USE_LTO=1` enables link-time optimizations. Among other things, this enables
@@ -298,7 +288,7 @@ endif
endif
export JAVAC_ARGS
CLEAN_FILES += rocksdb.pc
CLEAN_FILES += make_config.mk rocksdb.pc
ifeq ($(V), 1)
$(info $(shell uname -a))
@@ -306,28 +296,6 @@ $(info $(shell $(CC) --version))
$(info $(shell $(CXX) --version))
endif
# ccache support
# Set USE_CCACHE=1 to enable ccache, or let it auto-detect
ifndef USE_CCACHE
CCACHE := $(shell which ccache 2>/dev/null)
ifneq ($(CCACHE),)
USE_CCACHE := 1
else
USE_CCACHE := 0
endif
endif
ifeq ($(USE_CCACHE), 1)
CCACHE := $(shell which ccache 2>/dev/null)
ifneq ($(CCACHE),)
$(info Using ccache: $(CCACHE))
CC := $(CCACHE) $(CC)
CXX := $(CCACHE) $(CXX)
else
$(warning ccache requested but not found in PATH)
endif
endif
missing_make_config_paths := $(shell \
grep "\./\S*\|/\S*" -o $(CURDIR)/make_config.mk | \
while read path; \
@@ -337,9 +305,6 @@ missing_make_config_paths := $(shell \
$(foreach path, $(missing_make_config_paths), \
$(warning Warning: $(path) does not exist))
# This (the first rule) must depend on "all".
default: all
ifeq ($(PLATFORM), OS_AIX)
# no debug info
else ifneq ($(PLATFORM), IOS)
@@ -397,16 +362,14 @@ endif
# TSAN doesn't work well with jemalloc. If we're compiling with TSAN, we should use regular malloc.
ifdef COMPILE_WITH_TSAN
DISABLE_JEMALLOC=1
# Use a suppressions file instead of the process-wide TSAN default
# suppressions hook, which belongs to the final application.
TSAN_OPTIONS?=suppressions=$(CURDIR)/tools/tsan_suppressions.txt
export TSAN_OPTIONS
EXEC_LDFLAGS += -fsanitize=thread
PLATFORM_CCFLAGS += -fsanitize=thread -fPIC -DFOLLY_SANITIZE_THREAD
PLATFORM_CXXFLAGS += -fsanitize=thread -fPIC -DFOLLY_SANITIZE_THREAD
# Turn off -pg when enabling TSAN testing, because that induces
# a link failure. TODO: find the root cause
PROFILING_FLAGS =
# LUA is not supported under TSAN
LUA_PATH =
# Limit keys for crash test under TSAN to avoid error:
# "ThreadSanitizer: DenseSlabAllocator overflow. Dying."
CRASH_TEST_EXT_ARGS += --max_key=1000000
@@ -467,7 +430,7 @@ ifndef USE_FOLLY
endif
ifndef GTEST_THROW_ON_FAILURE
export GTEST_THROW_ON_FAILURE=0
export GTEST_THROW_ON_FAILURE=1
endif
ifndef GTEST_HAS_EXCEPTIONS
export GTEST_HAS_EXCEPTIONS=1
@@ -498,6 +461,9 @@ ifdef ROCKSDB_MODIFY_NPHASH
PLATFORM_CXXFLAGS += -DROCKSDB_MODIFY_NPHASH=1
endif
# This (the first rule) must depend on "all".
default: all
WARNING_FLAGS = -W -Wextra -Wall -Wsign-compare -Wshadow \
-Wunused-parameter
@@ -520,6 +486,32 @@ ifndef DISABLE_WARNING_AS_ERROR
endif
ifdef LUA_PATH
ifndef LUA_INCLUDE
LUA_INCLUDE=$(LUA_PATH)/include
endif
LUA_INCLUDE_FILE=$(LUA_INCLUDE)/lualib.h
ifeq ("$(wildcard $(LUA_INCLUDE_FILE))", "")
# LUA_INCLUDE_FILE does not exist
$(error Cannot find lualib.h under $(LUA_INCLUDE). Try to specify both LUA_PATH and LUA_INCLUDE manually)
endif
LUA_FLAGS = -I$(LUA_INCLUDE) -DLUA -DLUA_COMPAT_ALL
CFLAGS += $(LUA_FLAGS)
CXXFLAGS += $(LUA_FLAGS)
ifndef LUA_LIB
LUA_LIB = $(LUA_PATH)/lib/liblua.a
endif
ifeq ("$(wildcard $(LUA_LIB))", "") # LUA_LIB does not exist
$(error $(LUA_LIB) does not exist. Try to specify both LUA_PATH and LUA_LIB manually)
endif
EXEC_LDFLAGS += $(LUA_LIB)
endif
ifeq ($(NO_THREEWAY_CRC32C), 1)
CXXFLAGS += -DNO_THREEWAY_CRC32C
endif
@@ -589,12 +581,9 @@ TESTS += $(PLUGIN_TESTS)
ifneq ($(filter check-headers, $(MAKECMDGOALS)),)
# TODO: add/support JNI headers
DEV_HEADER_DIRS := $(sort include/ $(dir $(ALL_SOURCES)))
FOLLY_DEPENDENT_HEADERS := \
include/rocksdb/coro_db.h \
include/rocksdb/utilities/coro_stackable_db.h
# Some headers like in port/ are platform-specific
DEV_HEADERS_TO_CHECK := $(filter-out $(FOLLY_DEPENDENT_HEADERS), $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | grep -E -v 'port/|plugin/|range_tree/|secondary_index/'))
PUBLIC_HEADERS_TO_CHECK := $(filter-out $(FOLLY_DEPENDENT_HEADERS), $(shell $(FIND) include/ -type f -name '*.h'))
DEV_HEADERS_TO_CHECK := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | grep -E -v 'port/|plugin/|lua/|range_tree/|secondary_index/')
PUBLIC_HEADERS_TO_CHECK := $(shell $(FIND) include/ -type f -name '*.h' | grep -E -v 'lua/')
else
DEV_HEADERS_TO_CHECK :=
PUBLIC_HEADERS_TO_CHECK :=
@@ -638,24 +627,25 @@ endif
ROCKSDBTESTS_SUBSET ?= $(TESTS)
# c_test - doesn't use gtest, can't be sharded
# Other tests previously listed here (backup_engine_test, db_bloom_filter_test,
# perf_context_test, etc.) were NON_PARALLEL due to /dev/shm memory concerns
# when the old per-test-case sharding spawned thousands of processes. With the
# new gtest-based sharding (GTEST_SHARD_SIZE=10, max NCORES*8 shards), at most
# ~4 shards run concurrently on CI (4 cores), so peak memory is manageable
# (4 * 1GB = 4GB << 16GB shm).
# c_test - doesn't use gtest
# env_test - suspicious use of test::TmpDir
# deletefile_test - serial because it generates giant temporary files in
# its various tests. Parallel can fill up your /dev/shm
# db_bloom_filter_test - serial because excessive space usage by instances
# of DBFilterConstructionReserveMemoryTestWithParam can fill up /dev/shm
NON_PARALLEL_TEST = \
c_test \
env_test \
deletefile_test \
db_bloom_filter_test \
$(PLUGIN_TESTS) \
PARALLEL_TEST = $(filter-out $(NON_PARALLEL_TEST), $(ROCKSDBTESTS_SUBSET))
PARALLEL_TEST = $(filter-out $(NON_PARALLEL_TEST), $(TESTS))
# Not necessarily well thought out or up-to-date, but matches old list
TESTS_PLATFORM_DEPENDENT := \
db_basic_test \
db_blob_basic_test \
db_blob_direct_write_test \
db_encryption_test \
external_sst_file_basic_test \
auto_roll_logger_test \
@@ -663,7 +653,6 @@ TESTS_PLATFORM_DEPENDENT := \
dynamic_bloom_test \
c_test \
checkpoint_test \
sorted_run_builder_test \
crc32c_test \
coding_test \
inlineskiplist_test \
@@ -777,6 +766,7 @@ util/build_version.cc: $(filter-out $(OBJ_DIR)/util/build_version.o, $(LIB_OBJEC
$(AM_V_at)$(gen_build_version) > $@
endif
CLEAN_FILES += util/build_version.cc
default: all
#-----------------------------------------------
@@ -821,21 +811,9 @@ endif # PLATFORM_SHARED_EXT
.PHONY: check clean coverage ldb_tests package dbg gen-pc build_size \
release tags tags0 valgrind_check format static_lib shared_lib all \
rocksdbjavastatic rocksdbjava install install-static install-shared \
uninstall analyze tools tools_lib check-headers checkout_folly clang-tidy \
check-c-api-c_test
uninstall analyze tools tools_lib check-headers checkout_folly
# Auto-configure git hooks on first build so developers do not need to run
# "make install-hooks" manually. This is a no-op if already set.
setup-hooks:
@if [ -d .git ] && [ -d githooks ]; then \
cur=$$(git config core.hooksPath 2>/dev/null); \
if [ "$$cur" != "githooks" ]; then \
git config core.hooksPath githooks; \
echo "git hooks: configured core.hooksPath = githooks"; \
fi; \
fi
all: setup-hooks $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS)
all: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS)
all_but_some_tests: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(ROCKSDBTESTS_SUBSET)
@@ -899,62 +877,21 @@ coverage: clean
parallel_tests = $(patsubst %,parallel_%,$(PARALLEL_TEST))
.PHONY: gen_parallel_tests $(parallel_tests)
# Shard size controls how many test cases run per process. The actual number
# of shards per binary is: min(ceil(test_count / shard_size), NCORES * 8)
# This adapts to machine size: many small shards on beefy machines, fewer
# larger shards on CI (typically 2-4 cores).
GTEST_SHARD_SIZE ?= 10
NCORES ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
# Per-binary overrides for GTEST_SHARD_SIZE, used to chop up binaries whose
# individual test cases are slow enough that the default of 10 leaves one
# shard on the critical path of "make check". Format: whitespace-separated
# tokens "BINARY:SIZE". Sizes were tuned from `make suggest-slow-tests`
# output to keep max shard time under ~20s on a beefy box. Reducing too far
# adds per-shard fixed overhead, so don't use 1 unless individual tests are
# >5s.
SHARD_SIZE_OVERRIDES ?= \
point_lock_manager_stress_test:1 \
external_sst_file_test:1 \
external_sst_file_basic_test:2 \
db_test:3 \
compaction_service_test:1
$(parallel_tests):
$(AM_V_at)TEST_BINARY=$(patsubst parallel_%,%,$@); \
TEST_COUNT=` \
(./$$TEST_BINARY --gtest_list_tests 2>/dev/null || echo " list_failure") \
| grep -c '^ '`; \
if [ "$$TEST_COUNT" -le 0 ]; then TEST_COUNT=1; fi; \
SHARD_SIZE=$(GTEST_SHARD_SIZE); \
for o in $(SHARD_SIZE_OVERRIDES); do \
case "$$o" in \
"$$TEST_BINARY":*) SHARD_SIZE=$${o#*:} ;; \
esac; \
done; \
MAX_SHARDS=$$(( $(NCORES) * 8 )); \
NUM_SHARDS=$$(( (TEST_COUNT + SHARD_SIZE - 1) / SHARD_SIZE )); \
if [ "$$NUM_SHARDS" -gt "$$MAX_SHARDS" ]; then NUM_SHARDS=$$MAX_SHARDS; fi; \
if [ "$$NUM_SHARDS" -le 0 ]; then NUM_SHARDS=1; fi; \
echo " Generating $$NUM_SHARDS shards for $$TEST_BINARY ($$TEST_COUNT tests, shard_size=$$SHARD_SIZE)"; \
SHARD_IDX=0; \
while [ "$$SHARD_IDX" -lt "$$NUM_SHARDS" ]; do \
if [ -n "$(CI_TOTAL_SHARDS)" ] && [ $$(( $$SHARD_IDX % $(CI_TOTAL_SHARDS) )) -ne $(CI_SHARD_INDEX) ]; then \
SHARD_IDX=$$((SHARD_IDX + 1)); \
continue; \
fi; \
TEST_SCRIPT=t/run-$$TEST_BINARY-shard-$$SHARD_IDX; \
TEST_NAMES=` \
(./$$TEST_BINARY --gtest_list_tests || echo " $${TEST_BINARY}__list_tests_failure") \
| awk '/^[^ ]/ { prefix = $$1 } /^[ ]/ { print prefix $$1 }'`; \
echo " Generating parallel test scripts for $$TEST_BINARY"; \
for TEST_NAME in $$TEST_NAMES; do \
TEST_SCRIPT=t/run-$$TEST_BINARY-$${TEST_NAME//\//-}; \
printf '%s\n' \
'#!/bin/sh' \
"d=\$(TEST_TMPDIR)$$TEST_SCRIPT" \
'mkdir -p $$d' \
"TEST_TMPDIR=\$$d GTEST_TOTAL_SHARDS=$$NUM_SHARDS GTEST_SHARD_INDEX=$$SHARD_IDX $(DRIVER) ./$$TEST_BINARY" \
'test_retcode=$$?' \
'[ $$test_retcode -eq 0 ] && rm -rf $$d' \
'exit $$test_retcode' \
"TEST_TMPDIR=\$$d $(DRIVER) ./$$TEST_BINARY --gtest_filter=$$TEST_NAME" \
> $$TEST_SCRIPT; \
chmod a=rx $$TEST_SCRIPT; \
SHARD_IDX=$$((SHARD_IDX + 1)); \
done
gen_parallel_tests:
@@ -962,116 +899,29 @@ gen_parallel_tests:
$(AM_V_at)$(FIND) t -type f -name 'run-*' -exec rm -f {} \;
$(MAKE) $(parallel_tests)
# Auxiliary (non-unit-test) checks that are part of `make check`. Kept as a
# single list so the same set can run as parallel jobs alongside the C++ unit
# tests (see gen_check_scripts + check_0) and serially in the J=1 fallback.
CHECK_EXTRA_TARGETS =
ifneq ($(PLATFORM), OS_AIX)
CHECK_EXTRA_TARGETS += check-all-python
ifndef ASSERT_STATUS_CHECKED # not yet working with these tests
CHECK_EXTRA_TARGETS += ldb_tests db_crashtest_tests rocksdb_dump_test
endif
endif
ifndef SKIP_FORMAT_BUCK_CHECKS
CHECK_EXTRA_TARGETS += check-format check-buck-targets check-sources check-workflow-yaml check-c-api-gen
endif
# Generate a t/run-<target> wrapper per enabled auxiliary check; check_0's
# `$(FIND) t -name 'run-*'` then runs them as gnu_parallel jobs alongside the
# unit tests, each framed with a gtest-style pass/fail line. Under CI sharding,
# round-robin across shards so each check runs on exactly one shard. Kept
# separate from gen_parallel_tests (which cleans t/run-* first) so the valgrind_*
# targets, which also glob t/run-*, don't pick these up.
.PHONY: gen_check_scripts
gen_check_scripts:
$(AM_V_at)mkdir -p t; \
idx=0; \
for tgt in $(CHECK_EXTRA_TARGETS); do \
if [ -z "$(CI_TOTAL_SHARDS)" ] || [ $$(( idx % $(CI_TOTAL_SHARDS) )) -eq $(CI_SHARD_INDEX) ]; then \
s=t/run-$$tgt; \
printf '%s\n' \
'#!/bin/sh' \
'# Generated by `make gen_check_scripts`.' \
"t=$$tgt" \
'# Drop the parent jobserver from MAKEFLAGS (its fds are lost through' \
'# gnu_parallel, causing a spurious warning); keep overrides after "--".' \
'MAKEFLAGS=$$(printf "%s" "$$MAKEFLAGS" | sed -e "s/ --jobserver-auth=[^ ]*//g" -e "s/ --jobserver-fds=[^ ]*//g" -e "s/ -j[0-9]*//g")' \
'export MAKEFLAGS' \
'echo; echo "[----------]"; echo "[ RUN ] >>> make $$t <<<"' \
'$(MAKE) --no-print-directory ROCKSDB_RECURSIVE_MAKE_SAME_CONFIG=1 "$$t"' \
'rc=$$?' \
'if [ "$$rc" = 0 ]; then' \
' echo "[ OK ] >>> make $$t <<<"' \
'else' \
' echo "[ FAILED ] >>> make $$t <<<"' \
'fi' \
'echo "[----------]"' \
'exit $$rc' \
> $$s; \
chmod a=rx $$s; \
fi; \
idx=$$((idx + 1)); \
done
# Reorder input lines (one per test or per shard) so the longest-running
# tests/shards start first under "make check" parallel scheduling. The trick
# is to prefix matched names with a fake duration (100), sort numerically
# descending, then strip the prefix. Slow-matched tests therefore come ahead
# of all unmatched tests; ordering within each group is unspecified.
# Reorder input lines (which are one per test) so that the
# longest-running tests appear first in the output.
# Do this by prefixing each selected name with its duration,
# sort the resulting names, and remove the leading numbers.
# FIXME: the "100" we prepend is a fake time, for now.
# FIXME: squirrel away timings from each run and use them
# (when present) on subsequent runs to order these tests.
#
# Why this matters: gnu_parallel hands out jobs in input order. If a slow
# test starts only after most others have finished, the run is bottlenecked
# on its tail. Front-loading slow tests overlaps them with the bulk of
# faster ones for much better wall-clock time.
# Without this reordering, these two tests would happen to start only
# after almost all other tests had completed, thus adding 100 seconds
# to the duration of parallel "make check". That's the difference
# between 4 minutes (old) and 2m20s (new).
#
# Maintenance:
# 1) Run `make check` so LOG is up-to-date.
# 2) Run `make suggest-slow-tests` to see candidate slow binaries.
# 3) Add binaries with high per-shard time (slow critical path) or high
# total time across many shards (need early queueing for fan-out).
# Each alternative is wrapped in `^.*NAME.*$$` so the *whole input line* is
# captured into $$1; then `s,(...),100 $$1,` prepends "100 " to the line.
# 152.120 PASS t/DBTest.FileCreationRandomFailure
# 107.816 PASS t/DBTest.EncodeDecompressedBlockSizeTest
#
# Tiers below are based on observed timings (see suggest-slow-tests).
# Tier 1: max single-shard time >= 30s (critical-path bottlenecks).
# Tier 2: max single-shard time 15-30s.
# Tier 3: huge total time across many tiny shards; front-loading them keeps
# the tail of the run busy while big shards finish.
slow_test_regexp = \
^.*point_lock_manager_stress_test.*$$|^.*db_test.*$$|^.*external_sst_file_test.*$$|^.*compaction_service_test.*$$|^.*corruption_test.*$$|^.*comparator_db_test.*$$|^.*external_sst_file_basic_test.*$$|^.*rate_limiter_test.*$$|^.*db_compaction_test.*$$|^.*write_prepared_transaction_test.*$$|^.*db_merge_operator_test.*$$|\
^.*db_dynamic_level_test.*$$|^.*db_bloom_filter_test.*$$|^.*error_handler_fs_test.*$$|^.*merge_helper_test.*$$|^.*transaction_test.*$$|^.*db_kv_checksum_test.*$$|^.*inlineskiplist_test.*$$|\
^.*db_with_timestamp_basic_test.*$$|^.*table_test.*$$|^.*db_wal_test.*$$|^.*block_based_table_reader_test.*$$|^.*block_test.*$$|\
^.*run-check-c-api-gen.*$$|^.*run-check-format.*$$
^.*MySQLStyleTransactionTest.*$$|^.*SnapshotConcurrentAccessTest.*$$|^.*SeqAdvanceConcurrentTest.*$$|^t/run-table_test-HarnessTest.Randomized$$|^t/run-db_test-.*(?:FileCreationRandomFailure|EncodeDecompressedBlockSizeTest)$$|^.*RecoverFromCorruptedWALWithoutFlush$$
prioritize_long_running_tests = \
perl -pe 's,($(slow_test_regexp)),100 $$1,' \
| sort -k1,1gr \
| sed 's/^[.0-9]* //'
# Helper: print binaries observed to be slow in the last `make check` run.
# Use this to decide whether `slow_test_regexp` above needs updating.
# Aggregates per-binary across shards; flags any binary whose max single-shard
# time is >= 20s OR whose total time is >= 200s.
.PHONY: suggest-slow-tests
suggest-slow-tests:
@if [ ! -s LOG ]; then \
echo "No (or empty) LOG file. Run 'make check' first." >&2; exit 1; \
fi
@bash -c '$(quoted_perl_command)' < LOG | awk '\
{ \
t=$$1; name=$$3; \
sub(/^t\/run-/, "", name); \
sub(/-shard-[0-9]+$$/, "", name); \
total[name] += t; \
if (t > max[name]) max[name] = t; \
count[name]++; \
} \
END { \
printf "%8s %8s %5s %s\n", "TOTAL_s", "MAX_s", "SHRDS", "BINARY"; \
for (n in total) \
if (max[n] >= 20 || total[n] >= 200) \
printf "%8.1f %8.1f %5d %s\n", total[n], max[n], count[n], n; \
}' | (read header; echo "$$header"; sort -k2,2gr)
# "make check" uses
# Run with "make J=1 check" to disable parallelism in "make check".
# Run with "make J=200% check" to run two parallel jobs per core.
@@ -1101,14 +951,8 @@ check_0:
'To monitor subtest <duration,pass/fail,name>,' \
' run "make watch-log" in a separate window' ''; \
{ \
NON_PARALLEL_LIST="$(filter-out $(PARALLEL_TEST),$(ROCKSDBTESTS_SUBSET))"; \
if [ -n "$$NON_PARALLEL_LIST" ]; then \
printf './%s\n' $$NON_PARALLEL_LIST \
| if [ -n "$(CI_TOTAL_SHARDS)" ]; then \
awk -v s=$(CI_SHARD_INDEX) -v n=$(CI_TOTAL_SHARDS) '(NR-1)%n==s'; \
else cat; fi; \
fi; \
$(FIND) t -name 'run-*' -print; \
printf './%s\n' $(filter-out $(PARALLEL_TEST),$(TESTS)); \
find t -name 'run-*' -print; \
} \
| $(prioritize_long_running_tests) \
| grep -E '$(tests-regexp)' \
@@ -1130,7 +974,7 @@ valgrind_check_0:
' run "make watch-log" in a separate window' ''; \
{ \
printf './%s\n' $(filter-out $(PARALLEL_TEST) %skiplist_test options_settable_test, $(TESTS)); \
$(FIND) t -name 'run-*' -print; \
find t -name 'run-*' -print; \
} \
| $(prioritize_long_running_tests) \
| grep -E '$(tests-regexp)' \
@@ -1155,128 +999,32 @@ watch-log:
dump-log:
bash -c '$(quoted_perl_command)' < LOG
# Machine-parseable progress output for automated monitoring (e.g., Claude Code)
# Outputs JSON: {"status":"running","completed":45,"total":100,"failed":0,"percent":45,"eta_seconds":120}
check-progress:
@build_tools/check_progress.sh
# If J != 1 and GNU parallel is installed, run the tests in parallel,
# via the check_0 rule above. Otherwise, run them sequentially.
check: all
$(AM_V_at)echo "Cleaning up stale test directories older than 3 hours..."; \
test_tmpdir_parent=$$(dirname $(TEST_TMPDIR)); \
find $$test_tmpdir_parent -maxdepth 1 -name 'rocksdb.*' -type d \
-mmin +180 -exec rm -rf {} + 2>/dev/null; \
true
$(MAKE) gen_parallel_tests
$(AM_V_GEN)if test "$(J)" != 1 \
&& (build_tools/gnu_parallel --gnu --help 2>/dev/null) | \
grep -q 'GNU Parallel'; \
then \
$(MAKE) gen_check_scripts; \
$(MAKE) T="$$t" check_0; \
else \
for t in $(TESTS); do \
echo "===== Running $$t (`date`)"; ./$$t || exit 1; done; \
for t in $(CHECK_EXTRA_TARGETS); do \
echo "===== Running $$t (`date`)"; $(MAKE) $$t || exit 1; done; \
fi
rm -rf $(TEST_TMPDIR)
# NOTE: ^^^^^^^^ don't add new auxiliary checks here, but instead to
# CHECK_EXTRA_TARGETS
# Check that the auto-generated C API files are up to date. It regenerates the
# fragments and the inlined c.h/c.cc and compares them against a snapshot of the
# checked-in copies (no net change when everything is up to date). It requires
# clang++ (libclang, used to parse the C++ headers) and clang-format. When those
# are unavailable the staleness/compat sub-checks are SKIPPED with a message so
# `make check` still works without the codegen toolchain; the link-completeness
# sub-check always runs (it needs no toolchain).
#
# Pin the formatter to match CI by setting CLANG_FORMAT_BINARY, e.g.:
# make check-c-api-gen CLANG_FORMAT_BINARY=clang-format-21
# This target is part of `make check` and is skipped by SKIP_FORMAT_BUCK_CHECKS.
#
# Set CHECK_C_API_GEN_STRICT=1 to turn every "skip" below into a hard error, so a
# core CI job that runs this target cannot silently regress to a no-op if a
# prerequisite (clang++, or the compat baseline ref) goes missing. The dedicated
# build-linux-clang-21-no_test_run CI job runs this target with the flag set.
# Any non-empty value other than 0/no/false enables strict mode.
CLANG_FORMAT_BINARY ?=
# Backward-compatibility baseline for the C API (signature-level) check. CI
# overrides this with the PR's merge target or the branch's pre-push tip;
# locally it falls back to main or origin/main and is skipped if neither resolves.
API_COMPAT_REF ?= main
CHECK_C_API_GEN_STRICT ?=
check-c-api-gen:
# Link-completeness is a property of the checked-in c.h/c.cc and needs no
# clang toolchain, so it always runs: every declared public C API function
# must have exactly one definition (guards against dropped wrappers that
# would break downstream language bindings at link time).
$(PYTHON) tools/c_api_gen/check_api_completeness.py
# Backward-compatibility: no public C function may be removed or have its
# signature changed vs the baseline. Skipped if the baseline ref is not
# resolvable locally (CI passes an explicit ref), unless CHECK_C_API_GEN_STRICT.
@strict=""; case "$(CHECK_C_API_GEN_STRICT)" in ""|0|no|NO|false|FALSE) ;; *) strict=1 ;; esac; \
ref=""; \
if git rev-parse --verify --quiet "$(API_COMPAT_REF)^{commit}" >/dev/null; then ref="$(API_COMPAT_REF)"; \
elif git rev-parse --verify --quiet "origin/$(API_COMPAT_REF)^{commit}" >/dev/null; then ref="origin/$(API_COMPAT_REF)"; fi; \
if [ -n "$$ref" ]; then \
$(PYTHON) tools/c_api_gen/check_api_compatibility.py --ref "$$ref"; \
elif [ -n "$$strict" ]; then \
echo "ERROR: C API compat baseline '$(API_COMPAT_REF)' not resolvable and CHECK_C_API_GEN_STRICT is set" >&2; exit 1; \
else \
echo "Skipping C API backward-compatibility check ($(API_COMPAT_REF) not found; set API_COMPAT_REF)"; \
fi
# Staleness: regenerate and confirm the checked-in output is current. Needs a
# clang++ (the generator parses C++ ASTs). Use CLANG_CXX, which
# build_tools/build_detect_platform resolves once (the fbcode clang++ in
# fbcode builds, else a versioned clang++ on PATH) and passes explicitly, so
# the check and the generator agree on the same binary without heuristics.
@strict=""; case "$(CHECK_C_API_GEN_STRICT)" in ""|0|no|NO|false|FALSE) ;; *) strict=1 ;; esac; \
cf_arg=""; \
if [ -n "$(CLANG_FORMAT_BINARY)" ]; then cf_arg="--clang-format $(CLANG_FORMAT_BINARY)"; fi; \
if [ -n "$(CLANG_CXX)" ] && command -v "$(CLANG_CXX)" >/dev/null 2>&1; then \
$(PYTHON) tools/c_api_gen/verify_generated_up_to_date.py --clang "$(CLANG_CXX)" $$cf_arg; \
elif [ -n "$$strict" ]; then \
echo "ERROR: no clang++ found (CLANG_CXX unset) and CHECK_C_API_GEN_STRICT is set; cannot run the C API staleness check" >&2; exit 1; \
else \
echo "Skipping C API codegen staleness check (no clang++ found; CLANG_CXX unset, install clang++ to enable)"; \
fi
# Regenerate the checked-in C API generated files (fragments under c_api_gen/,
# the inlined include/rocksdb/c.h and db/c.cc, and the round-trip tests). Uses
# CLANG_CXX (resolved by build_tools/build_detect_platform) so it works in a gcc
# build too. Aborts up front if no usable clang++ is available, so a bad
# toolchain never leaves the tree in a partially regenerated state. Pin the
# formatter to match CI with CLANG_FORMAT_BINARY, e.g.:
# make regen-c-api CLANG_FORMAT_BINARY=clang-format-21
.PHONY: regen-c-api
regen-c-api:
@if [ -z "$(CLANG_CXX)" ] || ! command -v "$(CLANG_CXX)" >/dev/null 2>&1; then \
echo "ERROR: no clang++ found (CLANG_CXX unset); build on a host with clang++ or the fbcode toolchain to regenerate the C API" >&2; exit 1; \
fi
@cf_arg=""; \
if [ -n "$(CLANG_FORMAT_BINARY)" ]; then cf_arg="--clang-format $(CLANG_FORMAT_BINARY)"; fi; \
$(PYTHON) tools/c_api_gen/regen_all.py --clang "$(CLANG_CXX)" $$cf_arg
# Quick local validation for C API generation plus the focused C API test.
# This verifies the checked-in generated fragments as well as the inlined
# include/rocksdb/c.h and db/c.cc outputs, then runs c_test in an isolated
# TEST_TMPDIR to avoid stale-state failures.
check-c-api-c_test:
$(PYTHON) tools/c_api_gen/verify_generated_up_to_date.py --clang "$(CLANG_CXX)"
$(MAKE) c_test
@tmpdir=$$(mktemp -d); \
trap 'rm -rf "$$tmpdir"' EXIT; \
echo "===== Running c_test with TEST_TMPDIR=$$tmpdir"; \
if command -v timeout >/dev/null 2>&1; then \
TEST_TMPDIR="$$tmpdir" timeout 60 ./c_test; \
elif command -v gtimeout >/dev/null 2>&1; then \
TEST_TMPDIR="$$tmpdir" gtimeout 60 ./c_test; \
else \
TEST_TMPDIR="$$tmpdir" ./c_test; \
fi
ifneq ($(PLATFORM), OS_AIX)
$(PYTHON) tools/check_all_python.py
ifndef ASSERT_STATUS_CHECKED # not yet working with these tests
$(PYTHON) tools/ldb_test.py
sh tools/rocksdb_dump_test.sh
endif
endif
ifndef SKIP_FORMAT_BUCK_CHECKS
$(MAKE) check-format
$(MAKE) check-buck-targets
$(MAKE) check-sources
endif
# TODO add ldb_tests
check_some: $(ROCKSDBTESTS_SUBSET)
@@ -1286,18 +1034,6 @@ check_some: $(ROCKSDBTESTS_SUBSET)
ldb_tests: ldb
$(PYTHON) tools/ldb_test.py
.PHONY: db_crashtest_tests
db_crashtest_tests:
$(PYTHON) tools/db_crashtest_test.py
.PHONY: check-all-python
check-all-python:
$(PYTHON) tools/check_all_python.py
.PHONY: rocksdb_dump_test
rocksdb_dump_test: rocksdb_dump rocksdb_undump
sh tools/rocksdb_dump_test.sh
include crash_test.mk
asan_check: clean
@@ -1435,32 +1171,16 @@ rocksdb.h rocksdb.cc: build_tools/amalgamate.py Makefile $(LIB_SOURCES) unity.cc
build_tools/amalgamate.py -I. -i./include unity.cc -x include/rocksdb/c.h -H rocksdb.h -o rocksdb.cc
clean: clean-ext-libraries-all clean-rocks clean-rocksjava
# Removed here rather than in clean-rocks (via CLEAN_FILES) so the build-parameter
# auto-clean, which runs clean-rocks, doesn't delete the make_config.mk already
# included by the in-progress make.
@rm -f make_config.mk
clean-not-downloaded: clean-ext-libraries-bin clean-rocks clean-not-downloaded-rocksjava
@rm -f make_config.mk
clean-rocks:
# Not practical to exactly match all versions/variants in naming (e.g. debug or not)
@echo Removing link targets
@rm -f ${LIBNAME}*.so* ${LIBNAME}*.a $(BENCHMARKS) $(TOOLS) $(TESTS) $(PARALLEL_TEST) $(MICROBENCHS)
@echo Finding and cleaning other files
@rm -rf $(CLEAN_FILES) ios-x86 ios-arm scan_build_report
@if $(FIND) Makefile -regextype awk &> /dev/null; then \
$(FIND) . -regextype awk \
-regex '.*/([.].*|third-party)' -prune -o \
-type f -regex '.*[.]([oda]|gcda|gcno)' -exec rm -f {} \; ; \
else \
$(FIND) . -name "*.[oda]" -exec rm -f {} \; ; \
fi
# Remove the build signature(s) LAST. Done after the object files are gone so
# that a Ctrl+C partway through clean leaves the old signature in place: it
# still matches the leftover objects, so a later build with different
# parameters is still detected (signature usefulness is preserved).
@rm -f $(BUILD_SIG_FILE) jl/.build_signature jls/.build_signature
rm -f ${LIBNAME}*.so* ${LIBNAME}*.a
rm -f $(BENCHMARKS) $(TOOLS) $(TESTS) $(PARALLEL_TEST) $(MICROBENCHS)
rm -rf $(CLEAN_FILES) ios-x86 ios-arm scan_build_report
$(FIND) . -name "*.[oda]" -exec rm -f {} \;
$(FIND) . -type f \( -name "*.gcda" -o -name "*.gcno" \) -exec rm -f {} \;
clean-rocksjava: clean-rocks
rm -rf jl jls
@@ -1473,7 +1193,7 @@ clean-ext-libraries-all:
rm -rf bzip2* snappy* zlib* lz4* zstd*
clean-ext-libraries-bin:
$(FIND) . -maxdepth 1 -type d \( -name bzip2\* -or -name snappy\* -or -name zlib\* -or -name lz4\* -or -name zstd\* \) -prune -exec rm -rf {} \;
find . -maxdepth 1 -type d \( -name bzip2\* -or -name snappy\* -or -name zlib\* -or -name lz4\* -or -name zstd\* \) -prune -exec rm -rf {} \;
tags:
ctags -R .
@@ -1490,59 +1210,15 @@ tags0:
format:
build_tools/format-diff.sh
# Non-interactive format (auto-apply without prompts, for CI/automation/Claude Code)
format-auto:
build_tools/format-diff.sh -y
check-format:
build_tools/format-diff.sh -c
# Crude alternative to setup-hooks: copies hooks into .git/hooks/ instead of
# using core.hooksPath. The copies won't track changes to githooks/.
install-hooks:
@echo "Installing git hooks from githooks/..."
@if [ -d githooks ]; then \
for hook in githooks/*; do \
hook_name=$$(basename "$$hook"); \
cp "$$hook" .git/hooks/"$$hook_name"; \
chmod +x .git/hooks/"$$hook_name"; \
echo " Installed $$hook_name"; \
done; \
echo "Done. Hooks installed to .git/hooks/"; \
else \
echo "Error: githooks/ directory not found"; \
exit 1; \
fi
# Reverse of install-hooks (not needed if using setup-hooks / core.hooksPath).
uninstall-hooks:
@echo "Removing installed git hooks..."
@for hook in githooks/*; do \
hook_name=$$(basename "$$hook"); \
rm -f .git/hooks/"$$hook_name"; \
echo " Removed $$hook_name"; \
done
@echo "Done."
check-buck-targets:
buckifier/check_buck_targets.sh
check-sources:
build_tools/check-sources.sh
check-workflow-yaml:
build_tools/check-workflow-yaml.sh
# Run clang-tidy on locally changed files, filtered to changed lines only.
# Requires compile_commands.json (generate with cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON).
# Override CLANG_TIDY_BINARY and CLANG_TIDY_JOBS as needed:
# make clang-tidy CLANG_TIDY_BINARY=/usr/bin/clang-tidy CLANG_TIDY_JOBS=8
CLANG_TIDY_BINARY ?= /opt/homebrew/opt/llvm/bin/clang-tidy
CLANG_TIDY_JOBS ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
clang-tidy:
python3 tools/run_clang_tidy.py --clang-tidy-binary $(CLANG_TIDY_BINARY) -j $(CLANG_TIDY_JOBS)
package:
bash build_tools/make_package.sh $(SHARED_MAJOR).$(SHARED_MINOR)
@@ -1721,9 +1397,6 @@ db_basic_test: $(OBJ_DIR)/db/db_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
db_blob_basic_test: $(OBJ_DIR)/db/blob/db_blob_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_blob_direct_write_test: $(OBJ_DIR)/db/blob/db_blob_direct_write_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_blob_compaction_test: $(OBJ_DIR)/db/blob/db_blob_compaction_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -1733,12 +1406,6 @@ db_readonly_with_timestamp_test: $(OBJ_DIR)/db/db_readonly_with_timestamp_test.o
db_wide_basic_test: $(OBJ_DIR)/db/wide/db_wide_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_lazy_entity_test: $(OBJ_DIR)/db/wide/db_lazy_entity_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_wide_blob_direct_write_test: $(OBJ_DIR)/db/wide/db_wide_blob_direct_write_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_with_timestamp_basic_test: $(OBJ_DIR)/db/db_with_timestamp_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -1748,13 +1415,10 @@ db_with_timestamp_compaction_test: db/db_with_timestamp_compaction_test.o $(TEST
db_encryption_test: $(OBJ_DIR)/db/db_encryption_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_open_with_config_test: $(OBJ_DIR)/db/db_open_with_config_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_test: $(OBJ_DIR)/db/db_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_etc2_test: $(OBJ_DIR)/db/db_etc2_test.o $(TEST_LIBRARY) $(LIBRARY)
db_test2: $(OBJ_DIR)/db/db_test2.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_etc3_test: $(OBJ_DIR)/db/db_etc3_test.o $(TEST_LIBRARY) $(LIBRARY)
@@ -1784,9 +1448,6 @@ db_compaction_filter_test: $(OBJ_DIR)/db/db_compaction_filter_test.o $(TEST_LIBR
db_compaction_test: $(OBJ_DIR)/db/db_compaction_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_compaction_abort_test: $(OBJ_DIR)/db/db_compaction_abort_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
db_clip_test: $(OBJ_DIR)/db/db_clip_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -1895,12 +1556,6 @@ backup_engine_test: $(OBJ_DIR)/utilities/backup/backup_engine_test.o $(TEST_LIBR
checkpoint_test: $(OBJ_DIR)/utilities/checkpoint/checkpoint_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
copy_engine_test: $(OBJ_DIR)/utilities/copy_engine/copy_engine_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
sorted_run_builder_test: $(OBJ_DIR)/utilities/sorted_run_builder/sorted_run_builder_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
cache_simulator_test: $(OBJ_DIR)/utilities/simulator_cache/cache_simulator_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -1919,12 +1574,6 @@ object_registry_test: $(OBJ_DIR)/utilities/object_registry_test.o $(TEST_LIBRARY
ttl_test: $(OBJ_DIR)/utilities/ttl/ttl_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
trie_index_db_test: $(OBJ_DIR)/utilities/trie_index/trie_index_db_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
trie_index_test: $(OBJ_DIR)/utilities/trie_index/trie_index_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
types_util_test: $(OBJ_DIR)/utilities/types_util_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -1976,9 +1625,6 @@ io_posix_test: $(OBJ_DIR)/env/io_posix_test.o $(TEST_LIBRARY) $(LIBRARY)
fault_injection_test: $(OBJ_DIR)/db/fault_injection_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
fault_injection_fs_test: $(OBJ_DIR)/utilities/fault_injection_fs_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
rate_limiter_test: $(OBJ_DIR)/util/rate_limiter_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -2177,9 +1823,6 @@ write_committed_transaction_ts_test: $(OBJ_DIR)/utilities/transactions/write_com
write_prepared_transaction_test: $(OBJ_DIR)/utilities/transactions/write_prepared_transaction_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
write_prepared_transaction_seqno_test: $(OBJ_DIR)/utilities/transactions/write_prepared_transaction_seqno_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
write_unprepared_transaction_test: $(OBJ_DIR)/utilities/transactions/write_unprepared_transaction_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -2285,9 +1928,6 @@ blob_source_test: $(OBJ_DIR)/db/blob/blob_source_test.o $(TEST_LIBRARY) $(LIBRAR
blob_garbage_meter_test: $(OBJ_DIR)/db/blob/blob_garbage_meter_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
io_dispatcher_test: $(OBJ_DIR)/util/io_dispatcher_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
timer_test: $(OBJ_DIR)/util/timer_test.o $(TEST_LIBRARY) $(LIBRARY)
$(AM_LINK)
@@ -2440,27 +2080,22 @@ ROCKSDB_JAVADOCS_JAR = rocksdbjni-$(ROCKSDB_JAVA_VERSION)-javadoc.jar
ROCKSDB_SOURCES_JAR = rocksdbjni-$(ROCKSDB_JAVA_VERSION)-sources.jar
SHA256_CMD = sha256sum
# The *_DOWNLOAD_PREFIX defaults below point at the upstream projects; CI
# overrides them to a mirror on the "third-party-deps" GitHub release (see
# .github/actions/pre-steps/action.yml). When bumping a version, see
# instructions in CI config comments for how to update that release.
ZLIB_VER ?= 1.3.1
ZLIB_SHA256 ?= 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23
ZLIB_DOWNLOAD_PREFIX ?= http://zlib.net/zlib-
ZLIB_DOWNLOAD_BASE ?= http://zlib.net
BZIP2_VER ?= 1.0.8
BZIP2_SHA256 ?= ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269
BZIP2_DOWNLOAD_PREFIX ?= http://sourceware.org/pub/bzip2/bzip2-
BZIP2_DOWNLOAD_BASE ?= http://sourceware.org/pub/bzip2
SNAPPY_VER ?= 1.2.2
SNAPPY_SHA256 ?= 90f74bc1fbf78a6c56b3c4a082a05103b3a56bb17bca1a27e052ea11723292dc
SNAPPY_DOWNLOAD_PREFIX ?= https://github.com/google/snappy/archive/
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
LZ4_VER ?= 1.10.0
LZ4_SHA256 ?= 537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b
LZ4_DOWNLOAD_PREFIX ?= https://github.com/lz4/lz4/archive/v
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
ZSTD_VER ?= 1.5.7
ZSTD_SHA256 ?= 37d7284556b20954e56e1ca85b80226768902e2edabd3b649e9e72c0c9012ee3
ZSTD_DOWNLOAD_PREFIX ?= https://github.com/facebook/zstd/archive/v
# curl with the common options used to fetch the pinned third-party sources above
CURL_DOWNLOAD = curl --fail --location --retry 3 --retry-all-errors
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
CURL_SSL_OPTS ?= --tlsv1
ifeq ($(PLATFORM), OS_MACOSX)
ifeq (,$(findstring librocksdbjni-osx,$(ROCKSDBJNILIB)))
@@ -2505,103 +2140,8 @@ ifeq ($(PLATFORM), OS_OPENBSD)
endif
export SHA256_CMD
# ----------------------------------------------------------------------------
# Build parameter change detection
# ----------------------------------------------------------------------------
# RocksDB writes object files to the same $(OBJ_DIR) paths regardless of
# DEBUG_LEVEL, sanitizers (ASAN/TSAN/UBSAN), ASSERT_STATUS_CHECKED, RTTI, LTO,
# COERCE_CONTEXT_SWITCH, etc. Most of those are applied in this Makefile after
# `include make_config.mk` and are therefore NOT reflected in make_config.mk,
# so switching them and rebuilding silently mixes incompatible object files.
# To guard against that, we hash the fully-resolved compile/link parameters
# (which already embed make_config.mk via PLATFORM_*) and compare against the
# value recorded from the previous build. On mismatch the build stops so the
# user can `make clean`. Knobs:
# AUTO_CLEAN=1
# run `make clean-rocks` automatically on mismatch
# ALLOW_BUILD_PARAMETER_CHANGE=1
# skip the check entirely (e.g. intentionally mixing DEBUG_LEVEL=1 and
# DEBUG_LEVEL=2)
# The signature is stored per-$(OBJ_DIR), so Java (jl/jls) builds are tracked
# independently from the default build.
BUILD_SIG_FILE := $(OBJ_DIR)/.build_signature
# NOTE: deliberately NOT added to CLEAN_FILES. The signature is removed as the
# very last step of clean-rocks so that an interrupted clean keeps it (see
# clean-rocks), preserving change detection across a Ctrl+C'd clean.
# Goals that do not compile object files into the tree (pure utilities,
# informational, source/config checks): the change check is irrelevant for them.
BUILD_SIG_NONBUILD_GOALS := \
clean clean-rocks clean-not-downloaded clean-rocksjava \
clean-not-downloaded-rocksjava clean-ext-libraries-all \
clean-ext-libraries-bin \
format format-auto check-format check-buck-targets check-headers \
check-sources check-workflow-yaml check-progress clang-tidy \
tags tags0 package jclean checkout_folly build_folly \
watch-log dump-log suggest-slow-tests list_all_tests gen-pc \
gen_parallel_tests gen_check_scripts check-c-api-gen check-all-python \
setup-hooks install-hooks uninstall-hooks uninstall db_crashtest_tests
# Goals that clean before building (depend on or invoke `clean`): they manage
# their own freshness, so the check must not block them (it would error before
# their built-in clean runs).
BUILD_SIG_NONBUILD_GOALS += \
release coverage build_size analyze analyze_incremental \
asan_check asan_crash_test asan_crash_test_with_atomic_flush \
asan_crash_test_with_txn asan_crash_test_with_best_efforts_recovery \
whitebox_asan_crash_test blackbox_asan_crash_test \
ubsan_check ubsan_crash_test ubsan_crash_test_with_atomic_flush \
ubsan_crash_test_with_txn ubsan_crash_test_with_best_efforts_recovery \
whitebox_ubsan_crash_test blackbox_ubsan_crash_test
# Goals that explicitly clean; never trip the check when one is requested.
BUILD_SIG_CLEAN_GOALS := \
clean clean-rocks clean-not-downloaded clean-rocksjava \
clean-not-downloaded-rocksjava clean-ext-libraries-all \
clean-ext-libraries-bin
BUILD_SIG_GOALS := $(if $(MAKECMDGOALS),$(MAKECMDGOALS),all)
BUILD_SIG_DO_BUILD := $(filter-out $(BUILD_SIG_NONBUILD_GOALS),$(BUILD_SIG_GOALS))
BUILD_SIG_CLEANING := $(filter $(BUILD_SIG_CLEAN_GOALS),$(MAKECMDGOALS))
# Dry runs (-n/--just-print) must not write the stamp, clean, or error; the
# parse-time $(shell) below would otherwise run even under -n. Note that
# actual options are canonicalized and shorted as possible such that all
# short options are in the first word of MAKEFLAGS.
BUILD_SIG_DRYRUN := $(findstring n,$(firstword -$(MAKEFLAGS)))
# Only enforce at the top level. Sub-makes (e.g. `check` invokes
# $(MAKE) gen_parallel_tests / check-c-api-gen / check_0) inherit the parent's
# build flags, so the top-level check already covers them; re-checking inside a
# sub-make only causes spurious failures.
ifneq ($(ALLOW_BUILD_PARAMETER_CHANGE),1)
ifeq ($(MAKELEVEL),0)
ifeq ($(BUILD_SIG_DRYRUN),)
ifeq ($(BUILD_SIG_CLEANING),)
ifneq ($(BUILD_SIG_DO_BUILD),)
BUILD_SIG := $(shell printf '%s' '$(CC)|$(CXX)|$(CFLAGS)|$(CXXFLAGS)|$(LDFLAGS)|$(EXEC_LDFLAGS)' | $(SHA256_CMD) | cut -d ' ' -f 1)
BUILD_SIG_OLD := $(shell cat $(BUILD_SIG_FILE) 2>/dev/null)
ifneq ($(BUILD_SIG_OLD),)
ifneq ($(BUILD_SIG_OLD),$(BUILD_SIG))
ifeq ($(AUTO_CLEAN),1)
$(info *** Build parameters changed since last build (OBJ_DIR=$(OBJ_DIR)); running 'make clean-rocks' because AUTO_CLEAN=1)
BUILD_SIG_CLEAN_OUTPUT := $(shell $(MAKE) clean-rocks 1>&2)
ifneq ($(.SHELLSTATUS),0)
$(error AUTO_CLEAN: 'make clean-rocks' failed (exit $(.SHELLSTATUS)); not building against a partially-cleaned tree)
endif
else
$(error Build parameters changed since the last build (OBJ_DIR=$(OBJ_DIR)). Existing object files are stale and must be removed. Run 'make clean', or set AUTO_CLEAN=1 to clean automatically, or ALLOW_BUILD_PARAMETER_CHANGE=1 to build anyway)
endif
endif
endif
# Record the current signature for the next build.
BUILD_SIG_WRITE := $(shell mkdir -p $(OBJ_DIR) 2>/dev/null; printf '%s\n' '$(BUILD_SIG)' > $(BUILD_SIG_FILE))
endif
endif
endif
endif
endif
zlib-$(ZLIB_VER).tar.gz:
$(CURL_DOWNLOAD) --output zlib-$(ZLIB_VER).tar.gz ${ZLIB_DOWNLOAD_PREFIX}$(ZLIB_VER).tar.gz
curl --fail --output zlib-$(ZLIB_VER).tar.gz --location ${ZLIB_DOWNLOAD_BASE}/zlib-$(ZLIB_VER).tar.gz
ZLIB_SHA256_ACTUAL=`$(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz | cut -d ' ' -f 1`; \
if [ "$(ZLIB_SHA256)" != "$$ZLIB_SHA256_ACTUAL" ]; then \
echo zlib-$(ZLIB_VER).tar.gz checksum mismatch, expected=\"$(ZLIB_SHA256)\" actual=\"$$ZLIB_SHA256_ACTUAL\"; \
@@ -2619,7 +2159,7 @@ libz.a: zlib-$(ZLIB_VER).tar.gz
cp zlib-$(ZLIB_VER)/libz.a .
bzip2-$(BZIP2_VER).tar.gz:
$(CURL_DOWNLOAD) --output bzip2-$(BZIP2_VER).tar.gz ${BZIP2_DOWNLOAD_PREFIX}$(BZIP2_VER).tar.gz
curl --fail --output bzip2-$(BZIP2_VER).tar.gz --location ${CURL_SSL_OPTS} ${BZIP2_DOWNLOAD_BASE}/bzip2-$(BZIP2_VER).tar.gz
BZIP2_SHA256_ACTUAL=`$(SHA256_CMD) bzip2-$(BZIP2_VER).tar.gz | cut -d ' ' -f 1`; \
if [ "$(BZIP2_SHA256)" != "$$BZIP2_SHA256_ACTUAL" ]; then \
echo bzip2-$(BZIP2_VER).tar.gz checksum mismatch, expected=\"$(BZIP2_SHA256)\" actual=\"$$BZIP2_SHA256_ACTUAL\"; \
@@ -2633,7 +2173,7 @@ libbz2.a: bzip2-$(BZIP2_VER).tar.gz
cp bzip2-$(BZIP2_VER)/libbz2.a .
snappy-$(SNAPPY_VER).tar.gz:
$(CURL_DOWNLOAD) --output snappy-$(SNAPPY_VER).tar.gz ${SNAPPY_DOWNLOAD_PREFIX}$(SNAPPY_VER).tar.gz
curl --fail --output snappy-$(SNAPPY_VER).tar.gz --location ${CURL_SSL_OPTS} ${SNAPPY_DOWNLOAD_BASE}/$(SNAPPY_VER).tar.gz
SNAPPY_SHA256_ACTUAL=`$(SHA256_CMD) snappy-$(SNAPPY_VER).tar.gz | cut -d ' ' -f 1`; \
if [ "$(SNAPPY_SHA256)" != "$$SNAPPY_SHA256_ACTUAL" ]; then \
echo snappy-$(SNAPPY_VER).tar.gz checksum mismatch, expected=\"$(SNAPPY_SHA256)\" actual=\"$$SNAPPY_SHA256_ACTUAL\"; \
@@ -2648,7 +2188,7 @@ libsnappy.a: snappy-$(SNAPPY_VER).tar.gz
cp snappy-$(SNAPPY_VER)/build/libsnappy.a .
lz4-$(LZ4_VER).tar.gz:
$(CURL_DOWNLOAD) --output lz4-$(LZ4_VER).tar.gz ${LZ4_DOWNLOAD_PREFIX}$(LZ4_VER).tar.gz
curl --fail --output lz4-$(LZ4_VER).tar.gz --location ${CURL_SSL_OPTS} ${LZ4_DOWNLOAD_BASE}/v$(LZ4_VER).tar.gz
LZ4_SHA256_ACTUAL=`$(SHA256_CMD) lz4-$(LZ4_VER).tar.gz | cut -d ' ' -f 1`; \
if [ "$(LZ4_SHA256)" != "$$LZ4_SHA256_ACTUAL" ]; then \
echo lz4-$(LZ4_VER).tar.gz checksum mismatch, expected=\"$(LZ4_SHA256)\" actual=\"$$LZ4_SHA256_ACTUAL\"; \
@@ -2662,7 +2202,7 @@ liblz4.a: lz4-$(LZ4_VER).tar.gz
cp lz4-$(LZ4_VER)/lib/liblz4.a .
zstd-$(ZSTD_VER).tar.gz:
$(CURL_DOWNLOAD) --output zstd-$(ZSTD_VER).tar.gz ${ZSTD_DOWNLOAD_PREFIX}$(ZSTD_VER).tar.gz
curl --fail --output zstd-$(ZSTD_VER).tar.gz --location ${CURL_SSL_OPTS} ${ZSTD_DOWNLOAD_BASE}/v$(ZSTD_VER).tar.gz
ZSTD_SHA256_ACTUAL=`$(SHA256_CMD) zstd-$(ZSTD_VER).tar.gz | cut -d ' ' -f 1`; \
if [ "$(ZSTD_SHA256)" != "$$ZSTD_SHA256_ACTUAL" ]; then \
echo zstd-$(ZSTD_VER).tar.gz checksum mismatch, expected=\"$(ZSTD_SHA256)\" actual=\"$$ZSTD_SHA256_ACTUAL\"; \
@@ -3000,7 +2540,7 @@ list_all_tests:
# Remove the rules for which dependencies should not be generated and see if any are left.
#If so, include the dependencies; if not, do not include the dependency files
ROCKS_DEP_RULES=$(filter-out clean format check-format check-buck-targets check-headers check-sources check-workflow-yaml clang-tidy jclean jtest package analyze tags rocksdbjavastatic% unity.% unity_test checkout_folly, $(MAKECMDGOALS))
ROCKS_DEP_RULES=$(filter-out clean format check-format check-buck-targets check-headers check-sources jclean jtest package analyze tags rocksdbjavastatic% unity.% unity_test checkout_folly, $(MAKECMDGOALS))
ifneq ("$(ROCKS_DEP_RULES)", "")
-include $(DEPFILES)
endif
+4 -15
View File
@@ -145,21 +145,11 @@ def generate_buck(repo_path, deps_map):
# always add range_tree, it's only excluded on ppc64, which we don't use internally
src_mk["RANGE_TREE_SOURCES"] + src_mk["TOOL_LIB_SOURCES"],
deps=[
"//folly:executor",
"//folly/container:f14_hash",
"//folly/coro:baton",
"//folly/coro:blocking_wait",
"//folly/coro:collect",
"//folly/coro:coroutine",
"//folly/coro:nothrow",
"//folly/coro:task",
"//folly/executors:io_executor",
"//folly/executors:io_thread_pool_executor",
"//folly/executors/thread_factory:named_thread_factory",
"//folly/io/async:async_base",
"//folly/io/async:event_base_manager",
"//folly/io/async:io_uring_backend",
"//folly/io/async:request_context",
"//folly/experimental/coro:blocking_wait",
"//folly/experimental/coro:collect",
"//folly/experimental/coro:coroutine",
"//folly/experimental/coro:task",
"//folly/synchronization:distributed_mutex",
],
headers=LiteralValue("glob([\"**/*.h\"])")
@@ -370,7 +360,6 @@ def generate_buck(repo_path, deps_map):
extra_compiler_flags=json.dumps(deps["extra_compiler_flags"]),
)
BUCK.export_file("tools/db_crashtest.py")
BUCK.export_file("tools/fault_injection_log_parser.py")
print(ColorString.info("Generated BUCK Summary:"))
print(ColorString.info("- %d libs" % BUCK.total_lib))
-6
View File
@@ -118,12 +118,6 @@ class TARGETSBuilder:
self.total_bin = self.total_bin + 1
def add_c_test(self):
# The actual c_test_bin target is defined by add_c_test_wrapper in the
# internal //rocks/buckifier:defs.bzl (not in this OSS repo). db/c_test.c
# #includes the generated c_api_gen/*.inc fragments, so under Buck's
# hermetic sandbox that wrapper must expose them as headers, e.g.
# headers = native.glob(["c_api_gen/**/*.inc"])
# (Make/CMake resolve the include via -I. / PROJECT_SOURCE_DIR.)
with open(self.path, "ab") as targets_file:
targets_file.write(
b"""
+20 -61
View File
@@ -27,6 +27,7 @@
# -DLZ4 if the LZ4 library is present
# -DZSTD if the ZSTD library is present
# -DNUMA if the NUMA library is present
# -DTBB if the TBB library is present
# -DMEMKIND if the memkind library is present
#
# Using gflags in rocksdb:
@@ -89,36 +90,13 @@ if test -z "$CC"; then
fi
fi
# CLANG_CXX is the single clang++ detection point for the whole script: it is
# used for CXX when building with clang, for CLANG_ANALYZER (scan-build), and by
# tooling that needs clang even in a gcc build (e.g. the C API codegen, which
# parses C++ ASTs). The fbcode config above already sets CLANG_CXX; otherwise
# resolve it here.
if test -z "$CLANG_CXX"; then
if [ -n "$CXX" ] && echo | $CXX -dM -E -x c++ - 2>/dev/null | grep -q '\b__clang__\b'; then
# Honor an already-configured clang compiler (e.g. CI sets
# CXX=clang++-21) so codegen parses headers with the same clang the
# build uses, not an unrelated clang++ that merely happens to come first
# on PATH (an image may ship both a bare clang++ and clang++-NN).
CLANG_CXX="$CXX"
else
# Otherwise take the first clang++ on PATH. Candidates cover a bare
# clang++, versioned names, and clang++.par (a Meta-internal wrapper
# often present on dev machines).
CLANG_CXX=$(command -v clang++ || command -v clang++-21 || command -v clang++-20 \
|| command -v clang++-19 || command -v clang++-18 || command -v clang++-17 \
|| command -v clang++-16 || command -v clang++-15 || command -v clang++-14 \
|| command -v clang++-13 || command -v clang++.par || true)
fi
fi
if test -z "$CXX"; then
if [ "$USE_CLANG" ] && [ -n "$CLANG_CXX" ]; then
CXX="$CLANG_CXX"
if [ "$USE_CLANG" -a -x "$(command -v clang++)" ]; then
CXX=clang++
elif [ -x "$(command -v g++)" ]; then
CXX=g++
elif [ -n "$CLANG_CXX" ]; then
CXX="$CLANG_CXX"
elif [ -x "$(command -v clang++)" ]; then
CXX=clang++
else
CXX=g++
fi
@@ -136,17 +114,6 @@ if test -z "$AR"; then
fi
fi
# If the selected C++ compiler is actually clang (e.g. clang was the only
# compiler available), reflect that as USE_CLANG so clang-specific logic in the
# Makefile applies consistently. Detect it via the compiler's own __clang__
# predefined macro rather than matching the binary path, which can false-positive
# (e.g. a home directory containing "clang").
if test -z "$USE_CLANG"; then
if echo | $CXX -dM -E -x c++ - 2>/dev/null | grep -q '\b__clang__\b'; then
USE_CLANG=1
fi
fi
# Detect OS
if test -z "$TARGET_OS"; then
TARGET_OS=`uname -s`
@@ -161,7 +128,7 @@ if test -z "$CLANG_SCAN_BUILD"; then
fi
if test -z "$CLANG_ANALYZER"; then
CLANG_ANALYZER="$CLANG_CXX"
CLANG_ANALYZER=$(command -v clang++ 2> /dev/null)
fi
if test -z "$FIND"; then
@@ -181,24 +148,6 @@ PLATFORM_SHARED_LDFLAGS="-Wl,--no-as-needed -shared -Wl,-soname -Wl,"
PLATFORM_SHARED_CFLAGS="-fPIC"
PLATFORM_SHARED_VERSIONED=true
# Prefer lld linker when available on Linux. lld is typically 5-10x faster
# than the default ld.bfd for large C++ projects. macOS uses ld64 (or
# ld-prime) which is already fast, so we skip lld detection there.
# Set ROCKSDB_NO_FAST_LINKER=1 to disable this auto-detection.
if [ -z "$ROCKSDB_NO_FAST_LINKER" ] && [ "$TARGET_OS" = "Linux" ]; then
if $CXX -fuse-ld=lld -L/usr/local/lib -x c++ - -o /dev/null 2>/dev/null <<EOF
int main() { return 0; }
EOF
then
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -fuse-ld=lld"
# Ensure lld can find libraries in /usr/local/lib (lld does not
# search there by default, unlike ld.bfd)
if [ -d /usr/local/lib ]; then
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -L/usr/local/lib"
fi
fi
fi
# generic port files (working on all platform by #ifdef) go directly in /port
GENERIC_PORT_FILES=`cd "$ROCKSDB_ROOT"; find port -name '*.cc' | tr "\n" " "`
@@ -457,6 +406,19 @@ EOF
fi
fi
if ! test $ROCKSDB_DISABLE_TBB; then
# Test whether tbb is available
$CXX $PLATFORM_CXXFLAGS $LDFLAGS -x c++ - -o test.o -ltbb 2>/dev/null <<EOF
#include <tbb/tbb.h>
int main() {}
EOF
if [ "$?" = 0 ]; then
COMMON_FLAGS="$COMMON_FLAGS -DTBB"
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -ltbb"
JAVA_LDFLAGS="$JAVA_LDFLAGS -ltbb"
fi
fi
if ! test $ROCKSDB_DISABLE_JEMALLOC; then
# Test whether jemalloc is available
if echo 'int main() {}' | $CXX $PLATFORM_CXXFLAGS $LDFLAGS -x c++ - -o test.o -ljemalloc \
@@ -852,10 +814,6 @@ echo "ROCKSDB_MINOR=$ROCKSDB_MINOR" >> "$OUTPUT"
echo "ROCKSDB_PATCH=$ROCKSDB_PATCH" >> "$OUTPUT"
echo "CLANG_SCAN_BUILD=$CLANG_SCAN_BUILD" >> "$OUTPUT"
echo "CLANG_ANALYZER=$CLANG_ANALYZER" >> "$OUTPUT"
echo "CLANG_CXX=$CLANG_CXX" >> "$OUTPUT"
if test -n "$USE_CLANG"; then
echo "USE_CLANG=$USE_CLANG" >> "$OUTPUT"
fi
echo "PROFILING_FLAGS=$PROFILING_FLAGS" >> "$OUTPUT"
echo "FIND=$FIND" >> "$OUTPUT"
echo "WATCH=$WATCH" >> "$OUTPUT"
@@ -873,6 +831,7 @@ fi
if test -n "$WITH_JEMALLOC_FLAG"; then
echo "WITH_JEMALLOC_FLAG=$WITH_JEMALLOC_FLAG" >> "$OUTPUT"
fi
echo "LUA_PATH=$LUA_PATH" >> "$OUTPUT"
if test -n "$USE_FOLLY"; then
echo "USE_FOLLY=$USE_FOLLY" >> "$OUTPUT"
fi
+3 -6
View File
@@ -1,8 +1,5 @@
#!/usr/bin/env bash
# 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).
# Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
#
# Check for some simple mistakes in public headers (on the command line)
# that should prevent commit or push
@@ -11,7 +8,7 @@ BAD=""
# Look for potential for ODR violations caused by public headers depending on
# build parameters that could vary between RocksDB build and application build.
# * Cases like ROCKSDB_NAMESPACE, and ROCKSDB_ASSERT_STATUS_CHECKED are
# * Cases like LUA, ROCKSDB_NAMESPACE, and ROCKSDB_ASSERT_STATUS_CHECKED are
# intentional, hard to avoid. (We expect definitions to change and the user
# should also.)
# * Cases like _WIN32, OS_WIN, and __cplusplus are essentially ODR-safe.
@@ -22,7 +19,7 @@ BAD=""
# that should not cause ODR violations can be exempted with the ODR-SAFE
# marker recognized here.
grep -nHE '^#if' -- "$@" | grep -vE 'ROCKSDB_NAMESPACE|ROCKSDB_ASSERT_STATUS_CHECKED|_WIN32|OS_WIN|ODR-SAFE|__cplusplus|ROCKSDB_DLL|ROCKSDB_LIBRARY_EXPORTS'
grep -nHE '^#if' -- "$@" | grep -vE 'ROCKSDB_NAMESPACE|ROCKSDB_ASSERT_STATUS_CHECKED|LUA|_WIN32|OS_WIN|ODR-SAFE|__cplusplus|ROCKSDB_DLL|ROCKSDB_LIBRARY_EXPORTS'
if [ "$?" != "1" ]; then
echo "^^^^^ #if in public API could cause an ODR violation."
echo " Add // ODR-SAFE if verified safe."
+1 -1
View File
@@ -37,7 +37,7 @@ if [ "$?" != "1" ]; then
BAD=1
fi
LC_ALL=C git grep -n $'[\x80-\xff]' -- ':!docs' ':!*.md' ':!.github'
git grep -n -P "[\x80-\xFF]" -- ':!docs' ':!*.md'
if [ "$?" != "1" ]; then
echo '^^^^ Use only ASCII characters in source files'
BAD=1
-42
View File
@@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
#
# Validate GitHub Actions workflow YAML before it reaches CI runtime.
set -euo pipefail
if ! command -v ruby >/dev/null 2>&1; then
echo "ruby is required to validate GitHub Actions workflow YAML"
echo "On CentOS Stream: sudo dnf install ruby rubygems rubygem-psych"
exit 1
fi
if ! ruby -e 'require "psych"' 2>/dev/null; then
echo "ruby is installed but cannot load required library 'psych'"
echo "On CentOS Stream: sudo dnf install rubygems rubygem-psych"
exit 1
fi
ruby <<'RUBY'
require "psych"
bad = false
workflow_files = Dir[".github/workflows/*.{yml,yaml}"].sort
if workflow_files.empty?
warn "No workflow YAML files found under .github/workflows"
exit 1
end
workflow_files.each do |path|
begin
Psych.parse_file(path)
puts "OK #{path}"
rescue Psych::Exception => e
warn "Invalid YAML in #{path}: #{e.message}"
bad = true
end
end
exit(bad ? 1 : 0)
RUBY
-231
View File
@@ -1,231 +0,0 @@
#!/bin/bash
# Output test progress in JSON format for machine parsing
# Usage: build_tools/check_progress.sh
LOG_FILE="LOG"
T_DIR="t"
SRC_MK="src.mk"
# Maximum lines of test output to include per failed test
MAX_OUTPUT_LINES=50
# Helper to escape string for JSON (handles newlines, quotes, backslashes, tabs)
json_escape() {
local str="$1"
# Use python for reliable JSON escaping if available, otherwise use sed
if command -v python3 &>/dev/null; then
printf '%s' "$str" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read())[1:-1], end="")'
else
printf '%s' "$str" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g; s/\r/\\r/g' | awk '{printf "%s\\n", $0}' | sed 's/\\n$//'
fi
}
# Helper to output JSON and exit
output_json() {
local status="$1"
local completed="${2:-0}"
local total="${3:-0}"
local failed="${4:-0}"
local percent="${5:-0}"
local eta="${6:-0}"
local avg_time="${7:-0}"
local last_item="${8:-}"
local phase="${9:-}"
local failed_tests="${10:-}"
# Build JSON output
local json="{\"status\":\"$status\""
if [[ -n "$phase" ]]; then
json="$json,\"phase\":\"$phase\""
fi
json="$json,\"completed\":$completed,\"total\":$total,\"failed\":$failed,\"percent\":$percent"
json="$json,\"eta_seconds\":$eta,\"avg_time\":\"$avg_time\",\"last_item\":\"$(json_escape "$last_item")\""
if [[ -n "$failed_tests" ]]; then
json="$json,\"failed_tests\":[$failed_tests]"
fi
json="$json}"
echo "$json"
}
# Get failed test info with log output
get_failed_tests_json() {
local log_file="$1"
local t_dir="$2"
local max_failures=10
local count=0
local first=true
# Get failed tests from LOG file
while IFS=$'\t' read -r seq host starttime runtime send recv exitval signal cmd; do
# Skip header line
[[ "$seq" == "Seq" ]] && continue
# Check if failed (exitval != 0 or signal != 0)
if [[ "$exitval" != "0" || "$signal" != "0" ]]; then
# Extract test name from command
test_name=$(echo "$cmd" | sed 's,.*/run-,,;s, .*,,')
# Get log file path
log_path="$t_dir/log-run-$test_name"
# Read test output (last N lines)
if [[ -f "$log_path" ]]; then
output=$(tail -n "$MAX_OUTPUT_LINES" "$log_path" 2>/dev/null)
else
output="(log file not found: $log_path)"
fi
# Escape output for JSON
escaped_output=$(json_escape "$output")
# Build JSON object for this failure
if [[ "$first" == "true" ]]; then
first=false
else
printf ","
fi
printf '{"test":"%s","exit_code":%d,"signal":%d,"output":"%s"}' \
"$test_name" "$exitval" "$signal" "$escaped_output"
((count++))
if [[ $count -ge $max_failures ]]; then
break
fi
fi
done < "$log_file"
}
# Check if tests are running (LOG file exists)
if [[ -f "$LOG_FILE" ]]; then
# Count total tests from t/run-* files
if [[ -d "$T_DIR" ]]; then
total=$(find "$T_DIR" -name 'run-*' -type f 2>/dev/null | wc -l)
else
total=0
fi
# If no parallel tests generated yet
if [[ "$total" -eq 0 ]]; then
output_json "running" 0 0 0 0 0 "0" "" "generating"
exit 0
fi
# Parse LOG file (skip header line)
# LOG format: Seq Host Starttime JobRuntime Send Receive Exitval Signal Command
completed=$(tail -n +2 "$LOG_FILE" 2>/dev/null | wc -l)
# Count failures
failed=$(awk -F'\t' 'NR>1 && ($7 != 0 || $8 != 0) {count++} END {print count+0}' "$LOG_FILE" 2>/dev/null)
# Get failed tests JSON with output (only if there are failures)
if [[ "$failed" -gt 0 ]]; then
failed_tests=$(get_failed_tests_json "$LOG_FILE" "$T_DIR")
else
failed_tests=""
fi
# Calculate percentage
if [[ "$total" -gt 0 ]]; then
percent=$((completed * 100 / total))
else
percent=0
fi
# Get last completed test name (extract from command column)
last_test=$(tail -1 "$LOG_FILE" 2>/dev/null | awk -F'\t' '{print $9}' | sed 's,.*/run-,,;s, .*,,;s,^./,,')
# Calculate ETA based on average time
if [[ "$completed" -gt 0 ]]; then
avg_time=$(awk -F'\t' 'NR>1 {sum+=$4; count++} END {if(count>0) printf "%.1f", sum/count; else print "0"}' "$LOG_FILE")
remaining=$((total - completed))
eta=$(awk "BEGIN {printf \"%.0f\", $avg_time * $remaining}")
else
avg_time="0"
eta="0"
fi
# Determine status
if [[ "$completed" -ge "$total" ]]; then
status="completed"
elif [[ "$completed" -gt 0 ]]; then
status="running"
else
status="starting"
fi
output_json "$status" "$completed" "$total" "$failed" "$percent" "$eta" "$avg_time" "$last_test" "testing" "$failed_tests"
exit 0
fi
# No LOG file - check if we're in compilation/linking phase
# Count expected source files from src.mk
if [[ -f "$SRC_MK" ]]; then
# Count LIB_SOURCES (library object files to compile)
expected_lib_objects=$(grep -E '\.cc\s*\\?$' "$SRC_MK" | grep -v '^#' | wc -l)
# Count TEST_MAIN_SOURCES (test binaries to link)
expected_test_binaries=$(sed -n '/^TEST_MAIN_SOURCES =/,/^[^ ]/p' "$SRC_MK" | grep -cE '\.cc\s*\\?$' 2>/dev/null || echo 0)
else
expected_lib_objects=0
expected_test_binaries=0
fi
# Check for test generation phase (t/ directory being created)
if [[ -d "$T_DIR" ]]; then
total=$(find "$T_DIR" -name 'run-*' -type f 2>/dev/null | wc -l)
if [[ "$total" -gt 0 ]]; then
output_json "running" 0 "$total" 0 0 0 "0" "" "generating"
exit 0
fi
fi
# Count compiled object files (in subdirectories matching source structure)
# Object files are created as dir/file.o (e.g., cache/cache.o, db/db_impl.o)
compiled_objects=0
if [[ "$expected_lib_objects" -gt 0 ]]; then
# Count .o files in source directories
compiled_objects=$(find cache db env file logging memory memtable monitoring options port table test_util trace_replay util utilities -name '*.o' -type f 2>/dev/null | wc -l)
fi
# Count linked test binaries (test binaries are in current directory with _test suffix)
linked_tests=0
if [[ "$expected_test_binaries" -gt 0 ]]; then
linked_tests=$(find . -maxdepth 1 -name '*_test' -type f -executable 2>/dev/null | wc -l)
fi
# Determine phase based on what exists
if [[ "$compiled_objects" -eq 0 && "$linked_tests" -eq 0 ]]; then
# Nothing compiled yet - not started or just beginning
output_json "not_started" 0 0 0 0 0 "0" ""
exit 0
fi
# Calculate total work units: compiling + linking
total_work=$((expected_lib_objects + expected_test_binaries))
completed_work=$((compiled_objects + linked_tests))
if [[ "$total_work" -gt 0 ]]; then
percent=$((completed_work * 100 / total_work))
else
percent=0
fi
# Determine phase
if [[ "$compiled_objects" -lt "$expected_lib_objects" ]]; then
phase="compiling"
# Get most recently modified .o file as last_item
last_item=$(find cache db env file logging memory memtable monitoring options port table test_util trace_replay util utilities -name '*.o' -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2- | sed 's,^\./,,;s,\.o$,,')
elif [[ "$linked_tests" -lt "$expected_test_binaries" ]]; then
phase="linking"
# Get most recently modified test binary as last_item
last_item=$(find . -maxdepth 1 -name '*_test' -type f -executable -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2- | sed 's,^\./,,')
else
phase="generating"
last_item=""
fi
output_json "running" "$completed_work" "$total_work" 0 "$percent" 0 "0" "$last_item" "$phase"
+16 -14
View File
@@ -1,20 +1,22 @@
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
# The file is generated using update_dependencies.sh.
GCC_BASE=/mnt/gvfs/third-party2/gcc/e9cb2d4550b5a95024125084420342d256b349cd/11.x/centos9-native/3bed279
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/4e46e6967e15412702e51960c69790a78933856f/21/platform010/72a2ff8
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/63c5179edc90fec473e53c1b2f92269c65c39e07/11.x/platform010/5684a5a
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/b4a6248a76a163bcccb1e4751e247712c535846e/2.34/platform010/f259413
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/ef895164499fdfedb9d9b9c85520de10aa8ff9ca/1.1.8/platform010/76ebdda
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/643dbf0136f869562485cfcb2953f5cab60447ef/1.2.8/platform010/76ebdda
GCC_BASE=/mnt/gvfs/third-party2/gcc/62de5a92e5f23c661c3d4b9f322e04eb14e7a5bd/11.x/centos8-native/886b5eb
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/1f6edd1ff15c99c861afc8f3cd69054cd974dd64/15/platform010/72a2ff8
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/fed6e93d87571fb162734c86636119d45a398963/2.34/platform010/f259413
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/31a346126a1f3b64812c362511cb04cc1bd40855/1.1.8/platform010/76ebdda
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/0c65c05468b5a38cef1a106a1f526463e120c8dd/1.2.8/platform010/76ebdda
BZIP2_BASE=/mnt/gvfs/third-party2/bzip2/09703139cfc376bd8a82642385a0e97726b28287/1.0.6/platform010/76ebdda
LZ4_BASE=/mnt/gvfs/third-party2/lz4/823bf8e000654abef784311296ffc8166d9d3986/1.9.4/platform010/76ebdda
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/0cda78647b5712bec7ec6d9ba2f0dcdabfb6f44f/1.4.x/platform010/64091f4
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/a02e0de00945729ad553c187c64e86b57f45a33b/2.2.0/platform010/76ebdda
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/a1a50742bec7195bfafb594e174ea45dc197a420/master/platform010/779a252
LZ4_BASE=/mnt/gvfs/third-party2/lz4/ff23d17b932725cc1734a14896a8b67c518ba169/1.9.4/platform010/76ebdda
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/576397d8b1d9cea7306ad1e454d5e55caaa2ff1c/1.4.x/platform010/64091f4
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/fecac07861cb829f5e60dbeff0503d3272db73c0/2.2.0/platform010/76ebdda
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/0bb3f5756788ce26e2e16a1cb2f2af2c59b51abe/master/platform010/f57cc4a
NUMA_BASE=/mnt/gvfs/third-party2/numa/5b602edd46fda54cdd7ea45f77dbe4061206e174/2.0.11/platform010/76ebdda
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/f3cce2e1a79ac8d64e102886603a6997d6e88640/1.8/platform010/76ebdda
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/97cac22a149c2e202917e05d44e87e516b68216f/1.4/platform010/5074a48
TBB_BASE=/mnt/gvfs/third-party2/tbb/53953ebc4e3eda85ad6fc3e429ba146035e97b90/2018_U5/platform010/76ebdda
LIBURING_BASE=/mnt/gvfs/third-party2/liburing/a98e2d137007e3ebf7f33bd6f99c2c56bdaf8488/20210212/platform010/76ebdda
BENCHMARK_BASE=/mnt/gvfs/third-party2/benchmark/780c7a0f9cf0967961e69ad08e61cddd85d61821/trunk/platform010/76ebdda
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/0883cccda758e68b47e4c04e4fa01142e1f60f32/fb/platform010/da39a3e
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/1d5d19135a406a941d3a441eb2bf506bb9d19210/2.43/centos9-native/be7139e
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/3e2b7ccc315c9a0f2b678ce6fd774f4970f9bf3b/3.22.0/platform010/76ebdda
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/624a2f8f6c93c3c1df8aa4a6255d8202631a6c80/fb/platform010/da39a3e
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/39579e8603b48b3540f8b0633f43adf29acccb8b/2.37/centos8-native/da39a3e
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/cd9cc656d49ecb53797ce4d055e49fde29fd57ff/3.19.0/platform010/76ebdda
LUA_BASE=/mnt/gvfs/third-party2/lua/363787fa5cac2a8aa20638909210443278fa138e/5.3.4/platform010/9079c97
+22 -5
View File
@@ -87,6 +87,15 @@ if test -z $PIC_BUILD; then
LIBUNWIND="$LIBUNWIND_BASE/lib/libunwind.a"
fi
# location of TBB
TBB_INCLUDE=" -isystem $TBB_BASE/include/"
if test -z $PIC_BUILD; then
TBB_LIBS="$TBB_BASE/lib/libtbb.a"
else
TBB_LIBS="$TBB_BASE/lib/libtbb_pic.a"
fi
CFLAGS+=" -DTBB"
test "$USE_SSE" || USE_SSE=1
export USE_SSE
test "$PORTABLE" || PORTABLE=1
@@ -95,7 +104,7 @@ export PORTABLE
BINUTILS="$BINUTILS_BASE/bin"
AR="$BINUTILS/ar"
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE"
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE"
STDLIBS="-L $GCC_BASE/lib64"
@@ -141,18 +150,26 @@ CFLAGS+=" $DEPS_INCLUDE"
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT"
CXXFLAGS+=" $CFLAGS"
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB"
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS"
EXEC_LDFLAGS+=" -B$BINUTILS/gold"
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/gcc-5-glibc-2.23/lib/ld.so"
EXEC_LDFLAGS+=" $LIBUNWIND"
EXEC_LDFLAGS+=" -Wl,-rpath=/usr/local/fbcode/gcc-5-glibc-2.23/lib"
# dynamic loading
# required by libtbb
EXEC_LDFLAGS+=" -ldl"
PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS"
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS"
VALGRIND_VER="$VALGRIND_BASE/bin/"
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD
LUA_PATH="$LUA_BASE"
if test -z $PIC_BUILD; then
LUA_LIB=" $LUA_PATH/lib/liblua.a"
else
LUA_LIB=" $LUA_PATH/lib/liblua_pic.a"
fi
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD LUA_PATH LUA_LIB
+10 -9
View File
@@ -82,6 +82,11 @@ CFLAGS+=" -DNUMA"
# location of libunwind
LIBUNWIND="$LIBUNWIND_BASE/lib/libunwind${MAYBE_PIC}.a"
# location of TBB
TBB_INCLUDE=" -isystem $TBB_BASE/include/"
TBB_LIBS="$TBB_BASE/lib/libtbb${MAYBE_PIC}.a"
CFLAGS+=" -DTBB"
# location of LIBURING
LIBURING_INCLUDE=" -isystem $LIBURING_BASE/include/"
LIBURING_LIBS="$LIBURING_BASE/lib/liburing${MAYBE_PIC}.a"
@@ -96,7 +101,7 @@ BINUTILS="$BINUTILS_BASE/bin"
AR="$BINUTILS/ar"
AS="$BINUTILS/as"
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $LIBURING_INCLUDE $BENCHMARK_INCLUDE"
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE $LIBURING_INCLUDE $BENCHMARK_INCLUDE"
STDLIBS="-L $GCC_BASE/lib64"
@@ -104,10 +109,6 @@ CLANG_BIN="$CLANG_BASE/bin"
CLANG_LIB="$CLANG_BASE/lib"
CLANG_SRC="$CLANG_BASE/../../src"
# A clang++ is always available in the fbcode toolchain regardless of whether
# the build itself uses gcc or clang. CLANG_CXX exposes it for tooling (e.g. the
# C API codegen, which parses C++ ASTs) that needs clang even in a gcc build.
CLANG_CXX="$CLANG_BIN/clang++"
CLANG_ANALYZER="$CLANG_BIN/clang++"
CLANG_SCAN_BUILD="$CLANG_BIN/scan-build"
@@ -156,19 +157,19 @@ CFLAGS+=" $DEPS_INCLUDE"
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_IOURING_PRESENT"
CXXFLAGS+=" $CFLAGS"
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $LIBURING_LIBS $BENCHMARK_LIBS"
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS $LIBURING_LIBS $BENCHMARK_LIBS"
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/platform010/lib/ld.so"
EXEC_LDFLAGS+=" $LIBUNWIND"
EXEC_LDFLAGS+=" -Wl,-rpath=/usr/local/fbcode/platform010/lib"
EXEC_LDFLAGS+=" -Wl,-rpath=$GCC_BASE/lib64"
# dynamic loading
# required by libtbb
EXEC_LDFLAGS+=" -ldl"
PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
PLATFORM_LDFLAGS+=" -B$BINUTILS"
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $LIBURING_LIBS $BENCHMARK_LIBS"
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS $LIBURING_LIBS $BENCHMARK_LIBS"
VALGRIND_VER="$VALGRIND_BASE/bin/"
export CC CXX AR AS CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_CXX CLANG_ANALYZER CLANG_SCAN_BUILD
export CC CXX AR AS CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD LUA_PATH LUA_LIB
+6 -16
View File
@@ -7,18 +7,14 @@ print_usage () {
echo "Usage:"
echo "format-diff.sh [OPTIONS]"
echo "-c: check only."
echo "-y: auto-apply formatting without prompts (non-interactive mode)."
echo "-h: print this message."
}
while getopts ':cyh' OPTION; do
while getopts ':ch' OPTION; do
case "$OPTION" in
c)
CHECK_ONLY=1
;;
y)
AUTO_APPLY=1
;;
h)
print_usage
exit 1
@@ -244,16 +240,11 @@ echo "$diffs" |
sed -e "s/\(^-.*$\)/`echo -e \"$COLOR_RED\1$COLOR_END\"`/" |
sed -e "s/\(^+.*$\)/`echo -e \"$COLOR_GREEN\1$COLOR_END\"`/"
# Handle auto-apply mode (non-interactive)
if [ "$AUTO_APPLY" ]; then
to_fix="y"
else
echo -e "Would you like to fix the format automatically (y/n): \c"
echo -e "Would you like to fix the format automatically (y/n): \c"
# Make sure under any mode, we can read user input.
exec < /dev/tty
read to_fix
fi
# Make sure under any mode, we can read user input.
exec < /dev/tty
read to_fix
if [ "$to_fix" != "y" ]
then
@@ -270,8 +261,7 @@ fi
echo "Files reformatted!"
# Amend to last commit if user do the post-commit format check
# Skip amend prompt in auto-apply mode (user can amend manually if desired)
if [ -z "$uncommitted_code" ] && [ -z "$AUTO_APPLY" ]; then
if [ -z "$uncommitted_code" ]; then
echo -e "Would you like to amend the changes to last commit (`git log HEAD --oneline | head -1`)? (y/n): \c"
read to_amend
-228
View File
@@ -1,228 +0,0 @@
#!/usr/bin/env python3
# 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 the Apache 2.0 License (found in the LICENSE.Apache file in the root directory).
"""
Pre-download packages with unreliable mirrors using fallback mirrors.
Reads package info from folly's getdeps manifest files.
"""
import configparser
import hashlib
import os
import shutil
import sys
import urllib.request
DOWNLOAD_TIMEOUT_SECONDS = 120
DOWNLOAD_CHUNK_BYTES = 64 * 1024
MAX_DOWNLOAD_BYTES = 50 * 1024 * 1024
MIRROR_FALLBACKS = {
"ftpmirror.gnu.org/gnu/": [
"https://mirrors.kernel.org/gnu/",
"https://ftpmirror.gnu.org/gnu/",
"https://ftp.gnu.org/gnu/",
],
"ftp.gnu.org/gnu/": [
"https://mirrors.kernel.org/gnu/",
"https://ftpmirror.gnu.org/gnu/",
"https://ftp.gnu.org/gnu/",
],
}
# These packages must have URLs matching MIRROR_FALLBACKS; other packages are
# left for getdeps.py's normal download path.
PACKAGES_TO_CHECK = ("autoconf", "automake", "libtool", "libiberty")
def sha256_file(path):
"""Calculate SHA256 hash of a file."""
h = hashlib.sha256()
try:
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
h.update(chunk)
return h.hexdigest()
except Exception:
return None
def parse_manifest(manifest_path):
"""Parse a getdeps manifest file to extract download info."""
# folly manifests can contain bare keys in sections unrelated to downloads.
config = configparser.ConfigParser(allow_no_value=True, interpolation=None)
try:
with open(manifest_path, encoding="utf-8") as manifest_file:
config.read_file(manifest_file)
except Exception as ex:
print(f" {os.path.basename(manifest_path)}: WARNING - parse failed: {ex}")
return None
if "download" in config:
return {
"url": config["download"].get("url", ""),
"sha256": config["download"].get("sha256", ""),
}
return None
def file_size(path):
try:
return os.path.getsize(path)
except Exception:
return None
def get_fallback_mirrors(url):
"""Get fallback mirror URLs for a given URL."""
for pattern, mirrors in MIRROR_FALLBACKS.items():
if pattern in url:
# Extract the path after the pattern
path_start = url.find(pattern) + len(pattern)
path = url[path_start:]
return [mirror + path for mirror in mirrors]
return []
def download_url(url, filepath):
"""Download URL to filepath without leaving partial files behind."""
tmp_filepath = filepath + ".tmp"
if os.path.exists(tmp_filepath):
os.remove(tmp_filepath)
request = urllib.request.Request(
url, headers={"User-Agent": "rocksdb-getdeps-fallback/1.0"}
)
try:
with urllib.request.urlopen(
request, timeout=DOWNLOAD_TIMEOUT_SECONDS
) as response, open(tmp_filepath, "wb") as output:
copied = 0
while True:
chunk = response.read(DOWNLOAD_CHUNK_BYTES)
if not chunk:
break
copied += len(chunk)
if copied > MAX_DOWNLOAD_BYTES:
raise Exception(
f"download exceeds {MAX_DOWNLOAD_BYTES} bytes"
)
output.write(chunk)
os.replace(tmp_filepath, filepath)
finally:
if os.path.exists(tmp_filepath):
os.remove(tmp_filepath)
def prepare_download(package, info, download_dir, cache_dir):
url = info["url"]
expected_sha256 = info["sha256"]
mirrors = get_fallback_mirrors(url)
if not mirrors:
return False
if not expected_sha256:
print(f" {package}: WARNING - skipped fallback without sha256")
return False
# getdeps uses format: {package}-{filename}
filename = f"{package}-{os.path.basename(url)}"
filepath = os.path.join(download_dir, filename)
cache_path = os.path.join(cache_dir, filename)
# Check if already valid.
actual_sha256 = sha256_file(filepath) if os.path.exists(filepath) else None
if actual_sha256 == expected_sha256:
print(f" {filename}: OK (already downloaded)")
return True
if actual_sha256 is not None:
print(
f" {filename}: WARNING - removing invalid download "
f"sha256={actual_sha256}"
)
os.remove(filepath)
# The cache is only an opportunistic single-build accelerator; callers
# should not share it across concurrent builds without external locking.
actual_sha256 = sha256_file(cache_path) if os.path.exists(cache_path) else None
if actual_sha256 == expected_sha256:
print(f" {filename}: OK (from cache)")
shutil.copy2(cache_path, filepath)
return True
if actual_sha256 is not None:
print(
f" {filename}: WARNING - removing invalid cache "
f"sha256={actual_sha256}"
)
os.remove(cache_path)
# Try fallback mirrors.
for mirror_url in mirrors:
print(f" {filename}: trying {mirror_url}...")
try:
download_url(mirror_url, filepath)
except Exception as ex:
print(f" {filename}: WARNING - download failed: {ex}")
continue
actual_sha256 = sha256_file(filepath)
if actual_sha256 == expected_sha256:
size = file_size(filepath)
print(f" {filename}: OK (downloaded, {size} bytes)")
shutil.copy2(filepath, cache_path)
return True
size = file_size(filepath)
print(
f" {filename}: WARNING - sha256 mismatch from {mirror_url}: "
f"expected={expected_sha256} actual={actual_sha256} size={size}"
)
os.remove(filepath)
print(f" {filename}: WARNING - all mirrors failed")
return False
def main():
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} <download_dir> <cache_dir> <manifests_dir>")
sys.exit(1)
download_dir, cache_dir, manifests_dir = sys.argv[1], sys.argv[2], sys.argv[3]
os.makedirs(download_dir, exist_ok=True)
os.makedirs(cache_dir, exist_ok=True)
checked = 0
ready = 0
for package in PACKAGES_TO_CHECK:
manifest_path = os.path.join(manifests_dir, package)
if not os.path.isfile(manifest_path):
continue
info = parse_manifest(manifest_path)
if not info or not info["url"]:
continue
if not info["sha256"]:
print(f" {package}: WARNING - skipped fallback without sha256")
continue
if not get_fallback_mirrors(info["url"]):
print(
f" {package}: WARNING - skipped fallback without known mirror "
f"for {info['url']}"
)
continue
checked += 1
try:
if prepare_download(package, info, download_dir, cache_dir):
ready += 1
except Exception as ex:
print(f" {package}: WARNING - fallback preparation failed: {ex}")
print(f" fallback mirror downloads ready: {ready}/{checked}")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -1913,7 +1913,7 @@ sub drain_job_queue {
}
$last_progress_time = time();
$ps_reported = 0;
} elsif (not $ps_reported and (time() - $last_progress_time) >= 300) {
} elsif (not $ps_reported and (time() - $last_progress_time) >= 60) {
# No progress in at least 60 seconds: run ps
print $Global::original_stderr "\n";
my $script_dir = ::dirname($0);
-18
View File
@@ -1,18 +0,0 @@
#!/usr/bin/env python3
# Copyright 2017 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import gtest_parallel
import sys
sys.exit(gtest_parallel.main())
-959
View File
@@ -1,959 +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 the Apache 2.0 License (found in the LICENSE.Apache file in the root directory).
# Copyright 2013 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import errno
from functools import total_ordering
import gzip
import io
import json
import multiprocessing
import optparse
import os
import re
import shutil
import signal
import subprocess
import sys
import tempfile
import threading
import time
if sys.version_info.major >= 3:
long = int
import _pickle as cPickle
import _thread as thread
else:
import cPickle
import thread
from pickle import HIGHEST_PROTOCOL as PICKLE_HIGHEST_PROTOCOL
if sys.platform == 'win32':
import msvcrt
else:
import fcntl
# An object that catches SIGINT sent to the Python process and notices
# if processes passed to wait() die by SIGINT (we need to look for
# both of those cases, because pressing Ctrl+C can result in either
# the main process or one of the subprocesses getting the signal).
#
# Before a SIGINT is seen, wait(p) will simply call p.wait() and
# return the result. Once a SIGINT has been seen (in the main process
# or a subprocess, including the one the current call is waiting for),
# wait(p) will call p.terminate() and raise ProcessWasInterrupted.
class SigintHandler(object):
class ProcessWasInterrupted(Exception):
pass
sigint_returncodes = {
-signal.SIGINT, # Unix
-1073741510, # Windows
}
def __init__(self):
self.__lock = threading.Lock()
self.__processes = set()
self.__got_sigint = False
signal.signal(signal.SIGINT, lambda signal_num, frame: self.interrupt())
def __on_sigint(self):
self.__got_sigint = True
while self.__processes:
try:
self.__processes.pop().terminate()
except OSError:
pass
def interrupt(self):
with self.__lock:
self.__on_sigint()
def got_sigint(self):
with self.__lock:
return self.__got_sigint
def wait(self, p, timeout_per_test):
with self.__lock:
if self.__got_sigint:
p.terminate()
self.__processes.add(p)
try:
code = p.wait(timeout_per_test)
except subprocess.TimeoutExpired :
p.terminate()
self.__processes.remove(p)
code = -errno.ETIME
with self.__lock:
self.__processes.discard(p)
if code in self.sigint_returncodes:
self.__on_sigint()
if self.__got_sigint:
raise self.ProcessWasInterrupted
return code
sigint_handler = SigintHandler()
# Return the width of the terminal, or None if it couldn't be
# determined (e.g. because we're not being run interactively).
def term_width(out):
if not out.isatty():
return None
try:
p = subprocess.Popen(["stty", "size"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, err) = p.communicate()
if p.returncode != 0 or err:
return None
return int(out.split()[1])
except (IndexError, OSError, ValueError):
return None
# Output transient and permanent lines of text. If several transient
# lines are written in sequence, the new will overwrite the old. We
# use this to ensure that lots of unimportant info (tests passing)
# won't drown out important info (tests failing).
class Outputter(object):
def __init__(self, out_file):
self.__out_file = out_file
self.__previous_line_was_transient = False
self.__width = term_width(out_file) # Line width, or None if not a tty.
def transient_line(self, msg):
if self.__width is None:
self.__out_file.write(msg + "\n")
self.__out_file.flush()
else:
self.__out_file.write("\r" + msg[:self.__width].ljust(self.__width))
self.__previous_line_was_transient = True
def flush_transient_output(self):
if self.__previous_line_was_transient:
self.__out_file.write("\n")
self.__previous_line_was_transient = False
def permanent_line(self, msg):
self.flush_transient_output()
self.__out_file.write(msg + "\n")
if self.__width is None:
self.__out_file.flush()
def get_save_file_path():
"""Return path to file for saving transient data."""
if sys.platform == 'win32':
default_cache_path = os.path.join(os.path.expanduser('~'), 'AppData',
'Local')
cache_path = os.environ.get('LOCALAPPDATA', default_cache_path)
else:
# We don't use xdg module since it's not a standard.
default_cache_path = os.path.join(os.path.expanduser('~'), '.cache')
cache_path = os.environ.get('XDG_CACHE_HOME', default_cache_path)
if os.path.isdir(cache_path):
return os.path.join(cache_path, 'gtest-parallel')
else:
sys.stderr.write('Directory {} does not exist'.format(cache_path))
return os.path.join(os.path.expanduser('~'), '.gtest-parallel-times')
@total_ordering
class Task(object):
"""Stores information about a task (single execution of a test).
This class stores information about the test to be executed (gtest binary and
test name), and its result (log file, exit code and runtime).
Each task is uniquely identified by the gtest binary, the test name and an
execution number that increases each time the test is executed.
Additionaly we store the last execution time, so that next time the test is
executed, the slowest tests are run first.
"""
def __init__(self, test_binary, test_name, test_command, execution_number,
last_execution_time, output_dir):
self.test_name = test_name
self.output_dir = output_dir
self.test_binary = test_binary
self.test_command = test_command
self.execution_number = execution_number
self.last_execution_time = last_execution_time
self.exit_code = None
self.runtime_ms = None
self.test_id = (test_binary, test_name)
self.task_id = (test_binary, test_name, self.execution_number)
self.log_file = Task._logname(self.output_dir, self.test_binary, test_name,
self.execution_number)
def __sorting_key(self):
# Unseen or failing tests (both missing execution time) take precedence over
# execution time. Tests are greater (seen as slower) when missing times so
# that they are executed first.
return (1 if self.last_execution_time is None else 0,
self.last_execution_time)
def __eq__(self, other):
return self.__sorting_key() == other.__sorting_key()
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
return self.__sorting_key() < other.__sorting_key()
@staticmethod
def _normalize(string):
return re.sub('[^A-Za-z0-9]', '_', string)
@staticmethod
def _logname(output_dir, test_binary, test_name, execution_number):
# Store logs to temporary files if there is no output_dir.
if output_dir is None:
(log_handle, log_name) = tempfile.mkstemp(prefix='gtest_parallel_',
suffix=".log")
os.close(log_handle)
return log_name
log_name = '%s-%s-%d.log' % (Task._normalize(os.path.basename(test_binary)),
Task._normalize(test_name), execution_number)
return os.path.join(output_dir, log_name)
def run(self, timeout_per_test):
begin = time.time()
with open(self.log_file, 'w') as log:
task = subprocess.Popen(self.test_command, stdout=log, stderr=log)
try:
self.exit_code = sigint_handler.wait(task, timeout_per_test)
except sigint_handler.ProcessWasInterrupted:
thread.exit()
self.runtime_ms = int(1000 * (time.time() - begin))
self.last_execution_time = None if self.exit_code else self.runtime_ms
class TaskManager(object):
"""Executes the tasks and stores the passed, failed and interrupted tasks.
When a task is run, this class keeps track if it passed, failed or was
interrupted. After a task finishes it calls the relevant functions of the
Logger, TestResults and TestTimes classes, and in case of failure, retries the
test as specified by the --retry_failed flag.
"""
def __init__(self, times, logger, test_results, task_factory, times_to_retry,
initial_execution_number):
self.times = times
self.logger = logger
self.test_results = test_results
self.task_factory = task_factory
self.times_to_retry = times_to_retry
self.initial_execution_number = initial_execution_number
self.global_exit_code = 0
self.passed = []
self.failed = []
self.started = {}
self.timed_out = []
self.execution_number = {}
self.lock = threading.Lock()
def __get_next_execution_number(self, test_id):
with self.lock:
next_execution_number = self.execution_number.setdefault(
test_id, self.initial_execution_number)
self.execution_number[test_id] += 1
return next_execution_number
def __register_start(self, task):
with self.lock:
self.started[task.task_id] = task
def register_exit(self, task):
self.logger.log_exit(task)
self.times.record_test_time(task.test_binary, task.test_name,
task.last_execution_time)
if self.test_results:
self.test_results.log(task.test_name, task.runtime_ms / 1000.0,
task.exit_code)
with self.lock:
self.started.pop(task.task_id)
if task.exit_code == 0:
self.passed.append(task)
elif task.exit_code == -errno.ETIME:
self.timed_out.append(task)
else:
self.failed.append(task)
def run_task(self, task, timeout_per_test):
for try_number in range(self.times_to_retry + 1):
self.__register_start(task)
task.run(timeout_per_test)
self.register_exit(task)
if task.exit_code == 0:
break
if try_number < self.times_to_retry:
execution_number = self.__get_next_execution_number(task.test_id)
# We need create a new Task instance. Each task represents a single test
# execution, with its own runtime, exit code and log file.
task = self.task_factory(task.test_binary, task.test_name,
task.test_command, execution_number,
task.last_execution_time, task.output_dir)
with self.lock:
if task.exit_code != 0:
self.global_exit_code = task.exit_code
class FilterFormat(object):
def __init__(self, output_dir):
if sys.stdout.isatty():
# stdout needs to be unbuffered since the output is interactive.
if isinstance(sys.stdout, io.TextIOWrapper):
# workaround for https://bugs.python.org/issue17404
sys.stdout = io.TextIOWrapper(sys.stdout.detach(),
line_buffering=True,
write_through=True,
newline='\n')
else:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
self.output_dir = output_dir
self.total_tasks = 0
self.finished_tasks = 0
self.out = Outputter(sys.stdout)
self.stdout_lock = threading.Lock()
def move_to(self, destination_dir, tasks):
if self.output_dir is None:
return
destination_dir = os.path.join(self.output_dir, destination_dir)
os.makedirs(destination_dir)
for task in tasks:
shutil.move(task.log_file, destination_dir)
def print_tests(self, message, tasks, print_try_number, print_test_command):
self.out.permanent_line("%s (%s/%s):" %
(message, len(tasks), self.total_tasks))
for task in sorted(tasks):
runtime_ms = 'Interrupted'
if task.runtime_ms is not None:
runtime_ms = '%d ms' % task.runtime_ms
if print_test_command:
try:
cmd_str = " ".join(task.test_command)
except TypeError:
cmd_str = task.test_command
self.out.permanent_line(
"%11s: %s%s" %
(runtime_ms, cmd_str,
(" (try #%d)" % task.execution_number) if print_try_number else ""))
else:
self.out.permanent_line(
"%11s: %s %s%s" %
(runtime_ms, task.test_binary, task.test_name,
(" (try #%d)" % task.execution_number) if print_try_number else ""))
def log_exit(self, task):
with self.stdout_lock:
self.finished_tasks += 1
self.out.transient_line("[%d/%d] %s (%d ms)" %
(self.finished_tasks, self.total_tasks,
task.test_name, task.runtime_ms))
if task.exit_code != 0:
signal_name = None
if task.exit_code < 0:
try:
signal_name = signal.Signals(-task.exit_code).name
except ValueError:
pass
with open(task.log_file) as f:
for line in f.readlines():
self.out.permanent_line(line.rstrip())
if task.exit_code is None:
self.out.permanent_line("[%d/%d] %s aborted after %d ms" %
(self.finished_tasks, self.total_tasks,
task.test_name, task.runtime_ms))
elif task.exit_code == -errno.ETIME:
self.out.permanent_line(
"\033[31m[ TIMEOUT ]\033[0m %s timed out after %d s"
% (task.test_name, task.runtime_ms/1000))
elif signal_name is not None:
self.out.permanent_line(
"[%d/%d] %s killed by signal %s (%d ms)" %
(self.finished_tasks, self.total_tasks, task.test_name,
signal_name, task.runtime_ms))
else:
self.out.permanent_line(
"[%d/%d] %s returned with exit code %d (%d ms)" %
(self.finished_tasks, self.total_tasks, task.test_name,
task.exit_code, task.runtime_ms))
if self.output_dir is None:
# Try to remove the file 100 times (sleeping for 0.1 second in between).
# This is a workaround for a process handle seemingly holding on to the
# file for too long inside os.subprocess. This workaround is in place
# until we figure out a minimal repro to report upstream (or a better
# suspect) to prevent os.remove exceptions.
num_tries = 100
for i in range(num_tries):
try:
os.remove(task.log_file)
except OSError as e:
if e.errno is not errno.ENOENT:
if i is num_tries - 1:
self.out.permanent_line('Could not remove temporary log file: ' +
str(e))
else:
time.sleep(0.1)
continue
break
def log_tasks(self, total_tasks):
self.total_tasks += total_tasks
self.out.transient_line("[0/%d] Running tests..." % self.total_tasks)
def summarize(self, passed_tasks, failed_tasks, interrupted_tasks):
stats = {}
def add_stats(stats, task, idx):
task_key = (task.test_binary, task.test_name)
if not task_key in stats:
# (passed, failed, interrupted) task_key is added as tie breaker to get
# alphabetic sorting on equally-stable tests
stats[task_key] = [0, 0, 0, task_key]
stats[task_key][idx] += 1
for task in passed_tasks:
add_stats(stats, task, 0)
for task in failed_tasks:
add_stats(stats, task, 1)
for task in interrupted_tasks:
add_stats(stats, task, 2)
self.out.permanent_line("SUMMARY:")
for task_key in sorted(stats, key=stats.__getitem__):
(num_passed, num_failed, num_interrupted, _) = stats[task_key]
(test_binary, task_name) = task_key
total_runs = num_passed + num_failed + num_interrupted
if num_passed == total_runs:
continue
self.out.permanent_line(" %s %s passed %d / %d times%s." %
(test_binary, task_name, num_passed, total_runs,
"" if num_interrupted == 0 else
(" (%d interrupted)" % num_interrupted)))
def flush(self):
self.out.flush_transient_output()
class CollectTestResults(object):
def __init__(self, json_dump_filepath):
self.test_results_lock = threading.Lock()
self.json_dump_file = open(json_dump_filepath, 'w')
self.test_results = {
"interrupted": False,
"path_delimiter": ".",
# Third version of the file format. See the link in the flag description
# for details.
"version": 3,
"seconds_since_epoch": int(time.time()),
"num_failures_by_type": {
"PASS": 0,
"FAIL": 0,
"TIMEOUT": 0,
},
"tests": {},
}
def log(self, test, runtime_seconds, exit_code):
if exit_code is None:
actual_result = "TIMEOUT"
elif exit_code == 0:
actual_result = "PASS"
else:
actual_result = "FAIL"
with self.test_results_lock:
self.test_results['num_failures_by_type'][actual_result] += 1
results = self.test_results['tests']
for name in test.split('.'):
results = results.setdefault(name, {})
if results:
results['actual'] += ' ' + actual_result
results['times'].append(runtime_seconds)
else: # This is the first invocation of the test
results['actual'] = actual_result
results['times'] = [runtime_seconds]
results['time'] = runtime_seconds
results['expected'] = 'PASS'
def dump_to_file_and_close(self):
json.dump(self.test_results, self.json_dump_file)
self.json_dump_file.close()
# Record of test runtimes. Has built-in locking.
class TestTimes(object):
class LockedFile(object):
def __init__(self, filename, mode):
self._filename = filename
self._mode = mode
self._fo = None
def __enter__(self):
self._fo = open(self._filename, self._mode)
# Regardless of opening mode we always seek to the beginning of file.
# This simplifies code working with LockedFile and also ensures that
# we lock (and unlock below) always the same region in file on win32.
self._fo.seek(0)
try:
if sys.platform == 'win32':
# We are locking here fixed location in file to use it as
# an exclusive lock on entire file.
msvcrt.locking(self._fo.fileno(), msvcrt.LK_LOCK, 1)
else:
fcntl.flock(self._fo.fileno(), fcntl.LOCK_EX)
except IOError:
self._fo.close()
raise
return self._fo
def __exit__(self, exc_type, exc_value, traceback):
# Flush any buffered data to disk. This is needed to prevent race
# condition which happens from the moment of releasing file lock
# till closing the file.
self._fo.flush()
try:
if sys.platform == 'win32':
self._fo.seek(0)
msvcrt.locking(self._fo.fileno(), msvcrt.LK_UNLCK, 1)
else:
fcntl.flock(self._fo.fileno(), fcntl.LOCK_UN)
finally:
self._fo.close()
return exc_value is None
def __init__(self, save_file):
"Create new object seeded with saved test times from the given file."
self.__times = {} # (test binary, test name) -> runtime in ms
# Protects calls to record_test_time(); other calls are not
# expected to be made concurrently.
self.__lock = threading.Lock()
try:
with TestTimes.LockedFile(save_file, 'rb') as fd:
times = TestTimes.__read_test_times_file(fd)
except IOError:
# We couldn't obtain the lock.
return
# Discard saved times if the format isn't right.
if type(times) is not dict:
return
for ((test_binary, test_name), runtime) in times.items():
if (type(test_binary) is not str or type(test_name) is not str
or type(runtime) not in {int, long, type(None)}):
return
self.__times = times
def get_test_time(self, binary, testname):
"""Return the last duration for the given test as an integer number of
milliseconds, or None if the test failed or if there's no record for it."""
return self.__times.get((binary, testname), None)
def record_test_time(self, binary, testname, runtime_ms):
"""Record that the given test ran in the specified number of
milliseconds. If the test failed, runtime_ms should be None."""
with self.__lock:
self.__times[(binary, testname)] = runtime_ms
def write_to_file(self, save_file):
"Write all the times to file."
try:
with TestTimes.LockedFile(save_file, 'a+b') as fd:
times = TestTimes.__read_test_times_file(fd)
if times is None:
times = self.__times
else:
times.update(self.__times)
# We erase data from file while still holding a lock to it. This
# way reading old test times and appending new ones are atomic
# for external viewer.
fd.seek(0)
fd.truncate()
with gzip.GzipFile(fileobj=fd, mode='wb') as gzf:
cPickle.dump(times, gzf, PICKLE_HIGHEST_PROTOCOL)
except IOError:
pass # ignore errors---saving the times isn't that important
@staticmethod
def __read_test_times_file(fd):
try:
with gzip.GzipFile(fileobj=fd, mode='rb') as gzf:
times = cPickle.load(gzf)
except Exception:
# File doesn't exist, isn't readable, is malformed---whatever.
# Just ignore it.
return None
else:
return times
def find_tests(binaries, additional_args, options, times):
test_count = 0
tasks = []
for test_binary in binaries:
command = [test_binary] + additional_args
if options.gtest_also_run_disabled_tests:
command += ['--gtest_also_run_disabled_tests']
list_command = command + ['--gtest_list_tests']
if options.gtest_filter != '':
list_command += ['--gtest_filter=' + options.gtest_filter]
try:
test_list = subprocess.check_output(list_command,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
sys.exit("%s: %s\n%s" % (test_binary, str(e), e.output))
try:
test_list = test_list.split('\n')
except TypeError:
# subprocess.check_output() returns bytes in python3
test_list = test_list.decode(sys.stdout.encoding).split('\n')
command += ['--gtest_color=' + options.gtest_color]
test_group = ''
for line in test_list:
if not line.strip():
continue
if line[0] != " ":
# Remove comments for typed tests and strip whitespace.
test_group = line.split('#')[0].strip()
continue
# Remove comments for parameterized tests and strip whitespace.
line = line.split('#')[0].strip()
if not line:
continue
test_name = test_group + line
if not options.gtest_also_run_disabled_tests and 'DISABLED_' in test_name:
continue
# Skip PRE_ tests which are used by Chromium.
if '.PRE_' in test_name:
continue
last_execution_time = times.get_test_time(test_binary, test_name)
if options.failed and last_execution_time is not None:
continue
test_command = command + ['--gtest_filter=' + test_name]
if (test_count - options.shard_index) % options.shard_count == 0:
for execution_number in range(options.repeat):
tasks.append(
Task(test_binary, test_name, test_command, execution_number + 1,
last_execution_time, options.output_dir))
test_count += 1
# Sort the tasks to run the slowest tests first, so that faster ones can be
# finished in parallel.
return sorted(tasks, reverse=True)
def execute_tasks(tasks, pool_size, task_manager, timeout_seconds,
timeout_per_test, serialize_test_cases):
class WorkerFn(object):
def __init__(self, tasks, running_groups, timeout_per_test):
self.tasks = tasks
self.running_groups = running_groups
self.timeout_per_test = timeout_per_test
self.task_lock = threading.Lock()
def __call__(self):
while True:
with self.task_lock:
for task_id in range(len(self.tasks)):
task = self.tasks[task_id]
if self.running_groups is not None:
test_group = task.test_name.split('.')[0]
if test_group in self.running_groups:
# Try to find other non-running test group.
continue
else:
self.running_groups.add(test_group)
del self.tasks[task_id]
break
else:
# Either there is no tasks left or number or remaining test
# cases (groups) is less than number or running threads.
return
task_manager.run_task(task, self.timeout_per_test)
if self.running_groups is not None:
with self.task_lock:
self.running_groups.remove(test_group)
def start_daemon(func):
t = threading.Thread(target=func)
t.daemon = True
t.start()
return t
timeout = None
try:
if timeout_seconds:
timeout = threading.Timer(timeout_seconds, sigint_handler.interrupt)
timeout.start()
running_groups = set() if serialize_test_cases else None
worker_fn = WorkerFn(tasks, running_groups, timeout_per_test)
workers = [start_daemon(worker_fn) for _ in range(pool_size)]
for worker in workers:
worker.join()
finally:
if timeout:
timeout.cancel()
for task in list(task_manager.started.values()):
task.runtime_ms = timeout_seconds * 1000
task_manager.register_exit(task)
def default_options_parser():
parser = optparse.OptionParser(
usage='usage: %prog [options] binary [binary ...] -- [additional args]')
parser.add_option('-d',
'--output_dir',
type='string',
default=None,
help='Output directory for test logs. Logs will be '
'available under gtest-parallel-logs/, so '
'--output_dir=/tmp will results in all logs being '
'available under /tmp/gtest-parallel-logs/.')
parser.add_option('-r',
'--repeat',
type='int',
default=1,
help='Number of times to execute all the tests.')
parser.add_option('--retry_failed',
type='int',
default=0,
help='Number of times to repeat failed tests.')
parser.add_option('--failed',
action='store_true',
default=False,
help='run only failed and new tests')
parser.add_option('-w',
'--workers',
type='int',
default=multiprocessing.cpu_count(),
help='number of workers to spawn')
parser.add_option('--gtest_color',
type='string',
default='yes',
help='color output')
parser.add_option('--gtest_filter',
type='string',
default='',
help='test filter')
parser.add_option('--gtest_also_run_disabled_tests',
action='store_true',
default=False,
help='run disabled tests too')
parser.add_option(
'--print_test_times',
action='store_true',
default=False,
help='list the run time of each test at the end of execution')
parser.add_option(
'--print_test_command',
action='store_true',
default=False,
help='Print full test command instead of name')
parser.add_option('--shard_count',
type='int',
default=1,
help='total number of shards (for sharding test execution '
'between multiple machines)')
parser.add_option('--shard_index',
type='int',
default=0,
help='zero-indexed number identifying this shard (for '
'sharding test execution between multiple machines)')
parser.add_option(
'--dump_json_test_results',
type='string',
default=None,
help='Saves the results of the tests as a JSON machine-'
'readable file. The format of the file is specified at '
'https://www.chromium.org/developers/the-json-test-results-format')
parser.add_option('--timeout',
type='int',
default=None,
help='Interrupt all remaining processes after the given '
'time (in seconds).')
parser.add_option('--timeout_per_test',
type='int',
default=None,
help='Interrupt single processes after the given '
'time (in seconds).')
parser.add_option('--serialize_test_cases',
action='store_true',
default=False,
help='Do not run tests from the same test '
'case in parallel.')
return parser
def main():
# Remove additional arguments (anything after --).
additional_args = []
for i in range(len(sys.argv)):
if sys.argv[i] == '--':
additional_args = sys.argv[i + 1:]
sys.argv = sys.argv[:i]
break
parser = default_options_parser()
(options, binaries) = parser.parse_args()
if (options.output_dir is not None and not os.path.isdir(options.output_dir)):
parser.error('--output_dir value must be an existing directory, '
'current value is "%s"' % options.output_dir)
# Append gtest-parallel-logs to log output, this is to avoid deleting user
# data if an user passes a directory where files are already present. If a
# user specifies --output_dir=Docs/, we'll create Docs/gtest-parallel-logs
# and clean that directory out on startup, instead of nuking Docs/.
if options.output_dir:
options.output_dir = os.path.join(options.output_dir, 'gtest-parallel-logs')
if binaries == []:
parser.print_usage()
sys.exit(1)
if options.shard_count < 1:
parser.error("Invalid number of shards: %d. Must be at least 1." %
options.shard_count)
if not (0 <= options.shard_index < options.shard_count):
parser.error("Invalid shard index: %d. Must be between 0 and %d "
"(less than the number of shards)." %
(options.shard_index, options.shard_count - 1))
# Check that all test binaries have an unique basename. That way we can ensure
# the logs are saved to unique files even when two different binaries have
# common tests.
unique_binaries = set(os.path.basename(binary) for binary in binaries)
assert len(unique_binaries) == len(binaries), (
"All test binaries must have an unique basename.")
if options.output_dir:
# Remove files from old test runs.
if os.path.isdir(options.output_dir):
shutil.rmtree(options.output_dir)
# Create directory for test log output.
try:
os.makedirs(options.output_dir)
except OSError as e:
# Ignore errors if this directory already exists.
if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir):
raise e
test_results = None
if options.dump_json_test_results is not None:
test_results = CollectTestResults(options.dump_json_test_results)
save_file = get_save_file_path()
times = TestTimes(save_file)
logger = FilterFormat(options.output_dir)
task_manager = TaskManager(times, logger, test_results, Task,
options.retry_failed, options.repeat + 1)
tasks = find_tests(binaries, additional_args, options, times)
logger.log_tasks(len(tasks))
execute_tasks(tasks, options.workers, task_manager, options.timeout,
options.timeout_per_test, options.serialize_test_cases)
print_try_number = options.retry_failed > 0 or options.repeat > 1
if task_manager.passed:
logger.move_to('passed', task_manager.passed)
if options.print_test_times:
logger.print_tests('PASSED TESTS', task_manager.passed, print_try_number, options.print_test_command)
if task_manager.failed:
logger.print_tests('FAILED TESTS', task_manager.failed, print_try_number, options.print_test_command)
logger.move_to('failed', task_manager.failed)
if task_manager.timed_out:
logger.print_tests('TIMED OUT TESTS', task_manager.timed_out, print_try_number, options.print_test_command)
logger.move_to('timed_out', task_manager.timed_out)
if task_manager.started:
logger.print_tests('INTERRUPTED TESTS', task_manager.started.values(),
print_try_number, options.print_test_command)
logger.move_to('interrupted', task_manager.started.values())
if options.repeat > 1 and (task_manager.failed or task_manager.started):
logger.summarize(task_manager.passed, task_manager.failed,
task_manager.started.values())
logger.flush()
times.write_to_file(save_file)
if test_results:
test_results.dump_to_file_and_close()
if sigint_handler.got_sigint():
return -signal.SIGINT
return task_manager.global_exit_code
if __name__ == "__main__":
sys.exit(main())
-67
View File
@@ -1,67 +0,0 @@
#!/usr/bin/env bash
# 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).
#
# Build RocksDB unit test binaries and run them under gtest-parallel,
# which shards the test cases across CPUs for faster execution.
#
# Hardened version of a simple `make <bin> && gtest-parallel ./<bin>` helper:
# * AUTO_CLEAN=1 so the Makefile automatically runs a clean when the build
# parameters (DEBUG_LEVEL, sanitizers, ASSERT_STATUS_CHECKED, RTTI, etc.)
# have changed since the last build, preventing stale/mixed object files.
# * Parallel build with -j<NCORES>, computed the same way the Makefile does.
# * Uses the gtest-parallel checked in alongside this script (build_tools/),
# so it works regardless of PATH.
# * `set -euo pipefail` so any failure stops the script.
#
# Run from the repository root.
#
# Accepts one or more test binaries (gtest-parallel pools all their test cases
# into one shared worker queue). The leading non-option arguments are treated as
# binaries; everything from the first option onward is forwarded to
# gtest-parallel / the test binaries.
#
# Example usage:
# build_tools/rocksptest.sh db_test
# build_tools/rocksptest.sh db_test -r1000 --gtest_filter=*MixedSlowdown*
# build_tools/rocksptest.sh db_test env_test db_basic_test
# build_tools/rocksptest.sh db_test env_test --gtest_filter=*Foo*
set -euo pipefail
if [ "$#" -lt 1 ]; then
echo "usage: $0 <test_binary> [more_test_binaries...] [gtest-parallel/test args...]" >&2
echo "example: $0 db_test env_test -r1000 --gtest_filter=*MixedSlowdown*" >&2
exit 1
fi
# First argument must be a test binary, not an option (catches a forgotten name).
if [ "${1#-}" != "$1" ]; then
echo "$0: first argument must be a test binary name, not an option ('$1')" >&2
exit 1
fi
# Collect the leading non-option arguments as test binaries; everything from the
# first option onward is forwarded to gtest-parallel / the test binaries.
BINS=()
while [ "$#" -gt 0 ] && [ "${1#-}" = "$1" ]; do
BINS+=("$1")
shift
done
# Paths as gtest-parallel expects them (relative to the current directory).
BIN_PATHS=()
for b in "${BINS[@]}"; do
BIN_PATHS+=("./$b")
done
# Directory of this script, so we use the gtest-parallel checked in next to it.
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# Compute parallelism the same way the Makefile computes NCORES.
NCORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
make AUTO_CLEAN=1 -j"$NCORES" "${BINS[@]}"
"$SCRIPT_DIR/gtest-parallel" "${BIN_PATHS[@]}" "$@"
-76
View File
@@ -1,76 +0,0 @@
#!/usr/bin/env bash
# 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).
#
# Build a single RocksDB unit test binary and run it directly (serially).
# Only recommended with --gtest_filter=... because of speed. See also
# build_tools/rocksptest.sh
#
# Hardened version of a simple `make <bin> && ./<bin>` helper:
# * AUTO_CLEAN=1 so the Makefile automatically runs a clean when the build
# parameters (DEBUG_LEVEL, sanitizers, ASSERT_STATUS_CHECKED, RTTI, etc.)
# have changed since the last build, preventing stale/mixed object files.
# * Parallel build with -j<NCORES>, computed the same way the Makefile does.
# * `set -euo pipefail` so any failure stops the script.
#
# Run from the repository root.
#
# Example usage:
# build_tools/rockstest.sh db_test --gtest_filter=*MixedSlowdown*
# build_tools/rockstest.sh env_test # Slow to run many tests serially
#
# Install mode:
# build_tools/rockstest.sh install
# Creates ~/bin/rockstest and ~/bin/rocksptest shims that defer to
# build_tools/rockstest.sh / rocksptest.sh in whatever directory you run
# them from, so you can just type `rockstest db_test` from any rocksdb
# source root.
set -euo pipefail
# Install mode: write thin ~/bin shims that defer to the build_tools scripts in
# the current directory.
if [ "${1:-}" = "install" ]; then
mkdir -p "$HOME/bin"
for name in rockstest rocksptest; do
dest="$HOME/bin/$name"
cat > "$dest" <<EOF
#!/usr/bin/env bash
# Auto-generated by 'build_tools/rockstest.sh install'. Defers to
# build_tools/$name.sh in the current rocksdb source root.
if [ -x build_tools/$name.sh ]; then
exec build_tools/$name.sh "\$@"
else
echo "build_tools/$name.sh not found (Not in a rocksdb source root directory?)" >&2
exit 1
fi
EOF
chmod +x "$dest"
echo "Installed $dest"
done
exit 0
fi
if [ "$#" -lt 1 ]; then
echo "usage: $0 <test_binary> [test args...]" >&2
echo " $0 install # create ~/bin/rockstest and ~/bin/rocksptest shims" >&2
echo "example: $0 db_test --gtest_filter=*MixedSlowdown*" >&2
exit 1
fi
# First argument must be a test binary, not an option (catches a forgotten name).
if [ "${1#-}" != "$1" ]; then
echo "$0: first argument must be a test binary name, not an option ('$1')" >&2
exit 1
fi
BIN=$1
shift
# Compute parallelism the same way the Makefile computes NCORES.
NCORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
make AUTO_CLEAN=1 -j"$NCORES" "$BIN"
./"$BIN" "$@"
+3 -5
View File
@@ -5,8 +5,6 @@
# the docker and docker-registry groups, and logging out and back in to pick
# those up.)
#
# Meta employees: see https://fburl.com/rocksdb-docker to build this on a devvm.
#
# 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
#
@@ -17,8 +15,8 @@
# 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.2
# $ docker push ghcr.io/facebook/rocksdb_ubuntu:22.2
# $ 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
@@ -30,7 +28,7 @@ FROM ubuntu:22.04
RUN apt-get update
RUN apt-get upgrade -y
# install basic tools
RUN apt-get install -y vim wget curl ccache
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
+3 -9
View File
@@ -5,8 +5,6 @@
# the docker and docker-registry groups, and logging out and back in to pick
# those up.)
#
# Meta employees: see https://fburl.com/rocksdb-docker to build this on a devvm.
#
# 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
#
@@ -17,8 +15,8 @@
# 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.1
# $ docker push ghcr.io/facebook/rocksdb_ubuntu:24.1
# $ 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
@@ -30,15 +28,11 @@ FROM ubuntu:24.04
RUN apt-get update
RUN apt-get upgrade -y
# install basic tools
RUN apt-get install -y vim wget curl ccache
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 clang-21 from LLVM snapshot repo
RUN curl -fsSL https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm.gpg && \
echo "deb https://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" > /etc/apt/sources.list.d/llvm-21.list && \
apt-get update && apt-get install -y clang-21
# install basic package
RUN apt-get install -y lsb-release software-properties-common gnupg
# install gflags, tbb
+10 -24
View File
@@ -32,7 +32,7 @@ function get_lib_base()
local lib_platform=$3
local result="$TP2_LATEST/$lib_name/"
# Lib Version
if [ -z "$lib_version" ] || [ "$lib_version" = "LATEST" ]; then
# version is not provided, use latest
@@ -40,7 +40,7 @@ function get_lib_base()
else
result="$result/$lib_version/"
fi
# Lib Platform
if [ -z "$lib_platform" ]; then
# platform is not provided, use latest gcc
@@ -49,17 +49,17 @@ function get_lib_base()
echo $lib_platform
result="$result/$lib_platform/"
fi
result=`ls -1d $result/*/ | head -n1`
echo Finding link $result
# lib_name => LIB_NAME_BASE
local __res_var=${lib_name^^}"_BASE"
__res_var=`echo $__res_var | tr - _`
# LIB_NAME_BASE=$result
eval $__res_var=`readlink -f $result`
log_variable $__res_var
}
@@ -75,33 +75,17 @@ touch "$OUTPUT"
echo "Writing dependencies to $OUTPUT"
# Compilers locations
# GCC is pinned to 11.x because the only newer GCC in third-party2 (13.x) is
# built for centos9/glibc>=2.35 -- its libgcc_s.so.1 has a hard reference
# to _dl_find_object@GLIBC_2.35, but platform010 ships glibc 2.34. Bumping
# GCC requires a platform with glibc >= 2.35.
GCC_BASE=`readlink -f $TP2_LATEST/gcc/11.x/centos9-native/*/`
# Clang is pinned to the latest tested major (21). Bump deliberately.
CLANG_BASE=`readlink -f $TP2_LATEST/llvm-fb/21/platform010/*/`
GCC_BASE=`readlink -f $TP2_LATEST/gcc/11.x/centos8-native/*/`
CLANG_BASE=`readlink -f $TP2_LATEST/llvm-fb/15/platform010/*/`
log_header
log_variable GCC_BASE
log_variable CLANG_BASE
# Libraries locations
# libgcc is pinned to 11.x to match the GCC 11 compiler above (libstdc++/
# libgcc runtime, ABI, and C++ headers). Bump in lockstep with GCC_BASE.
get_lib_base libgcc 11.x platform010
# glibc 2.34 is the platform010 ABI baseline (ld.so + libc); it is also the
# only version available in third-party2, and defines the platform -- do
# not bump independently.
get_lib_base glibc 2.34 platform010
get_lib_base snappy LATEST platform010
# zlib is pinned to 1.2.8: it is the latest version with an x86_64
# platform010 build (1.2.13 / 1.3.1 are centos9 / aarch64 only). At time of
# writing, LATEST here doesn't work: get_lib_base picks the newest version
# dir first and only then appends the platform, with no fallback -- so
# LATEST would resolve to 1.3.1, find no platform010 build, and emit an
# empty ZLIB_BASE.
get_lib_base zlib 1.2.8 platform010
get_lib_base bzip2 LATEST platform010
get_lib_base lz4 LATEST platform010
@@ -110,11 +94,13 @@ get_lib_base gflags LATEST platform010
get_lib_base jemalloc LATEST platform010
get_lib_base numa LATEST platform010
get_lib_base libunwind LATEST platform010
get_lib_base tbb 2018_U5 platform010
get_lib_base liburing LATEST platform010
get_lib_base benchmark LATEST platform010
get_lib_base kernel-headers fb platform010
get_lib_base binutils LATEST centos9-native
get_lib_base binutils LATEST centos8-native
get_lib_base valgrind LATEST platform010
get_lib_base lua 5.3.4 platform010
git diff $OUTPUT
@@ -1,43 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'BlockBasedOptions simple'
// --header-out
// c_api_gen/c_generated_block_based_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_block_based_options_subset.cc.inc
/* BlockBasedOptions simple */
void rocksdb_block_based_options_set_data_block_hash_ratio(
rocksdb_block_based_table_options_t* options, double v) {
options->rep.data_block_hash_table_util_ratio = v;
}
void rocksdb_block_based_options_set_top_level_index_pinning_tier(
rocksdb_block_based_table_options_t* options, int v) {
options->rep.metadata_cache_options.top_level_index_pinning =
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
}
void rocksdb_block_based_options_set_partition_pinning_tier(
rocksdb_block_based_table_options_t* options, int v) {
options->rep.metadata_cache_options.partition_pinning =
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
}
void rocksdb_block_based_options_set_unpartitioned_pinning_tier(
rocksdb_block_based_table_options_t* options, int v) {
options->rep.metadata_cache_options.unpartitioned_pinning =
static_cast<ROCKSDB_NAMESPACE::PinningTier>(v);
}
@@ -1,36 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'BlockBasedOptions simple'
// --header-out
// c_api_gen/c_generated_block_based_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_block_based_options_subset.cc.inc
/* BlockBasedOptions simple */
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_data_block_hash_ratio(
rocksdb_block_based_table_options_t* options, double v);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_top_level_index_pinning_tier(
rocksdb_block_based_table_options_t* options, int v);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_partition_pinning_tier(
rocksdb_block_based_table_options_t* options, int v);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_unpartitioned_pinning_tier(
rocksdb_block_based_table_options_t* options, int v);
@@ -1,25 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'CuckooOptions simple'
// --header-out
// c_api_gen/c_generated_cuckoo_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_cuckoo_options_subset.cc.inc
/* CuckooOptions simple */
void rocksdb_cuckoo_options_set_hash_ratio(
rocksdb_cuckoo_table_options_t* options, double v) {
options->rep.hash_table_ratio = v;
}
@@ -1,23 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'CuckooOptions simple'
// --header-out
// c_api_gen/c_generated_cuckoo_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_cuckoo_options_subset.cc.inc
/* CuckooOptions simple */
extern ROCKSDB_LIBRARY_API void rocksdb_cuckoo_options_set_hash_ratio(
rocksdb_cuckoo_table_options_t* options, double v);
@@ -1,193 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'DB data operations'
// --header-out
// c_api_gen/c_generated_db_simple_subset.h.inc
// --source-out
// c_api_gen/c_generated_db_simple_subset.cc.inc
/* DB data operations */
void rocksdb_put(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr,
db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_put_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Put(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_delete(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen)));
}
void rocksdb_delete_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_merge(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Merge(options->rep, Slice(key, keylen),
Slice(val, vallen)));
}
void rocksdb_merge_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Merge(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_write(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr) {
SaveError(errptr, db->rep->Write(options->rep, &batch->rep));
}
void rocksdb_put_with_ts(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* ts,
size_t tslen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr, db->rep->Put(options->rep, Slice(key, keylen),
Slice(ts, tslen), Slice(val, vallen)));
}
void rocksdb_put_cf_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* ts,
size_t tslen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr,
db->rep->Put(options->rep, column_family->rep, Slice(key, keylen),
Slice(ts, tslen), Slice(val, vallen)));
}
void rocksdb_delete_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* ts,
size_t tslen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen),
Slice(ts, tslen)));
}
void rocksdb_delete_cf_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* ts,
size_t tslen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen), Slice(ts, tslen)));
}
void rocksdb_singledelete(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, Slice(key, keylen)));
}
void rocksdb_singledelete_cf(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_singledelete_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
const char* key, size_t keylen,
const char* ts, size_t tslen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, Slice(key, keylen),
Slice(ts, tslen)));
}
void rocksdb_singledelete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr) {
SaveError(errptr,
db->rep->SingleDelete(options->rep, column_family->rep,
Slice(key, keylen), Slice(ts, tslen)));
}
void rocksdb_delete_range_cf(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* start_key, size_t start_key_len,
const char* end_key, size_t end_key_len,
char** errptr) {
SaveError(errptr, db->rep->DeleteRange(options->rep, column_family->rep,
Slice(start_key, start_key_len),
Slice(end_key, end_key_len)));
}
void rocksdb_flush(rocksdb_t* db, const rocksdb_flushoptions_t* options,
char** errptr) {
SaveError(errptr, db->rep->Flush(options->rep));
}
void rocksdb_flush_cf(rocksdb_t* db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family,
char** errptr) {
SaveError(errptr, db->rep->Flush(options->rep, column_family->rep));
}
void rocksdb_flush_wal(rocksdb_t* db, unsigned char sync, char** errptr) {
SaveError(errptr, db->rep->FlushWAL(sync));
}
void rocksdb_pause_background_work(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->PauseBackgroundWork());
}
void rocksdb_continue_background_work(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->ContinueBackgroundWork());
}
void rocksdb_disable_file_deletions(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->DisableFileDeletions());
}
void rocksdb_enable_file_deletions(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->EnableFileDeletions());
}
void rocksdb_verify_checksum(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->VerifyChecksum());
}
void rocksdb_verify_file_checksums(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->VerifyFileChecksums(ReadOptions()));
}
void rocksdb_destroy_db(const rocksdb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, DestroyDB(name, options->rep));
}
void rocksdb_repair_db(const rocksdb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, RepairDB(name, options->rep));
}
@@ -1,130 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'DB data operations'
// --header-out
// c_api_gen/c_generated_db_simple_subset.h.inc
// --source-out
// c_api_gen/c_generated_db_simple_subset.cc.inc
/* DB data operations */
extern ROCKSDB_LIBRARY_API void rocksdb_put(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_merge(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_merge_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_write(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, const char* val, size_t vallen,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, const char* val, size_t vallen,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_range_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* start_key,
size_t start_key_len, const char* end_key, size_t end_key_len,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush(
rocksdb_t* db, const rocksdb_flushoptions_t* options, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush_cf(
rocksdb_t* db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush_wal(rocksdb_t* db,
unsigned char sync,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_pause_background_work(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_continue_background_work(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_disable_file_deletions(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_enable_file_deletions(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_verify_checksum(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_verify_file_checksums(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_destroy_db(
const rocksdb_options_t* options, const char* name, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_repair_db(
const rocksdb_options_t* options, const char* name, char** errptr);
-259
View File
@@ -1,259 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/listener.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered JobInfo metadata simple
/* FlushJobInfo */
uint32_t rocksdb_flushjobinfo_cf_id(const rocksdb_flushjobinfo_t* info) {
return info->rep.cf_id;
}
const char* rocksdb_flushjobinfo_cf_name(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_flushjobinfo_file_path(const rocksdb_flushjobinfo_t* info,
size_t* size) {
*size = info->rep.file_path.size();
return info->rep.file_path.data();
}
uint64_t rocksdb_flushjobinfo_file_number(const rocksdb_flushjobinfo_t* info) {
return info->rep.file_number;
}
uint64_t rocksdb_flushjobinfo_oldest_blob_file_number(
const rocksdb_flushjobinfo_t* info) {
return info->rep.oldest_blob_file_number;
}
uint64_t rocksdb_flushjobinfo_thread_id(const rocksdb_flushjobinfo_t* info) {
return info->rep.thread_id;
}
int rocksdb_flushjobinfo_job_id(const rocksdb_flushjobinfo_t* info) {
return info->rep.job_id;
}
unsigned char rocksdb_flushjobinfo_triggered_writes_slowdown(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_slowdown;
}
unsigned char rocksdb_flushjobinfo_triggered_writes_stop(
const rocksdb_flushjobinfo_t* info) {
return info->rep.triggered_writes_stop;
}
uint64_t rocksdb_flushjobinfo_smallest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.smallest_seqno;
}
uint64_t rocksdb_flushjobinfo_largest_seqno(
const rocksdb_flushjobinfo_t* info) {
return info->rep.largest_seqno;
}
uint32_t rocksdb_flushjobinfo_flush_reason(const rocksdb_flushjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.flush_reason);
}
uint32_t rocksdb_flushjobinfo_blob_compression_type(
const rocksdb_flushjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.blob_compression_type);
}
/* CompactionJobInfo */
uint32_t rocksdb_compactionjobinfo_cf_id(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.cf_id;
}
const char* rocksdb_compactionjobinfo_cf_name(
const rocksdb_compactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
void rocksdb_compactionjobinfo_status(const rocksdb_compactionjobinfo_t* info,
char** errptr) {
SaveError(errptr, info->rep.status);
}
uint64_t rocksdb_compactionjobinfo_thread_id(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.thread_id;
}
int rocksdb_compactionjobinfo_job_id(const rocksdb_compactionjobinfo_t* info) {
return info->rep.job_id;
}
int rocksdb_compactionjobinfo_num_l0_files(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.num_l0_files;
}
int rocksdb_compactionjobinfo_base_input_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_compactionjobinfo_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_level;
}
uint32_t rocksdb_compactionjobinfo_compaction_reason(
const rocksdb_compactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compaction_reason);
}
uint32_t rocksdb_compactionjobinfo_compression(
const rocksdb_compactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compression);
}
uint32_t rocksdb_compactionjobinfo_blob_compression_type(
const rocksdb_compactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.blob_compression_type);
}
unsigned char rocksdb_compactionjobinfo_aborted(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.aborted;
}
/* SubcompactionJobInfo */
uint32_t rocksdb_subcompactionjobinfo_cf_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.cf_id;
}
const char* rocksdb_subcompactionjobinfo_cf_name(
const rocksdb_subcompactionjobinfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
void rocksdb_subcompactionjobinfo_status(
const rocksdb_subcompactionjobinfo_t* info, char** errptr) {
SaveError(errptr, info->rep.status);
}
uint64_t rocksdb_subcompactionjobinfo_thread_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.thread_id;
}
int rocksdb_subcompactionjobinfo_job_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.job_id;
}
int rocksdb_subcompactionjobinfo_subcompaction_job_id(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.subcompaction_job_id;
}
int rocksdb_subcompactionjobinfo_base_input_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.base_input_level;
}
int rocksdb_subcompactionjobinfo_output_level(
const rocksdb_subcompactionjobinfo_t* info) {
return info->rep.output_level;
}
uint32_t rocksdb_subcompactionjobinfo_compaction_reason(
const rocksdb_subcompactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compaction_reason);
}
uint32_t rocksdb_subcompactionjobinfo_compression(
const rocksdb_subcompactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.compression);
}
uint32_t rocksdb_subcompactionjobinfo_blob_compression_type(
const rocksdb_subcompactionjobinfo_t* info) {
return static_cast<uint32_t>(info->rep.blob_compression_type);
}
/* ExternalFileIngestionInfo */
const char* rocksdb_externalfileingestioninfo_cf_name(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const char* rocksdb_externalfileingestioninfo_external_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.external_file_path.size();
return info->rep.external_file_path.data();
}
const char* rocksdb_externalfileingestioninfo_internal_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size) {
*size = info->rep.internal_file_path.size();
return info->rep.internal_file_path.data();
}
uint64_t rocksdb_externalfileingestioninfo_global_seqno(
const rocksdb_externalfileingestioninfo_t* info) {
return info->rep.global_seqno;
}
/* MemTableInfo */
const char* rocksdb_memtableinfo_cf_name(const rocksdb_memtableinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
uint64_t rocksdb_memtableinfo_first_seqno(const rocksdb_memtableinfo_t* info) {
return info->rep.first_seqno;
}
uint64_t rocksdb_memtableinfo_earliest_seqno(
const rocksdb_memtableinfo_t* info) {
return info->rep.earliest_seqno;
}
uint64_t rocksdb_memtableinfo_num_entries(const rocksdb_memtableinfo_t* info) {
return info->rep.num_entries;
}
uint64_t rocksdb_memtableinfo_num_deletes(const rocksdb_memtableinfo_t* info) {
return info->rep.num_deletes;
}
const char* rocksdb_memtableinfo_newest_udt(const rocksdb_memtableinfo_t* info,
size_t* size) {
*size = info->rep.newest_udt.size();
return info->rep.newest_udt.data();
}
-177
View File
@@ -1,177 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/listener.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered JobInfo metadata simple
/* FlushJobInfo */
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_flushjobinfo_cf_id(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API const char* rocksdb_flushjobinfo_cf_name(
const rocksdb_flushjobinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API const char* rocksdb_flushjobinfo_file_path(
const rocksdb_flushjobinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_file_number(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_oldest_blob_file_number(
const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_thread_id(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_flushjobinfo_job_id(
const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_flushjobinfo_triggered_writes_slowdown(
const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_flushjobinfo_triggered_writes_stop(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_smallest_seqno(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_flushjobinfo_largest_seqno(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_flushjobinfo_flush_reason(const rocksdb_flushjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_flushjobinfo_blob_compression_type(const rocksdb_flushjobinfo_t* info);
/* CompactionJobInfo */
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_compactionjobinfo_cf_id(const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API const char* rocksdb_compactionjobinfo_cf_name(
const rocksdb_compactionjobinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API void rocksdb_compactionjobinfo_status(
const rocksdb_compactionjobinfo_t* info, char** errptr);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_thread_id(const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_job_id(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_num_l0_files(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_base_input_level(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_compactionjobinfo_output_level(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t rocksdb_compactionjobinfo_compaction_reason(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_compactionjobinfo_compression(const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_compactionjobinfo_blob_compression_type(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_compactionjobinfo_aborted(
const rocksdb_compactionjobinfo_t* info);
/* SubcompactionJobInfo */
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_subcompactionjobinfo_cf_id(const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API const char* rocksdb_subcompactionjobinfo_cf_name(
const rocksdb_subcompactionjobinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API void rocksdb_subcompactionjobinfo_status(
const rocksdb_subcompactionjobinfo_t* info, char** errptr);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_subcompactionjobinfo_thread_id(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_subcompactionjobinfo_job_id(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int
rocksdb_subcompactionjobinfo_subcompaction_job_id(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_subcompactionjobinfo_base_input_level(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API int rocksdb_subcompactionjobinfo_output_level(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_subcompactionjobinfo_compaction_reason(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t rocksdb_subcompactionjobinfo_compression(
const rocksdb_subcompactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint32_t
rocksdb_subcompactionjobinfo_blob_compression_type(
const rocksdb_subcompactionjobinfo_t* info);
/* ExternalFileIngestionInfo */
extern ROCKSDB_LIBRARY_API const char*
rocksdb_externalfileingestioninfo_cf_name(
const rocksdb_externalfileingestioninfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_externalfileingestioninfo_external_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_externalfileingestioninfo_internal_file_path(
const rocksdb_externalfileingestioninfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_externalfileingestioninfo_global_seqno(
const rocksdb_externalfileingestioninfo_t* info);
/* MemTableInfo */
extern ROCKSDB_LIBRARY_API const char* rocksdb_memtableinfo_cf_name(
const rocksdb_memtableinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_first_seqno(const rocksdb_memtableinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_earliest_seqno(const rocksdb_memtableinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_num_entries(const rocksdb_memtableinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_memtableinfo_num_deletes(const rocksdb_memtableinfo_t* info);
extern ROCKSDB_LIBRARY_API const char* rocksdb_memtableinfo_newest_udt(
const rocksdb_memtableinfo_t* info, size_t* size);
@@ -1,88 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'JobInfo metadata simple'
// --header-out
// c_api_gen/c_generated_jobinfo_metadata_subset.h.inc
// --source-out
// c_api_gen/c_generated_jobinfo_metadata_subset.cc.inc
/* JobInfo metadata simple */
size_t rocksdb_compactionjobinfo_input_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.input_files.size();
}
size_t rocksdb_compactionjobinfo_output_files_count(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.output_files.size();
}
uint64_t rocksdb_compactionjobinfo_elapsed_micros(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.elapsed_micros;
}
uint64_t rocksdb_compactionjobinfo_num_corrupt_keys(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_corrupt_keys;
}
uint64_t rocksdb_compactionjobinfo_input_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_records;
}
uint64_t rocksdb_compactionjobinfo_output_records(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_output_records;
}
uint64_t rocksdb_compactionjobinfo_total_input_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_input_bytes;
}
uint64_t rocksdb_compactionjobinfo_total_output_bytes(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.total_output_bytes;
}
size_t rocksdb_compactionjobinfo_num_input_files(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files;
}
size_t rocksdb_compactionjobinfo_num_input_files_at_output_level(
const rocksdb_compactionjobinfo_t* info) {
return info->rep.stats.num_input_files_at_output_level;
}
const char* rocksdb_writestallinfo_cf_name(const rocksdb_writestallinfo_t* info,
size_t* size) {
*size = info->rep.cf_name.size();
return info->rep.cf_name.data();
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_cur(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.cur);
}
const rocksdb_writestallcondition_t* rocksdb_writestallinfo_prev(
const rocksdb_writestallinfo_t* info) {
return reinterpret_cast<const rocksdb_writestallcondition_t*>(
&info->rep.condition.prev);
}
@@ -1,61 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'JobInfo metadata simple'
// --header-out
// c_api_gen/c_generated_jobinfo_metadata_subset.h.inc
// --source-out
// c_api_gen/c_generated_jobinfo_metadata_subset.cc.inc
/* JobInfo metadata simple */
extern ROCKSDB_LIBRARY_API size_t rocksdb_compactionjobinfo_input_files_count(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compactionjobinfo_output_files_count(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compactionjobinfo_elapsed_micros(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compactionjobinfo_num_corrupt_keys(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compactionjobinfo_input_records(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compactionjobinfo_output_records(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compactionjobinfo_total_input_bytes(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compactionjobinfo_total_output_bytes(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compactionjobinfo_num_input_files(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compactionjobinfo_num_input_files_at_output_level(
const rocksdb_compactionjobinfo_t* info);
extern ROCKSDB_LIBRARY_API const char* rocksdb_writestallinfo_cf_name(
const rocksdb_writestallinfo_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API const rocksdb_writestallcondition_t*
rocksdb_writestallinfo_cur(const rocksdb_writestallinfo_t* info);
extern ROCKSDB_LIBRARY_API const rocksdb_writestallcondition_t*
rocksdb_writestallinfo_prev(const rocksdb_writestallinfo_t* info);
@@ -1,527 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/compaction_job_stats.h
// - include/rocksdb/listener.h
// - include/rocksdb/table_properties.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered metadata view structs simple
/* TableProperties */
uint64_t rocksdb_table_properties_orig_file_number(
const rocksdb_table_properties_t* props) {
return props->rep.orig_file_number;
}
uint64_t rocksdb_table_properties_data_size(
const rocksdb_table_properties_t* props) {
return props->rep.data_size;
}
uint64_t rocksdb_table_properties_uncompressed_data_size(
const rocksdb_table_properties_t* props) {
return props->rep.uncompressed_data_size;
}
uint64_t rocksdb_table_properties_index_size(
const rocksdb_table_properties_t* props) {
return props->rep.index_size;
}
uint64_t rocksdb_table_properties_index_partitions(
const rocksdb_table_properties_t* props) {
return props->rep.index_partitions;
}
uint64_t rocksdb_table_properties_top_level_index_size(
const rocksdb_table_properties_t* props) {
return props->rep.top_level_index_size;
}
uint64_t rocksdb_table_properties_index_key_is_user_key(
const rocksdb_table_properties_t* props) {
return props->rep.index_key_is_user_key;
}
uint64_t rocksdb_table_properties_index_value_is_delta_encoded(
const rocksdb_table_properties_t* props) {
return props->rep.index_value_is_delta_encoded;
}
uint64_t rocksdb_table_properties_udi_is_primary_index(
const rocksdb_table_properties_t* props) {
return props->rep.udi_is_primary_index;
}
uint64_t rocksdb_table_properties_filter_size(
const rocksdb_table_properties_t* props) {
return props->rep.filter_size;
}
uint64_t rocksdb_table_properties_raw_key_size(
const rocksdb_table_properties_t* props) {
return props->rep.raw_key_size;
}
uint64_t rocksdb_table_properties_raw_value_size(
const rocksdb_table_properties_t* props) {
return props->rep.raw_value_size;
}
uint64_t rocksdb_table_properties_num_data_blocks(
const rocksdb_table_properties_t* props) {
return props->rep.num_data_blocks;
}
uint64_t rocksdb_table_properties_num_data_blocks_compression_rejected(
const rocksdb_table_properties_t* props) {
return props->rep.num_data_blocks_compression_rejected;
}
uint64_t rocksdb_table_properties_num_data_blocks_compression_bypassed(
const rocksdb_table_properties_t* props) {
return props->rep.num_data_blocks_compression_bypassed;
}
uint64_t rocksdb_table_properties_num_uniform_blocks(
const rocksdb_table_properties_t* props) {
return props->rep.num_uniform_blocks;
}
uint64_t rocksdb_table_properties_num_entries(
const rocksdb_table_properties_t* props) {
return props->rep.num_entries;
}
uint64_t rocksdb_table_properties_num_filter_entries(
const rocksdb_table_properties_t* props) {
return props->rep.num_filter_entries;
}
uint64_t rocksdb_table_properties_num_deletions(
const rocksdb_table_properties_t* props) {
return props->rep.num_deletions;
}
uint64_t rocksdb_table_properties_num_merge_operands(
const rocksdb_table_properties_t* props) {
return props->rep.num_merge_operands;
}
uint64_t rocksdb_table_properties_num_range_deletions(
const rocksdb_table_properties_t* props) {
return props->rep.num_range_deletions;
}
uint64_t rocksdb_table_properties_format_version(
const rocksdb_table_properties_t* props) {
return props->rep.format_version;
}
uint64_t rocksdb_table_properties_fixed_key_len(
const rocksdb_table_properties_t* props) {
return props->rep.fixed_key_len;
}
uint64_t rocksdb_table_properties_column_family_id(
const rocksdb_table_properties_t* props) {
return props->rep.column_family_id;
}
uint64_t rocksdb_table_properties_creation_time(
const rocksdb_table_properties_t* props) {
return props->rep.creation_time;
}
uint64_t rocksdb_table_properties_oldest_key_time(
const rocksdb_table_properties_t* props) {
return props->rep.oldest_key_time;
}
uint64_t rocksdb_table_properties_newest_key_time(
const rocksdb_table_properties_t* props) {
return props->rep.newest_key_time;
}
uint64_t rocksdb_table_properties_file_creation_time(
const rocksdb_table_properties_t* props) {
return props->rep.file_creation_time;
}
uint64_t rocksdb_table_properties_slow_compression_estimated_data_size(
const rocksdb_table_properties_t* props) {
return props->rep.slow_compression_estimated_data_size;
}
uint64_t rocksdb_table_properties_fast_compression_estimated_data_size(
const rocksdb_table_properties_t* props) {
return props->rep.fast_compression_estimated_data_size;
}
uint64_t rocksdb_table_properties_external_sst_file_global_seqno_offset(
const rocksdb_table_properties_t* props) {
return props->rep.external_sst_file_global_seqno_offset;
}
uint64_t rocksdb_table_properties_tail_start_offset(
const rocksdb_table_properties_t* props) {
return props->rep.tail_start_offset;
}
uint64_t rocksdb_table_properties_user_defined_timestamps_persisted(
const rocksdb_table_properties_t* props) {
return props->rep.user_defined_timestamps_persisted;
}
uint64_t rocksdb_table_properties_key_largest_seqno(
const rocksdb_table_properties_t* props) {
return props->rep.key_largest_seqno;
}
uint64_t rocksdb_table_properties_key_smallest_seqno(
const rocksdb_table_properties_t* props) {
return props->rep.key_smallest_seqno;
}
uint64_t rocksdb_table_properties_data_block_restart_interval(
const rocksdb_table_properties_t* props) {
return props->rep.data_block_restart_interval;
}
uint64_t rocksdb_table_properties_index_block_restart_interval(
const rocksdb_table_properties_t* props) {
return props->rep.index_block_restart_interval;
}
uint64_t rocksdb_table_properties_separate_key_value_in_data_block(
const rocksdb_table_properties_t* props) {
return props->rep.separate_key_value_in_data_block;
}
const char* rocksdb_table_properties_db_id(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.db_id.size();
return props->rep.db_id.data();
}
const char* rocksdb_table_properties_db_session_id(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.db_session_id.size();
return props->rep.db_session_id.data();
}
const char* rocksdb_table_properties_db_host_id(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.db_host_id.size();
return props->rep.db_host_id.data();
}
const char* rocksdb_table_properties_column_family_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.column_family_name.size();
return props->rep.column_family_name.data();
}
const char* rocksdb_table_properties_filter_policy_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.filter_policy_name.size();
return props->rep.filter_policy_name.data();
}
const char* rocksdb_table_properties_comparator_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.comparator_name.size();
return props->rep.comparator_name.data();
}
const char* rocksdb_table_properties_merge_operator_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.merge_operator_name.size();
return props->rep.merge_operator_name.data();
}
const char* rocksdb_table_properties_prefix_extractor_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.prefix_extractor_name.size();
return props->rep.prefix_extractor_name.data();
}
const char* rocksdb_table_properties_property_collectors_names(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.property_collectors_names.size();
return props->rep.property_collectors_names.data();
}
const char* rocksdb_table_properties_compression_name(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.compression_name.size();
return props->rep.compression_name.data();
}
const char* rocksdb_table_properties_compression_options(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.compression_options.size();
return props->rep.compression_options.data();
}
const char* rocksdb_table_properties_seqno_to_time_mapping(
const rocksdb_table_properties_t* props, size_t* size) {
*size = props->rep.seqno_to_time_mapping.size();
return props->rep.seqno_to_time_mapping.data();
}
/* CompactionJobStats */
uint64_t rocksdb_compaction_job_stats_elapsed_micros(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.elapsed_micros;
}
uint64_t rocksdb_compaction_job_stats_cpu_micros(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.cpu_micros;
}
unsigned char rocksdb_compaction_job_stats_has_accurate_num_input_records(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.has_accurate_num_input_records;
}
uint64_t rocksdb_compaction_job_stats_num_input_records(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_input_records;
}
uint64_t rocksdb_compaction_job_stats_num_blobs_read(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_blobs_read;
}
size_t rocksdb_compaction_job_stats_num_input_files(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_input_files;
}
size_t rocksdb_compaction_job_stats_num_input_files_trivially_moved(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_input_files_trivially_moved;
}
size_t rocksdb_compaction_job_stats_num_input_files_at_output_level(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_input_files_at_output_level;
}
size_t rocksdb_compaction_job_stats_num_filtered_input_files(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_filtered_input_files;
}
size_t rocksdb_compaction_job_stats_num_filtered_input_files_at_output_level(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_filtered_input_files_at_output_level;
}
uint64_t rocksdb_compaction_job_stats_num_output_records(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_output_records;
}
size_t rocksdb_compaction_job_stats_num_output_files(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_output_files;
}
size_t rocksdb_compaction_job_stats_num_output_files_blob(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_output_files_blob;
}
unsigned char rocksdb_compaction_job_stats_is_full_compaction(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.is_full_compaction;
}
unsigned char rocksdb_compaction_job_stats_is_manual_compaction(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.is_manual_compaction;
}
unsigned char rocksdb_compaction_job_stats_is_remote_compaction(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.is_remote_compaction;
}
uint64_t rocksdb_compaction_job_stats_total_input_bytes(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_input_bytes;
}
uint64_t rocksdb_compaction_job_stats_total_blob_bytes_read(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_blob_bytes_read;
}
uint64_t rocksdb_compaction_job_stats_total_output_bytes(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_output_bytes;
}
uint64_t rocksdb_compaction_job_stats_total_output_bytes_blob(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_output_bytes_blob;
}
uint64_t rocksdb_compaction_job_stats_total_skipped_input_bytes(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_skipped_input_bytes;
}
uint64_t rocksdb_compaction_job_stats_num_records_replaced(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_records_replaced;
}
uint64_t rocksdb_compaction_job_stats_total_input_raw_key_bytes(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_input_raw_key_bytes;
}
uint64_t rocksdb_compaction_job_stats_total_input_raw_value_bytes(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.total_input_raw_value_bytes;
}
uint64_t rocksdb_compaction_job_stats_num_input_deletion_records(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_input_deletion_records;
}
uint64_t rocksdb_compaction_job_stats_num_expired_deletion_records(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_expired_deletion_records;
}
uint64_t rocksdb_compaction_job_stats_num_corrupt_keys(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_corrupt_keys;
}
uint64_t rocksdb_compaction_job_stats_file_write_nanos(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.file_write_nanos;
}
uint64_t rocksdb_compaction_job_stats_file_range_sync_nanos(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.file_range_sync_nanos;
}
uint64_t rocksdb_compaction_job_stats_file_fsync_nanos(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.file_fsync_nanos;
}
uint64_t rocksdb_compaction_job_stats_file_prepare_write_nanos(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.file_prepare_write_nanos;
}
const char* rocksdb_compaction_job_stats_smallest_output_key_prefix(
const rocksdb_compaction_job_stats_t* stats, size_t* size) {
*size = stats->rep.smallest_output_key_prefix.size();
return stats->rep.smallest_output_key_prefix.data();
}
const char* rocksdb_compaction_job_stats_largest_output_key_prefix(
const rocksdb_compaction_job_stats_t* stats, size_t* size) {
*size = stats->rep.largest_output_key_prefix.size();
return stats->rep.largest_output_key_prefix.data();
}
uint64_t rocksdb_compaction_job_stats_num_single_del_fallthru(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_single_del_fallthru;
}
uint64_t rocksdb_compaction_job_stats_num_single_del_mismatch(
const rocksdb_compaction_job_stats_t* stats) {
return stats->rep.num_single_del_mismatch;
}
/* CompactionFileInfo */
int rocksdb_compaction_file_info_level(
const rocksdb_compaction_file_info_t* info) {
return info->rep.level;
}
uint64_t rocksdb_compaction_file_info_file_number(
const rocksdb_compaction_file_info_t* info) {
return info->rep.file_number;
}
uint64_t rocksdb_compaction_file_info_oldest_blob_file_number(
const rocksdb_compaction_file_info_t* info) {
return info->rep.oldest_blob_file_number;
}
/* BlobFileAdditionInfo */
const char* rocksdb_blob_file_addition_info_blob_file_path(
const rocksdb_blob_file_addition_info_t* info, size_t* size) {
*size = info->rep.blob_file_path.size();
return info->rep.blob_file_path.data();
}
uint64_t rocksdb_blob_file_addition_info_blob_file_number(
const rocksdb_blob_file_addition_info_t* info) {
return info->rep.blob_file_number;
}
uint64_t rocksdb_blob_file_addition_info_total_blob_count(
const rocksdb_blob_file_addition_info_t* info) {
return info->rep.total_blob_count;
}
uint64_t rocksdb_blob_file_addition_info_total_blob_bytes(
const rocksdb_blob_file_addition_info_t* info) {
return info->rep.total_blob_bytes;
}
/* BlobFileGarbageInfo */
const char* rocksdb_blob_file_garbage_info_blob_file_path(
const rocksdb_blob_file_garbage_info_t* info, size_t* size) {
*size = info->rep.blob_file_path.size();
return info->rep.blob_file_path.data();
}
uint64_t rocksdb_blob_file_garbage_info_blob_file_number(
const rocksdb_blob_file_garbage_info_t* info) {
return info->rep.blob_file_number;
}
uint64_t rocksdb_blob_file_garbage_info_garbage_blob_count(
const rocksdb_blob_file_garbage_info_t* info) {
return info->rep.garbage_blob_count;
}
uint64_t rocksdb_blob_file_garbage_info_garbage_blob_bytes(
const rocksdb_blob_file_garbage_info_t* info) {
return info->rep.garbage_blob_bytes;
}
@@ -1,381 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/compaction_job_stats.h
// - include/rocksdb/listener.h
// - include/rocksdb/table_properties.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered metadata view structs simple
/* TableProperties */
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_orig_file_number(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_data_size(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_uncompressed_data_size(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_index_size(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_index_partitions(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_top_level_index_size(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_index_key_is_user_key(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_index_value_is_delta_encoded(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_udi_is_primary_index(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_filter_size(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_raw_key_size(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_raw_value_size(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_num_data_blocks(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_num_data_blocks_compression_rejected(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_num_data_blocks_compression_bypassed(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_num_uniform_blocks(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_num_entries(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_num_filter_entries(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_num_deletions(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_num_merge_operands(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_num_range_deletions(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_format_version(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_fixed_key_len(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_column_family_id(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_creation_time(const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_oldest_key_time(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_newest_key_time(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_file_creation_time(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_slow_compression_estimated_data_size(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_fast_compression_estimated_data_size(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_external_sst_file_global_seqno_offset(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_tail_start_offset(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_user_defined_timestamps_persisted(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_key_largest_seqno(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_table_properties_key_smallest_seqno(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_data_block_restart_interval(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_index_block_restart_interval(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_table_properties_separate_key_value_in_data_block(
const rocksdb_table_properties_t* props);
extern ROCKSDB_LIBRARY_API const char* rocksdb_table_properties_db_id(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char* rocksdb_table_properties_db_session_id(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char* rocksdb_table_properties_db_host_id(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_column_family_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_filter_policy_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char* rocksdb_table_properties_comparator_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_merge_operator_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_prefix_extractor_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_property_collectors_names(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_compression_name(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_compression_options(
const rocksdb_table_properties_t* props, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_table_properties_seqno_to_time_mapping(
const rocksdb_table_properties_t* props, size_t* size);
/* CompactionJobStats */
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compaction_job_stats_elapsed_micros(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compaction_job_stats_cpu_micros(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_compaction_job_stats_has_accurate_num_input_records(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_input_records(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compaction_job_stats_num_blobs_read(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compaction_job_stats_num_input_files(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compaction_job_stats_num_input_files_trivially_moved(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compaction_job_stats_num_input_files_at_output_level(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compaction_job_stats_num_filtered_input_files(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compaction_job_stats_num_filtered_input_files_at_output_level(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_output_records(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t rocksdb_compaction_job_stats_num_output_files(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_compaction_job_stats_num_output_files_blob(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_compaction_job_stats_is_full_compaction(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_compaction_job_stats_is_manual_compaction(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_compaction_job_stats_is_remote_compaction(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_input_bytes(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_blob_bytes_read(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_output_bytes(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_output_bytes_blob(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_skipped_input_bytes(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_records_replaced(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_input_raw_key_bytes(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_total_input_raw_value_bytes(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_input_deletion_records(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_expired_deletion_records(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_corrupt_keys(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_file_write_nanos(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_file_range_sync_nanos(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_file_fsync_nanos(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_file_prepare_write_nanos(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_compaction_job_stats_smallest_output_key_prefix(
const rocksdb_compaction_job_stats_t* stats, size_t* size);
extern ROCKSDB_LIBRARY_API const char*
rocksdb_compaction_job_stats_largest_output_key_prefix(
const rocksdb_compaction_job_stats_t* stats, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_single_del_fallthru(
const rocksdb_compaction_job_stats_t* stats);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_job_stats_num_single_del_mismatch(
const rocksdb_compaction_job_stats_t* stats);
/* CompactionFileInfo */
extern ROCKSDB_LIBRARY_API int rocksdb_compaction_file_info_level(
const rocksdb_compaction_file_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t rocksdb_compaction_file_info_file_number(
const rocksdb_compaction_file_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_compaction_file_info_oldest_blob_file_number(
const rocksdb_compaction_file_info_t* info);
/* BlobFileAdditionInfo */
extern ROCKSDB_LIBRARY_API const char*
rocksdb_blob_file_addition_info_blob_file_path(
const rocksdb_blob_file_addition_info_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_addition_info_blob_file_number(
const rocksdb_blob_file_addition_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_addition_info_total_blob_count(
const rocksdb_blob_file_addition_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_addition_info_total_blob_bytes(
const rocksdb_blob_file_addition_info_t* info);
/* BlobFileGarbageInfo */
extern ROCKSDB_LIBRARY_API const char*
rocksdb_blob_file_garbage_info_blob_file_path(
const rocksdb_blob_file_garbage_info_t* info, size_t* size);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_garbage_info_blob_file_number(
const rocksdb_blob_file_garbage_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_garbage_info_garbage_blob_count(
const rocksdb_blob_file_garbage_info_t* info);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_blob_file_garbage_info_garbage_blob_bytes(
const rocksdb_blob_file_garbage_info_t* info);
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,88 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'Options simple'
// --header-out
// c_api_gen/c_generated_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_options_subset.cc.inc
/* Options simple */
void rocksdb_options_set_compression_options_zstd_max_train_bytes(
rocksdb_options_t* opt, int zstd_max_train_bytes) {
opt->rep.compression_opts.zstd_max_train_bytes = zstd_max_train_bytes;
}
int rocksdb_options_get_compression_options_zstd_max_train_bytes(
rocksdb_options_t* opt) {
return opt->rep.compression_opts.zstd_max_train_bytes;
}
void rocksdb_options_set_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt, unsigned char use_zstd_dict_trainer) {
opt->rep.compression_opts.use_zstd_dict_trainer = use_zstd_dict_trainer;
}
unsigned char rocksdb_options_get_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt) {
return opt->rep.compression_opts.use_zstd_dict_trainer;
}
void rocksdb_options_set_compression_options_parallel_threads(
rocksdb_options_t* opt, int value) {
opt->rep.compression_opts.parallel_threads = value;
}
int rocksdb_options_get_compression_options_parallel_threads(
rocksdb_options_t* opt) {
return opt->rep.compression_opts.parallel_threads;
}
void rocksdb_options_set_compression_options_max_dict_buffer_bytes(
rocksdb_options_t* opt, uint64_t max_dict_buffer_bytes) {
opt->rep.compression_opts.max_dict_buffer_bytes = max_dict_buffer_bytes;
}
uint64_t rocksdb_options_get_compression_options_max_dict_buffer_bytes(
rocksdb_options_t* opt) {
return opt->rep.compression_opts.max_dict_buffer_bytes;
}
unsigned char
rocksdb_options_get_bottommost_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt) {
return opt->rep.bottommost_compression_opts.use_zstd_dict_trainer;
}
void rocksdb_options_set_use_fsync(rocksdb_options_t* opt, int use_fsync) {
opt->rep.use_fsync = use_fsync;
}
int rocksdb_options_get_use_fsync(rocksdb_options_t* opt) {
return opt->rep.use_fsync;
}
void rocksdb_options_set_disable_auto_compactions(rocksdb_options_t* opt,
int disable) {
opt->rep.disable_auto_compactions = disable;
}
void rocksdb_options_set_optimize_filters_for_hits(rocksdb_options_t* opt,
int v) {
opt->rep.optimize_filters_for_hits = v;
}
void rocksdb_options_set_report_bg_io_stats(rocksdb_options_t* opt, int v) {
opt->rep.report_bg_io_stats = v;
}
@@ -1,71 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'Options simple'
// --header-out
// c_api_gen/c_generated_options_subset.h.inc
// --source-out
// c_api_gen/c_generated_options_subset.cc.inc
/* Options simple */
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_compression_options_zstd_max_train_bytes(
rocksdb_options_t* opt, int zstd_max_train_bytes);
extern ROCKSDB_LIBRARY_API int
rocksdb_options_get_compression_options_zstd_max_train_bytes(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt, unsigned char use_zstd_dict_trainer);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_options_get_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_compression_options_parallel_threads(rocksdb_options_t* opt,
int value);
extern ROCKSDB_LIBRARY_API int
rocksdb_options_get_compression_options_parallel_threads(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_options_set_compression_options_max_dict_buffer_bytes(
rocksdb_options_t* opt, uint64_t max_dict_buffer_bytes);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_options_get_compression_options_max_dict_buffer_bytes(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_options_get_bottommost_compression_options_use_zstd_dict_trainer(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_use_fsync(
rocksdb_options_t* opt, int use_fsync);
extern ROCKSDB_LIBRARY_API int rocksdb_options_get_use_fsync(
rocksdb_options_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_disable_auto_compactions(
rocksdb_options_t* opt, int disable);
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_optimize_filters_for_hits(
rocksdb_options_t* opt, int v);
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_report_bg_io_stats(
rocksdb_options_t* opt, int v);
@@ -1,240 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/options.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered ReadOptions simple
/* ReadOptions */
void rocksdb_readoptions_set_deadline(rocksdb_readoptions_t* opt,
uint64_t microseconds) {
opt->rep.deadline = std::chrono::microseconds(microseconds);
}
uint64_t rocksdb_readoptions_get_deadline(rocksdb_readoptions_t* opt) {
return opt->rep.deadline.count();
}
void rocksdb_readoptions_set_io_timeout(rocksdb_readoptions_t* opt,
uint64_t microseconds) {
opt->rep.io_timeout = std::chrono::microseconds(microseconds);
}
uint64_t rocksdb_readoptions_get_io_timeout(rocksdb_readoptions_t* opt) {
return opt->rep.io_timeout.count();
}
void rocksdb_readoptions_set_read_tier(rocksdb_readoptions_t* opt, int v) {
opt->rep.read_tier = static_cast<decltype(opt->rep.read_tier)>(v);
}
int rocksdb_readoptions_get_read_tier(rocksdb_readoptions_t* opt) {
return static_cast<int>(opt->rep.read_tier);
}
void rocksdb_readoptions_set_rate_limiter_priority(rocksdb_readoptions_t* opt,
int v) {
opt->rep.rate_limiter_priority =
static_cast<decltype(opt->rep.rate_limiter_priority)>(v);
}
int rocksdb_readoptions_get_rate_limiter_priority(rocksdb_readoptions_t* opt) {
return static_cast<int>(opt->rep.rate_limiter_priority);
}
void rocksdb_readoptions_set_value_size_soft_limit(rocksdb_readoptions_t* opt,
uint64_t v) {
opt->rep.value_size_soft_limit = v;
}
uint64_t rocksdb_readoptions_get_value_size_soft_limit(
rocksdb_readoptions_t* opt) {
return opt->rep.value_size_soft_limit;
}
void rocksdb_readoptions_set_verify_checksums(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.verify_checksums = v;
}
unsigned char rocksdb_readoptions_get_verify_checksums(
rocksdb_readoptions_t* opt) {
return opt->rep.verify_checksums;
}
void rocksdb_readoptions_set_fill_cache(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.fill_cache = v;
}
unsigned char rocksdb_readoptions_get_fill_cache(rocksdb_readoptions_t* opt) {
return opt->rep.fill_cache;
}
void rocksdb_readoptions_set_ignore_range_deletions(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.ignore_range_deletions = v;
}
unsigned char rocksdb_readoptions_get_ignore_range_deletions(
rocksdb_readoptions_t* opt) {
return opt->rep.ignore_range_deletions;
}
void rocksdb_readoptions_set_async_io(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.async_io = v;
}
unsigned char rocksdb_readoptions_get_async_io(rocksdb_readoptions_t* opt) {
return opt->rep.async_io;
}
void rocksdb_readoptions_set_optimize_multiget_for_io(
rocksdb_readoptions_t* opt, unsigned char v) {
opt->rep.optimize_multiget_for_io = v;
}
unsigned char rocksdb_readoptions_get_optimize_multiget_for_io(
rocksdb_readoptions_t* opt) {
return opt->rep.optimize_multiget_for_io;
}
void rocksdb_readoptions_set_readahead_size(rocksdb_readoptions_t* opt,
size_t v) {
opt->rep.readahead_size = v;
}
size_t rocksdb_readoptions_get_readahead_size(rocksdb_readoptions_t* opt) {
return opt->rep.readahead_size;
}
void rocksdb_readoptions_set_max_skippable_internal_keys(
rocksdb_readoptions_t* opt, uint64_t v) {
opt->rep.max_skippable_internal_keys = v;
}
uint64_t rocksdb_readoptions_get_max_skippable_internal_keys(
rocksdb_readoptions_t* opt) {
return opt->rep.max_skippable_internal_keys;
}
void rocksdb_readoptions_set_tailing(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.tailing = v;
}
unsigned char rocksdb_readoptions_get_tailing(rocksdb_readoptions_t* opt) {
return opt->rep.tailing;
}
void rocksdb_readoptions_set_total_order_seek(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.total_order_seek = v;
}
unsigned char rocksdb_readoptions_get_total_order_seek(
rocksdb_readoptions_t* opt) {
return opt->rep.total_order_seek;
}
void rocksdb_readoptions_set_auto_prefix_mode(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.auto_prefix_mode = v;
}
unsigned char rocksdb_readoptions_get_auto_prefix_mode(
rocksdb_readoptions_t* opt) {
return opt->rep.auto_prefix_mode;
}
void rocksdb_readoptions_set_prefix_same_as_start(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.prefix_same_as_start = v;
}
unsigned char rocksdb_readoptions_get_prefix_same_as_start(
rocksdb_readoptions_t* opt) {
return opt->rep.prefix_same_as_start;
}
void rocksdb_readoptions_set_pin_data(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.pin_data = v;
}
unsigned char rocksdb_readoptions_get_pin_data(rocksdb_readoptions_t* opt) {
return opt->rep.pin_data;
}
void rocksdb_readoptions_set_adaptive_readahead(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.adaptive_readahead = v;
}
unsigned char rocksdb_readoptions_get_adaptive_readahead(
rocksdb_readoptions_t* opt) {
return opt->rep.adaptive_readahead;
}
void rocksdb_readoptions_set_background_purge_on_iterator_cleanup(
rocksdb_readoptions_t* opt, unsigned char v) {
opt->rep.background_purge_on_iterator_cleanup = v;
}
unsigned char rocksdb_readoptions_get_background_purge_on_iterator_cleanup(
rocksdb_readoptions_t* opt) {
return opt->rep.background_purge_on_iterator_cleanup;
}
void rocksdb_readoptions_set_auto_readahead_size(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.auto_readahead_size = v;
}
unsigned char rocksdb_readoptions_get_auto_readahead_size(
rocksdb_readoptions_t* opt) {
return opt->rep.auto_readahead_size;
}
void rocksdb_readoptions_set_allow_unprepared_value(rocksdb_readoptions_t* opt,
unsigned char v) {
opt->rep.allow_unprepared_value = v;
}
unsigned char rocksdb_readoptions_get_allow_unprepared_value(
rocksdb_readoptions_t* opt) {
return opt->rep.allow_unprepared_value;
}
void rocksdb_readoptions_set_auto_refresh_iterator_with_snapshot(
rocksdb_readoptions_t* opt, unsigned char v) {
opt->rep.auto_refresh_iterator_with_snapshot = v;
}
unsigned char rocksdb_readoptions_get_auto_refresh_iterator_with_snapshot(
rocksdb_readoptions_t* opt) {
return opt->rep.auto_refresh_iterator_with_snapshot;
}
void rocksdb_readoptions_set_io_activity(rocksdb_readoptions_t* opt, int v) {
opt->rep.io_activity = static_cast<decltype(opt->rep.io_activity)>(v);
}
int rocksdb_readoptions_get_io_activity(rocksdb_readoptions_t* opt) {
return static_cast<int>(opt->rep.io_activity);
}
@@ -1,165 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/auto_simple_bindings.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Sources:
// - include/rocksdb/options.h
// - tools/c_api_gen/auto_simple_bindings_blocklist.json
// - include/rocksdb/c.h
// - tools/c_api_gen/c_base.cc
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/auto_simple_bindings.py
// Output group: Auto-discovered ReadOptions simple
/* ReadOptions */
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_deadline(
rocksdb_readoptions_t* opt, uint64_t microseconds);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_readoptions_get_deadline(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_io_timeout(
rocksdb_readoptions_t* opt, uint64_t microseconds);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_readoptions_get_io_timeout(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_read_tier(
rocksdb_readoptions_t* opt, int v);
extern ROCKSDB_LIBRARY_API int rocksdb_readoptions_get_read_tier(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_rate_limiter_priority(
rocksdb_readoptions_t* opt, int v);
extern ROCKSDB_LIBRARY_API int rocksdb_readoptions_get_rate_limiter_priority(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_value_size_soft_limit(
rocksdb_readoptions_t* opt, uint64_t v);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_readoptions_get_value_size_soft_limit(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_verify_checksums(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_verify_checksums(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_fill_cache(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_readoptions_get_fill_cache(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_ignore_range_deletions(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_ignore_range_deletions(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_async_io(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_readoptions_get_async_io(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_readoptions_set_optimize_multiget_for_io(rocksdb_readoptions_t* opt,
unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_optimize_multiget_for_io(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_readahead_size(
rocksdb_readoptions_t* opt, size_t v);
extern ROCKSDB_LIBRARY_API size_t
rocksdb_readoptions_get_readahead_size(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_readoptions_set_max_skippable_internal_keys(rocksdb_readoptions_t* opt,
uint64_t v);
extern ROCKSDB_LIBRARY_API uint64_t
rocksdb_readoptions_get_max_skippable_internal_keys(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_tailing(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_readoptions_get_tailing(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_total_order_seek(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_total_order_seek(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_auto_prefix_mode(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_auto_prefix_mode(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_prefix_same_as_start(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_prefix_same_as_start(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_pin_data(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char rocksdb_readoptions_get_pin_data(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_adaptive_readahead(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_adaptive_readahead(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_readoptions_set_background_purge_on_iterator_cleanup(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_background_purge_on_iterator_cleanup(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_auto_readahead_size(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_auto_readahead_size(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_allow_unprepared_value(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_allow_unprepared_value(rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void
rocksdb_readoptions_set_auto_refresh_iterator_with_snapshot(
rocksdb_readoptions_t* opt, unsigned char v);
extern ROCKSDB_LIBRARY_API unsigned char
rocksdb_readoptions_get_auto_refresh_iterator_with_snapshot(
rocksdb_readoptions_t* opt);
extern ROCKSDB_LIBRARY_API void rocksdb_readoptions_set_io_activity(
rocksdb_readoptions_t* opt, int v);
extern ROCKSDB_LIBRARY_API int rocksdb_readoptions_get_io_activity(
rocksdb_readoptions_t* opt);
File diff suppressed because it is too large. Load diff
-375
View File
@@ -1,375 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'DB data operations'
// --section 'WriteBatch' --section 'Transaction'
// --section 'TransactionDB simple'
// --header-out
// c_api_gen/c_generated_subset.h.inc
// --source-out
// c_api_gen/c_generated_subset.cc.inc
/* DB data operations */
void rocksdb_put(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr,
db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_put_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Put(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_delete(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen)));
}
void rocksdb_delete_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_merge(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Merge(options->rep, Slice(key, keylen),
Slice(val, vallen)));
}
void rocksdb_merge_cf(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* val,
size_t vallen, char** errptr) {
SaveError(errptr, db->rep->Merge(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_write(rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr) {
SaveError(errptr, db->rep->Write(options->rep, &batch->rep));
}
void rocksdb_put_with_ts(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* ts,
size_t tslen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr, db->rep->Put(options->rep, Slice(key, keylen),
Slice(ts, tslen), Slice(val, vallen)));
}
void rocksdb_put_cf_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* ts,
size_t tslen, const char* val, size_t vallen,
char** errptr) {
SaveError(errptr,
db->rep->Put(options->rep, column_family->rep, Slice(key, keylen),
Slice(ts, tslen), Slice(val, vallen)));
}
void rocksdb_delete_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, const char* ts,
size_t tslen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen),
Slice(ts, tslen)));
}
void rocksdb_delete_cf_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, const char* ts,
size_t tslen, char** errptr) {
SaveError(errptr, db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen), Slice(ts, tslen)));
}
void rocksdb_singledelete(rocksdb_t* db, const rocksdb_writeoptions_t* options,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, Slice(key, keylen)));
}
void rocksdb_singledelete_cf(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_singledelete_with_ts(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
const char* key, size_t keylen,
const char* ts, size_t tslen, char** errptr) {
SaveError(errptr, db->rep->SingleDelete(options->rep, Slice(key, keylen),
Slice(ts, tslen)));
}
void rocksdb_singledelete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr) {
SaveError(errptr,
db->rep->SingleDelete(options->rep, column_family->rep,
Slice(key, keylen), Slice(ts, tslen)));
}
void rocksdb_delete_range_cf(rocksdb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* start_key, size_t start_key_len,
const char* end_key, size_t end_key_len,
char** errptr) {
SaveError(errptr, db->rep->DeleteRange(options->rep, column_family->rep,
Slice(start_key, start_key_len),
Slice(end_key, end_key_len)));
}
void rocksdb_flush(rocksdb_t* db, const rocksdb_flushoptions_t* options,
char** errptr) {
SaveError(errptr, db->rep->Flush(options->rep));
}
void rocksdb_flush_cf(rocksdb_t* db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family,
char** errptr) {
SaveError(errptr, db->rep->Flush(options->rep, column_family->rep));
}
void rocksdb_flush_wal(rocksdb_t* db, unsigned char sync, char** errptr) {
SaveError(errptr, db->rep->FlushWAL(sync));
}
void rocksdb_pause_background_work(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->PauseBackgroundWork());
}
void rocksdb_continue_background_work(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->ContinueBackgroundWork());
}
void rocksdb_disable_file_deletions(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->DisableFileDeletions());
}
void rocksdb_enable_file_deletions(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->EnableFileDeletions());
}
void rocksdb_verify_checksum(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->VerifyChecksum());
}
void rocksdb_verify_file_checksums(rocksdb_t* db, char** errptr) {
SaveError(errptr, db->rep->VerifyFileChecksums(ReadOptions()));
}
void rocksdb_destroy_db(const rocksdb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, DestroyDB(name, options->rep));
}
void rocksdb_repair_db(const rocksdb_options_t* options, const char* name,
char** errptr) {
SaveError(errptr, RepairDB(name, options->rep));
}
/* WriteBatch */
void rocksdb_writebatch_clear(rocksdb_writebatch_t* b) { b->rep.Clear(); }
void rocksdb_writebatch_put(rocksdb_writebatch_t* b, const char* key,
size_t klen, const char* val, size_t vlen) {
b->rep.Put(Slice(key, klen), Slice(val, vlen));
}
void rocksdb_writebatch_put_cf(rocksdb_writebatch_t* b,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen) {
b->rep.Put(column_family->rep, Slice(key, klen), Slice(val, vlen));
}
void rocksdb_writebatch_delete(rocksdb_writebatch_t* b, const char* key,
size_t klen) {
b->rep.Delete(Slice(key, klen));
}
void rocksdb_writebatch_put_log_data(rocksdb_writebatch_t* b, const char* blob,
size_t len) {
b->rep.PutLogData(Slice(blob, len));
}
void rocksdb_writebatch_set_save_point(rocksdb_writebatch_t* b) {
b->rep.SetSavePoint();
}
void rocksdb_writebatch_rollback_to_save_point(rocksdb_writebatch_t* b,
char** errptr) {
SaveError(errptr, b->rep.RollbackToSavePoint());
}
void rocksdb_writebatch_pop_save_point(rocksdb_writebatch_t* b, char** errptr) {
SaveError(errptr, b->rep.PopSavePoint());
}
void rocksdb_writebatch_verify_checksum(rocksdb_writebatch_t* b,
char** errptr) {
SaveError(errptr, b->rep.VerifyChecksum());
}
/* Transaction */
void rocksdb_transaction_put(rocksdb_transaction_t* txn, const char* key,
size_t klen, const char* val, size_t vlen,
char** errptr) {
SaveError(errptr, txn->rep->Put(Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transaction_put_cf(rocksdb_transaction_t* txn,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn->rep->Put(column_family->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transaction_merge(rocksdb_transaction_t* txn, const char* key,
size_t klen, const char* val, size_t vlen,
char** errptr) {
SaveError(errptr, txn->rep->Merge(Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transaction_merge_cf(rocksdb_transaction_t* txn,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn->rep->Merge(column_family->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transaction_delete(rocksdb_transaction_t* txn, const char* key,
size_t klen, char** errptr) {
SaveError(errptr, txn->rep->Delete(Slice(key, klen)));
}
void rocksdb_transaction_delete_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, char** errptr) {
SaveError(errptr, txn->rep->Delete(column_family->rep, Slice(key, klen)));
}
void rocksdb_transaction_commit(rocksdb_transaction_t* txn, char** errptr) {
SaveError(errptr, txn->rep->Commit());
}
void rocksdb_transaction_rollback(rocksdb_transaction_t* txn, char** errptr) {
SaveError(errptr, txn->rep->Rollback());
}
void rocksdb_transaction_put_log_data(rocksdb_transaction_t* txn,
const char* blob, size_t len) {
txn->rep->PutLogData(Slice(blob, len));
}
void rocksdb_transaction_set_savepoint(rocksdb_transaction_t* txn) {
txn->rep->SetSavePoint();
}
void rocksdb_transaction_rollback_to_savepoint(rocksdb_transaction_t* txn,
char** errptr) {
SaveError(errptr, txn->rep->RollbackToSavePoint());
}
/* TransactionDB simple */
void rocksdb_transactiondb_put(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr,
txn_db->rep->Put(options->rep, Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transactiondb_put_cf(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen,
const char* val, size_t vallen,
char** errptr) {
SaveError(errptr, txn_db->rep->Put(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_transactiondb_write(rocksdb_transactiondb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr) {
SaveError(errptr, db->rep->Write(options->rep, &batch->rep));
}
void rocksdb_transactiondb_merge(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn_db->rep->Merge(options->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transactiondb_merge_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key, size_t klen,
const char* val, size_t vlen, char** errptr) {
SaveError(errptr, txn_db->rep->Merge(options->rep, column_family->rep,
Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transactiondb_delete(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, char** errptr) {
SaveError(errptr, txn_db->rep->Delete(options->rep, Slice(key, klen)));
}
void rocksdb_transactiondb_delete_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr) {
SaveError(errptr, txn_db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_transactiondb_flush_wal(rocksdb_transactiondb_t* txn_db,
unsigned char sync, char** errptr) {
SaveError(errptr, txn_db->rep->FlushWAL(sync));
}
void rocksdb_transactiondb_flush(rocksdb_transactiondb_t* txn_db,
const rocksdb_flushoptions_t* options,
char** errptr) {
SaveError(errptr, txn_db->rep->Flush(options->rep));
}
void rocksdb_transactiondb_flush_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr) {
SaveError(errptr, txn_db->rep->Flush(options->rep, column_family->rep));
}
-249
View File
@@ -1,249 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'DB data operations'
// --section 'WriteBatch' --section 'Transaction'
// --section 'TransactionDB simple'
// --header-out
// c_api_gen/c_generated_subset.h.inc
// --source-out
// c_api_gen/c_generated_subset.cc.inc
/* DB data operations */
extern ROCKSDB_LIBRARY_API void rocksdb_put(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_merge(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_merge_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_write(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, const char* val, size_t vallen,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_put_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, const char* val, size_t vallen,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_singledelete_cf_with_ts(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* ts, size_t tslen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_delete_range_cf(
rocksdb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* start_key,
size_t start_key_len, const char* end_key, size_t end_key_len,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush(
rocksdb_t* db, const rocksdb_flushoptions_t* options, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush_cf(
rocksdb_t* db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_flush_wal(rocksdb_t* db,
unsigned char sync,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_pause_background_work(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_continue_background_work(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_disable_file_deletions(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_enable_file_deletions(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_verify_checksum(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_verify_file_checksums(rocksdb_t* db,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_destroy_db(
const rocksdb_options_t* options, const char* name, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_repair_db(
const rocksdb_options_t* options, const char* name, char** errptr);
/* WriteBatch */
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_clear(
rocksdb_writebatch_t* b);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put(rocksdb_writebatch_t* b,
const char* key,
size_t klen,
const char* val,
size_t vlen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put_cf(
rocksdb_writebatch_t* b, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_delete(
rocksdb_writebatch_t* b, const char* key, size_t klen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put_log_data(
rocksdb_writebatch_t* b, const char* blob, size_t len);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_set_save_point(
rocksdb_writebatch_t* b);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_rollback_to_save_point(
rocksdb_writebatch_t* b, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_pop_save_point(
rocksdb_writebatch_t* b, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_verify_checksum(
rocksdb_writebatch_t* b, char** errptr);
/* Transaction */
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put(
rocksdb_transaction_t* txn, const char* key, size_t klen, const char* val,
size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_merge(
rocksdb_transaction_t* txn, const char* key, size_t klen, const char* val,
size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_merge_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_delete(
rocksdb_transaction_t* txn, const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_delete_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_commit(
rocksdb_transaction_t* txn, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_rollback(
rocksdb_transaction_t* txn, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put_log_data(
rocksdb_transaction_t* txn, const char* blob, size_t len);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_set_savepoint(
rocksdb_transaction_t* txn);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_rollback_to_savepoint(
rocksdb_transaction_t* txn, char** errptr);
/* TransactionDB simple */
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_put(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_put_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_write(
rocksdb_transactiondb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_merge(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_merge_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key, size_t klen,
const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_delete(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_delete_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush_wal(
rocksdb_transactiondb_t* txn_db, unsigned char sync, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr);
@@ -1,81 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'Transaction'
// --header-out
// c_api_gen/c_generated_transaction_subset.h.inc
// --source-out
// c_api_gen/c_generated_transaction_subset.cc.inc
/* Transaction */
void rocksdb_transaction_put(rocksdb_transaction_t* txn, const char* key,
size_t klen, const char* val, size_t vlen,
char** errptr) {
SaveError(errptr, txn->rep->Put(Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transaction_put_cf(rocksdb_transaction_t* txn,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn->rep->Put(column_family->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transaction_merge(rocksdb_transaction_t* txn, const char* key,
size_t klen, const char* val, size_t vlen,
char** errptr) {
SaveError(errptr, txn->rep->Merge(Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transaction_merge_cf(rocksdb_transaction_t* txn,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn->rep->Merge(column_family->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transaction_delete(rocksdb_transaction_t* txn, const char* key,
size_t klen, char** errptr) {
SaveError(errptr, txn->rep->Delete(Slice(key, klen)));
}
void rocksdb_transaction_delete_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, char** errptr) {
SaveError(errptr, txn->rep->Delete(column_family->rep, Slice(key, klen)));
}
void rocksdb_transaction_commit(rocksdb_transaction_t* txn, char** errptr) {
SaveError(errptr, txn->rep->Commit());
}
void rocksdb_transaction_rollback(rocksdb_transaction_t* txn, char** errptr) {
SaveError(errptr, txn->rep->Rollback());
}
void rocksdb_transaction_put_log_data(rocksdb_transaction_t* txn,
const char* blob, size_t len) {
txn->rep->PutLogData(Slice(blob, len));
}
void rocksdb_transaction_set_savepoint(rocksdb_transaction_t* txn) {
txn->rep->SetSavePoint();
}
void rocksdb_transaction_rollback_to_savepoint(rocksdb_transaction_t* txn,
char** errptr) {
SaveError(errptr, txn->rep->RollbackToSavePoint());
}
@@ -1,58 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'Transaction'
// --header-out
// c_api_gen/c_generated_transaction_subset.h.inc
// --source-out
// c_api_gen/c_generated_transaction_subset.cc.inc
/* Transaction */
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put(
rocksdb_transaction_t* txn, const char* key, size_t klen, const char* val,
size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_merge(
rocksdb_transaction_t* txn, const char* key, size_t klen, const char* val,
size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_merge_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_delete(
rocksdb_transaction_t* txn, const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_delete_cf(
rocksdb_transaction_t* txn, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_commit(
rocksdb_transaction_t* txn, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_rollback(
rocksdb_transaction_t* txn, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_put_log_data(
rocksdb_transaction_t* txn, const char* blob, size_t len);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_set_savepoint(
rocksdb_transaction_t* txn);
extern ROCKSDB_LIBRARY_API void rocksdb_transaction_rollback_to_savepoint(
rocksdb_transaction_t* txn, char** errptr);
@@ -1,91 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'TransactionDB simple'
// --header-out
// c_api_gen/c_generated_transactiondb_subset.h.inc
// --source-out
// c_api_gen/c_generated_transactiondb_subset.cc.inc
/* TransactionDB simple */
void rocksdb_transactiondb_put(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr,
txn_db->rep->Put(options->rep, Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transactiondb_put_cf(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t keylen,
const char* val, size_t vallen,
char** errptr) {
SaveError(errptr, txn_db->rep->Put(options->rep, column_family->rep,
Slice(key, keylen), Slice(val, vallen)));
}
void rocksdb_transactiondb_write(rocksdb_transactiondb_t* db,
const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr) {
SaveError(errptr, db->rep->Write(options->rep, &batch->rep));
}
void rocksdb_transactiondb_merge(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val,
size_t vlen, char** errptr) {
SaveError(errptr, txn_db->rep->Merge(options->rep, Slice(key, klen),
Slice(val, vlen)));
}
void rocksdb_transactiondb_merge_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key, size_t klen,
const char* val, size_t vlen, char** errptr) {
SaveError(errptr, txn_db->rep->Merge(options->rep, column_family->rep,
Slice(key, klen), Slice(val, vlen)));
}
void rocksdb_transactiondb_delete(rocksdb_transactiondb_t* txn_db,
const rocksdb_writeoptions_t* options,
const char* key, size_t klen, char** errptr) {
SaveError(errptr, txn_db->rep->Delete(options->rep, Slice(key, klen)));
}
void rocksdb_transactiondb_delete_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr) {
SaveError(errptr, txn_db->rep->Delete(options->rep, column_family->rep,
Slice(key, keylen)));
}
void rocksdb_transactiondb_flush_wal(rocksdb_transactiondb_t* txn_db,
unsigned char sync, char** errptr) {
SaveError(errptr, txn_db->rep->FlushWAL(sync));
}
void rocksdb_transactiondb_flush(rocksdb_transactiondb_t* txn_db,
const rocksdb_flushoptions_t* options,
char** errptr) {
SaveError(errptr, txn_db->rep->Flush(options->rep));
}
void rocksdb_transactiondb_flush_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr) {
SaveError(errptr, txn_db->rep->Flush(options->rep, column_family->rep));
}
@@ -1,62 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'TransactionDB simple'
// --header-out
// c_api_gen/c_generated_transactiondb_subset.h.inc
// --source-out
// c_api_gen/c_generated_transactiondb_subset.cc.inc
/* TransactionDB simple */
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_put(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_put_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, const char* val, size_t vallen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_write(
rocksdb_transactiondb_t* db, const rocksdb_writeoptions_t* options,
rocksdb_writebatch_t* batch, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_merge(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_merge_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key, size_t klen,
const char* val, size_t vlen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_delete(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
const char* key, size_t klen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_delete_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_writeoptions_t* options,
rocksdb_column_family_handle_t* column_family, const char* key,
size_t keylen, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush_wal(
rocksdb_transactiondb_t* txn_db, unsigned char sync, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_transactiondb_flush_cf(
rocksdb_transactiondb_t* txn_db, const rocksdb_flushoptions_t* options,
rocksdb_column_family_handle_t* column_family, char** errptr);
@@ -1,62 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'WriteBatch'
// --header-out
// c_api_gen/c_generated_writebatch_subset.h.inc
// --source-out
// c_api_gen/c_generated_writebatch_subset.cc.inc
/* WriteBatch */
void rocksdb_writebatch_clear(rocksdb_writebatch_t* b) { b->rep.Clear(); }
void rocksdb_writebatch_put(rocksdb_writebatch_t* b, const char* key,
size_t klen, const char* val, size_t vlen) {
b->rep.Put(Slice(key, klen), Slice(val, vlen));
}
void rocksdb_writebatch_put_cf(rocksdb_writebatch_t* b,
rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val,
size_t vlen) {
b->rep.Put(column_family->rep, Slice(key, klen), Slice(val, vlen));
}
void rocksdb_writebatch_delete(rocksdb_writebatch_t* b, const char* key,
size_t klen) {
b->rep.Delete(Slice(key, klen));
}
void rocksdb_writebatch_put_log_data(rocksdb_writebatch_t* b, const char* blob,
size_t len) {
b->rep.PutLogData(Slice(blob, len));
}
void rocksdb_writebatch_set_save_point(rocksdb_writebatch_t* b) {
b->rep.SetSavePoint();
}
void rocksdb_writebatch_rollback_to_save_point(rocksdb_writebatch_t* b,
char** errptr) {
SaveError(errptr, b->rep.RollbackToSavePoint());
}
void rocksdb_writebatch_pop_save_point(rocksdb_writebatch_t* b, char** errptr) {
SaveError(errptr, b->rep.PopSavePoint());
}
void rocksdb_writebatch_verify_checksum(rocksdb_writebatch_t* b,
char** errptr) {
SaveError(errptr, b->rep.VerifyChecksum());
}
@@ -1,51 +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).
// @generated
// -----------------------------------------------------------------------------
// Auto-generated by tools/c_api_gen/generate_c_api.py.
// DO NOT EDIT THIS FILE DIRECTLY.
// Source: tools/c_api_gen/spec.json
// -----------------------------------------------------------------------------
// To regenerate this file:
// python3 tools/c_api_gen/generate_c_api.py
// --spec tools/c_api_gen/spec.json --section 'WriteBatch'
// --header-out
// c_api_gen/c_generated_writebatch_subset.h.inc
// --source-out
// c_api_gen/c_generated_writebatch_subset.cc.inc
/* WriteBatch */
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_clear(
rocksdb_writebatch_t* b);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put(rocksdb_writebatch_t* b,
const char* key,
size_t klen,
const char* val,
size_t vlen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put_cf(
rocksdb_writebatch_t* b, rocksdb_column_family_handle_t* column_family,
const char* key, size_t klen, const char* val, size_t vlen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_delete(
rocksdb_writebatch_t* b, const char* key, size_t klen);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_put_log_data(
rocksdb_writebatch_t* b, const char* blob, size_t len);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_set_save_point(
rocksdb_writebatch_t* b);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_rollback_to_save_point(
rocksdb_writebatch_t* b, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_pop_save_point(
rocksdb_writebatch_t* b, char** errptr);
extern ROCKSDB_LIBRARY_API void rocksdb_writebatch_verify_checksum(
rocksdb_writebatch_t* b, char** errptr);
+5
View File
@@ -54,6 +54,11 @@ static std::unordered_map<std::string, OptionTypeInfo>
{offsetof(struct CompressedSecondaryCacheOptions, compression_type),
OptionType::kCompressionType, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
{"compress_format_version",
{offsetof(struct CompressedSecondaryCacheOptions,
compress_format_version),
OptionType::kUInt32T, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
{"enable_custom_split_merge",
{offsetof(struct CompressedSecondaryCacheOptions,
enable_custom_split_merge),
+9 -9
View File
@@ -101,23 +101,23 @@ class CacheEntryStatsCollector {
}
// Gets saved stats, regardless of age
void GetStats(Stats* stats) {
void GetStats(Stats *stats) {
std::lock_guard<std::mutex> lock(saved_mutex_);
*stats = saved_stats_;
}
Cache* GetCache() const { return cache_; }
Cache *GetCache() const { return cache_; }
// Gets or creates a shared instance of CacheEntryStatsCollector in the
// cache itself, and saves into `ptr`. This shared_ptr will hold the
// entry in cache until all refs are destroyed.
static Status GetShared(Cache* raw_cache, SystemClock* clock,
std::shared_ptr<CacheEntryStatsCollector>* ptr) {
static Status GetShared(Cache *raw_cache, SystemClock *clock,
std::shared_ptr<CacheEntryStatsCollector> *ptr) {
assert(raw_cache);
BasicTypedCacheInterface<CacheEntryStatsCollector, CacheEntryRole::kMisc>
cache{raw_cache};
const Slice& cache_key = GetCacheKey();
const Slice &cache_key = GetCacheKey();
auto h = cache.Lookup(cache_key);
if (h == nullptr) {
// Not yet in cache, but Cache doesn't provide a built-in way to
@@ -152,7 +152,7 @@ class CacheEntryStatsCollector {
}
private:
explicit CacheEntryStatsCollector(Cache* cache, SystemClock* clock)
explicit CacheEntryStatsCollector(Cache *cache, SystemClock *clock)
: saved_stats_(),
working_stats_(),
last_start_time_micros_(0),
@@ -160,7 +160,7 @@ class CacheEntryStatsCollector {
cache_(cache),
clock_(clock) {}
static const Slice& GetCacheKey() {
static const Slice &GetCacheKey() {
// For each template instantiation
static CacheKey ckey = CacheKey::CreateUniqueForProcessLifetime();
static Slice ckey_slice = ckey.AsSlice();
@@ -175,8 +175,8 @@ class CacheEntryStatsCollector {
uint64_t last_start_time_micros_;
uint64_t last_end_time_micros_;
Cache* const cache_;
SystemClock* const clock_;
Cache *const cache_;
SystemClock *const clock_;
};
} // namespace ROCKSDB_NAMESPACE
+3 -3
View File
@@ -24,7 +24,7 @@ namespace ROCKSDB_NAMESPACE {
// 0 | >= 1<<63 | CreateUniqueForProcessLifetime
// > 0 | any | OffsetableCacheKey.WithOffset
CacheKey CacheKey::CreateUniqueForCacheLifetime(Cache* cache) {
CacheKey CacheKey::CreateUniqueForCacheLifetime(Cache *cache) {
// +1 so that we can reserve all zeros for "unset" cache key
uint64_t id = cache->NewId() + 1;
// Ensure we don't collide with CreateUniqueForProcessLifetime
@@ -297,8 +297,8 @@ CacheKey CacheKey::CreateUniqueForProcessLifetime() {
//
// TODO: Nevertheless / regardless, an efficient way to detect (and thus
// quantify) block cache corruptions, including collisions, should be added.
OffsetableCacheKey::OffsetableCacheKey(const std::string& db_id,
const std::string& db_session_id,
OffsetableCacheKey::OffsetableCacheKey(const std::string &db_id,
const std::string &db_session_id,
uint64_t file_number) {
UniqueId64x2 internal_id;
Status s = GetSstInternalUniqueId(db_id, db_session_id, file_number,
+5 -23
View File
@@ -44,13 +44,13 @@ class CacheKey {
inline Slice AsSlice() const {
static_assert(sizeof(*this) == 16, "Standardized on 16-byte cache key");
assert(!IsEmpty());
return Slice(reinterpret_cast<const char*>(this), sizeof(*this));
return Slice(reinterpret_cast<const char *>(this), sizeof(*this));
}
// Create a CacheKey that is unique among others associated with this Cache
// instance. Depends on Cache::NewId. This is useful for block cache
// "reservations".
static CacheKey CreateUniqueForCacheLifetime(Cache* cache);
static CacheKey CreateUniqueForCacheLifetime(Cache *cache);
// Create a CacheKey that is unique among others for the lifetime of this
// process. This is useful for saving in a static data member so that
@@ -87,7 +87,7 @@ class OffsetableCacheKey : private CacheKey {
// Constructs an OffsetableCacheKey with the given information about a file.
// This constructor never generates an "empty" base key.
OffsetableCacheKey(const std::string& db_id, const std::string& db_session_id,
OffsetableCacheKey(const std::string &db_id, const std::string &db_session_id,
uint64_t file_number);
// Creates an OffsetableCacheKey from an SST unique ID, so that cache keys
@@ -127,24 +127,6 @@ class OffsetableCacheKey : private CacheKey {
return CacheKey(file_num_etc64_, offset_etc64_ ^ offset);
}
// Construct a CacheKey for a record located at byte `offset` within a file in
// which every distinct cached region is at least 5 bytes long. The low two
// offset bits are dropped, which is collision-free under that >= 5-byte (>= 4
// would suffice) guarantee and lets different kinds of records in the same
// file share a single keyspace without colliding.
//
// This is the canonical cache-key scheme for byte-offset records that carry
// the block-based "min 5 byte" guarantee: block-based SST blocks (see
// BlockBasedTable::GetCacheKey) and SimpleGen2Blob records (which always
// include a >= 5-byte trailer; see db/blob/blob_gen2_format.h). Because both
// use this same function, an SST's data blocks and its embedded blob records
// never collide even when the block cache and blob cache are the same cache.
// Keeping a single implementation here avoids a divergence bug that would
// silently alias the two keyspaces.
inline CacheKey WithOffsetForMinSizeRecord(uint64_t offset) const {
return WithOffset(offset >> 2);
}
// The "common prefix" is a shared prefix for all the returned CacheKeys.
// It is specific to the file but the same for all offsets within the file.
static constexpr size_t kCommonPrefixSize = 8;
@@ -152,9 +134,9 @@ class OffsetableCacheKey : private CacheKey {
static_assert(sizeof(file_num_etc64_) == kCommonPrefixSize,
"8 byte common prefix expected");
assert(!IsEmpty());
assert(&this->file_num_etc64_ == static_cast<const void*>(this));
assert(&this->file_num_etc64_ == static_cast<const void *>(this));
return Slice(reinterpret_cast<const char*>(this), kCommonPrefixSize);
return Slice(reinterpret_cast<const char *>(this), kCommonPrefixSize);
}
};
+16 -16
View File
@@ -44,8 +44,8 @@ class CacheReservationManager {
bool increase) = 0;
virtual Status MakeCacheReservation(
std::size_t incremental_memory_used,
std::unique_ptr<CacheReservationManager::CacheReservationHandle>*
handle) = 0;
std::unique_ptr<CacheReservationManager::CacheReservationHandle>
*handle) = 0;
virtual std::size_t GetTotalReservedCacheSize() = 0;
virtual std::size_t GetTotalMemoryUsed() = 0;
};
@@ -90,11 +90,11 @@ class CacheReservationManagerImpl
bool delayed_decrease = false);
// no copy constructor, copy assignment, move constructor, move assignment
CacheReservationManagerImpl(const CacheReservationManagerImpl&) = delete;
CacheReservationManagerImpl& operator=(const CacheReservationManagerImpl&) =
CacheReservationManagerImpl(const CacheReservationManagerImpl &) = delete;
CacheReservationManagerImpl &operator=(const CacheReservationManagerImpl &) =
delete;
CacheReservationManagerImpl(CacheReservationManagerImpl&&) = delete;
CacheReservationManagerImpl& operator=(CacheReservationManagerImpl&&) =
CacheReservationManagerImpl(CacheReservationManagerImpl &&) = delete;
CacheReservationManagerImpl &operator=(CacheReservationManagerImpl &&) =
delete;
~CacheReservationManagerImpl() override;
@@ -178,7 +178,7 @@ class CacheReservationManagerImpl
// REQUIRES: handle != nullptr
Status MakeCacheReservation(
std::size_t incremental_memory_used,
std::unique_ptr<CacheReservationManager::CacheReservationHandle>* handle)
std::unique_ptr<CacheReservationManager::CacheReservationHandle> *handle)
override;
// Return the size of the cache (which is a multiple of kSizeDummyEntry)
@@ -200,7 +200,7 @@ class CacheReservationManagerImpl
// For testing only - it is to help ensure the CacheItemHelperForRole<R>
// accessed from CacheReservationManagerImpl and the one accessed from the
// test are from the same translation units
static const Cache::CacheItemHelper* TEST_GetCacheItemHelperForRole();
static const Cache::CacheItemHelper *TEST_GetCacheItemHelperForRole();
private:
static constexpr std::size_t kSizeDummyEntry = 256 * 1024;
@@ -216,7 +216,7 @@ class CacheReservationManagerImpl
bool delayed_decrease_;
std::atomic<std::size_t> cache_allocated_size_;
std::size_t memory_used_;
std::vector<Cache::Handle*> dummy_handles_;
std::vector<Cache::Handle *> dummy_handles_;
CacheKey cache_key_;
};
@@ -251,14 +251,14 @@ class ConcurrentCacheReservationManager
std::shared_ptr<CacheReservationManager> cache_res_mgr) {
cache_res_mgr_ = std::move(cache_res_mgr);
}
ConcurrentCacheReservationManager(const ConcurrentCacheReservationManager&) =
ConcurrentCacheReservationManager(const ConcurrentCacheReservationManager &) =
delete;
ConcurrentCacheReservationManager& operator=(
const ConcurrentCacheReservationManager&) = delete;
ConcurrentCacheReservationManager(ConcurrentCacheReservationManager&&) =
ConcurrentCacheReservationManager &operator=(
const ConcurrentCacheReservationManager &) = delete;
ConcurrentCacheReservationManager(ConcurrentCacheReservationManager &&) =
delete;
ConcurrentCacheReservationManager& operator=(
ConcurrentCacheReservationManager&&) = delete;
ConcurrentCacheReservationManager &operator=(
ConcurrentCacheReservationManager &&) = delete;
~ConcurrentCacheReservationManager() override {}
@@ -286,7 +286,7 @@ class ConcurrentCacheReservationManager
inline Status MakeCacheReservation(
std::size_t incremental_memory_used,
std::unique_ptr<CacheReservationManager::CacheReservationHandle>* handle)
std::unique_ptr<CacheReservationManager::CacheReservationHandle> *handle)
override {
std::unique_ptr<CacheReservationManager::CacheReservationHandle>
wrapped_handle;
+1 -1
View File
@@ -644,7 +644,7 @@ using TypedHandle = SharedCache::TypedHandle;
TEST_P(CacheTest, SetCapacity) {
if (IsHyperClock()) {
// TODO: update test & code for limited support
// TODO: update test & code for limited supoort
ROCKSDB_GTEST_BYPASS(
"HyperClockCache doesn't support arbitrary capacity "
"adjustments.");
+414 -355
View File
File diff suppressed because it is too large. Load diff
+69 -135
View File
@@ -317,89 +317,40 @@ struct ClockHandle : public ClockHandleBasicData {
// | acquire counter | release counter | hit bit | state marker |
// -----------------------------------------------------------------------
struct SlotMeta : public BitFields<uint64_t, SlotMeta> {
// For reading or updating counters in meta word.
static constexpr uint8_t kCounterNumBits = 30;
// Number of times the a reference has been acquired (or attempted)
// since last reset by eviction processing
using AcquireCounter =
UnsignedBitField<SlotMeta, kCounterNumBits, NoPrevBitField>;
// Number of times the a reference has been released (or attempted)
// since last reset by eviction processing
using ReleaseCounter =
UnsignedBitField<SlotMeta, kCounterNumBits, AcquireCounter>;
// Metadata bit in support of secondary cache
using HitFlag = BoolBitField<SlotMeta, ReleaseCounter>;
// Occupied means any state other than empty
using OccupiedFlag = BoolBitField<SlotMeta, HitFlag>;
// Shareable means the entry is reference counted (visible or invisible)
// (only set if also occupied)
using ShareableFlag = BoolBitField<SlotMeta, OccupiedFlag>;
// Visible is only set if also shareable (invisible can't be found by
// Lookup)
using VisibleFlag = BoolBitField<SlotMeta, ShareableFlag>;
// For reading or updating counters in meta word.
static constexpr uint8_t kCounterNumBits = 30;
static constexpr uint64_t kCounterMask = (uint64_t{1} << kCounterNumBits) - 1;
// Convenience functions
uint32_t GetAcquireCounter() const { return Get<AcquireCounter>(); }
void SetAcquireCounter(uint32_t val) { Set<AcquireCounter>(val); }
uint32_t GetReleaseCounter() const { return Get<ReleaseCounter>(); }
void SetReleaseCounter(uint32_t val) { Set<ReleaseCounter>(val); }
uint32_t GetRefcount() const {
return Get<AcquireCounter>() - Get<ReleaseCounter>();
}
bool GetHit() const { return Get<HitFlag>(); }
void SetHit(bool val) { Set<HitFlag>(val); }
static constexpr uint8_t kAcquireCounterShift = 0;
static constexpr uint64_t kAcquireIncrement = uint64_t{1}
<< kAcquireCounterShift;
static constexpr uint8_t kReleaseCounterShift = kCounterNumBits;
static constexpr uint64_t kReleaseIncrement = uint64_t{1}
<< kReleaseCounterShift;
// Some distinct states for the various state flags
bool IsEmpty() const {
bool rv = !Get<OccupiedFlag>();
if (rv) {
assert(!Get<ShareableFlag>());
assert(!Get<VisibleFlag>());
}
return rv;
}
// For setting the hit bit
static constexpr uint8_t kHitBitShift = 2U * kCounterNumBits;
static constexpr uint64_t kHitBitMask = uint64_t{1} << kHitBitShift;
bool IsUnderConstruction() const {
bool rv = Get<OccupiedFlag>() && !Get<ShareableFlag>();
if (rv) {
assert(!Get<VisibleFlag>());
}
return rv;
}
void SetUnderConstruction() {
Set<OccupiedFlag>(true);
Set<ShareableFlag>(false);
Set<VisibleFlag>(false);
}
// For reading or updating the state marker in meta word
static constexpr uint8_t kStateShift = kHitBitShift + 1;
bool IsShareable() const { return Get<ShareableFlag>(); }
bool IsInvisible() const {
bool rv = Get<ShareableFlag>() && !Get<VisibleFlag>();
if (rv) {
assert(Get<OccupiedFlag>());
}
return rv;
}
void SetInvisible() {
Set<OccupiedFlag>(true);
Set<ShareableFlag>(true);
Set<VisibleFlag>(false);
}
// Bits contribution to state marker.
// Occupied means any state other than empty
static constexpr uint8_t kStateOccupiedBit = 0b100;
// Shareable means the entry is reference counted (visible or invisible)
// (only set if also occupied)
static constexpr uint8_t kStateShareableBit = 0b010;
// Visible is only set if also shareable
static constexpr uint8_t kStateVisibleBit = 0b001;
bool IsVisible() const {
bool rv = Get<ShareableFlag>() && Get<VisibleFlag>();
if (rv) {
assert(Get<OccupiedFlag>());
}
return rv;
}
void SetVisible() {
Set<OccupiedFlag>(true);
Set<ShareableFlag>(true);
Set<VisibleFlag>(true);
}
};
// Complete state markers (not shifted into full word)
static constexpr uint8_t kStateEmpty = 0b000;
static constexpr uint8_t kStateConstruction = kStateOccupiedBit;
static constexpr uint8_t kStateInvisible =
kStateOccupiedBit | kStateShareableBit;
static constexpr uint8_t kStateVisible =
kStateOccupiedBit | kStateShareableBit | kStateVisibleBit;
// Constants for initializing the countdown clock. (Countdown clock is only
// in effect with zero refs, acquire counter == release counter, and in that
@@ -413,7 +364,7 @@ struct ClockHandle : public ClockHandleBasicData {
// TODO: make these coundown values tuning parameters for eviction?
// See above. Mutable for read reference counting.
mutable BitFieldsAtomic<SlotMeta> meta{};
mutable AcqRelAtomic<uint64_t> meta{};
}; // struct ClockHandle
class BaseClockTable {
@@ -480,9 +431,9 @@ class BaseClockTable {
bool IsEvictionEffortExceeded(const BaseClockTable::EvictionData& data) const;
#ifndef NDEBUG
// Acquire N references
void TEST_RefN(ClockHandle& handle, uint32_t n);
void TEST_RefN(ClockHandle& handle, size_t n);
// Helper for TEST_ReleaseN
void TEST_ReleaseNMinus1(ClockHandle* handle, uint32_t n);
void TEST_ReleaseNMinus1(ClockHandle* handle, size_t n);
#endif
private: // fns
@@ -538,13 +489,13 @@ class BaseClockTable {
// TODO: is this separation needed if we don't do background evictions?
ALIGN_AS(CACHE_LINE_SIZE)
// Number of elements in the table.
Atomic<size_t> occupancy_{};
AcqRelAtomic<size_t> occupancy_{};
// Memory usage by entries tracked by the cache (including standalone)
Atomic<size_t> usage_{};
AcqRelAtomic<size_t> usage_{};
// Part of usage by standalone entries (not in table)
Atomic<size_t> standalone_usage_{};
AcqRelAtomic<size_t> standalone_usage_{};
// Maximum total charge of all elements stored in the table.
// (Relaxed: eventual consistency/update is OK)
@@ -635,7 +586,7 @@ class FixedHyperClockTable : public BaseClockTable {
bool GrowIfNeeded(size_t new_occupancy, InsertState& state);
HandleImpl* DoInsert(const ClockHandleBasicData& proto,
uint32_t initial_countdown, bool take_ref,
uint64_t initial_countdown, bool take_ref,
InsertState& state);
// Runs the clock eviction algorithm trying to reclaim at least
@@ -663,7 +614,7 @@ class FixedHyperClockTable : public BaseClockTable {
}
// Release N references
void TEST_ReleaseN(HandleImpl* handle, uint32_t n);
void TEST_ReleaseN(HandleImpl* handle, size_t n);
#endif
// The load factor p is a real number in (0, 1) such that at all
@@ -824,7 +775,6 @@ class AutoHyperClockTable : public BaseClockTable {
// chain--specifically the next entry in the chain.
// * The end of a chain is given a special "end" marker and refers back
// to the head of the chain.
// These decorated pointers use the NextWithShift bit field struct below.
//
// Why do we need shift on each pointer? To make Lookup wait-free, we need
// to be able to query a chain without missing anything, and preferably
@@ -844,63 +794,47 @@ class AutoHyperClockTable : public BaseClockTable {
// it is normal to see "under construction" entries on the chain, and it
// is not safe to read their hashed key without either a read reference
// on the entry or a rewrite lock on the chain.
struct NextWithShift : public BitFields<uint64_t, NextWithShift> {
// The "shift" associated with this decorated pointer (see description
// above).
using Shift = UnsignedBitField<NextWithShift, 6, NoPrevBitField>;
// Marker for the end of a chain. Must also (a) point back to the head of
// the chain (with end marker removed), and (b) set the LockedFlag
// (below), so that attempting to lock an empty chain has no effect (not
// needed, as the lock is only needed for removals).
using EndFlag = BoolBitField<NextWithShift, Shift>;
// Marker that some thread owning writes to the chain structure (except
// for inserts), but only if not an "end" pointer. Also called the
// "rewrite lock."
using LockedFlag = BoolBitField<NextWithShift, EndFlag>;
// The "next" associated with this decorated pointer, which is an index
// into the table's array_ (see description above).
using Next = UnsignedBitField<NextWithShift, 56, LockedFlag>;
bool IsLocked() const { return Get<LockedFlag>(); }
bool IsEnd() const {
// End flag should imply locked flag
assert(!Get<EndFlag>() || Get<LockedFlag>());
return Get<EndFlag>();
}
bool IsLockedNotEnd() const {
// NOTE: helping GCC to optimize this simpler code:
// return IsLocked() && !IsEnd();
constexpr U kEndFlag = U{1} << EndFlag::kBitOffset;
constexpr U kLockedFlag = U{1} << LockedFlag::kBitOffset;
return (underlying & (kEndFlag | kLockedFlag)) == kLockedFlag;
}
auto GetNext() const { return Get<Next>(); }
auto GetShift() const { return Get<Shift>(); }
// Marker in a "with_shift" head pointer for some thread owning writes
// to the chain structure (except for inserts), but only if not an
// "end" pointer. Also called the "rewrite lock."
static constexpr uint64_t kHeadLocked = uint64_t{1} << 7;
static NextWithShift Make(size_t next, int shift) {
return NextWithShift{}.With<Next>(next).With<Shift>(
static_cast<uint8_t>(shift));
}
// Marker in a "with_shift" pointer for the end of a chain. Must also
// point back to the head of the chain (with end marker removed).
// Also includes the "locked" bit so that attempting to lock an empty
// chain has no effect (not needed, as the lock is only needed for
// removals).
static constexpr uint64_t kNextEndFlags = (uint64_t{1} << 6) | kHeadLocked;
static NextWithShift MakeEnd(size_t next, int shift) {
return Make(next, shift).With<EndFlag>(true).With<LockedFlag>(true);
}
};
static inline bool IsEnd(uint64_t next_with_shift) {
// Assuming certain values never used, suffices to check this one bit
constexpr auto kCheckBit = kNextEndFlags ^ kHeadLocked;
return next_with_shift & kCheckBit;
}
// Bottom bits to right shift away to get an array index from a
// "with_shift" pointer.
static constexpr int kNextShift = 8;
// A bit mask for the "shift" associated with each "with_shift" pointer.
// Always bottommost bits.
static constexpr int kShiftMask = 63;
// A marker for head_next_with_shift that indicates this HandleImpl is
// heap allocated (standalone) rather than in the table.
static constexpr NextWithShift kStandaloneMarker{UINT64_MAX};
static constexpr uint64_t kStandaloneMarker = UINT64_MAX;
// A marker for head_next_with_shift indicating the head is not yet part
// of the usable table, or for chain_next_with_shift indicating that the
// entry is not present or is not yet part of a chain (must not be
// "shareable" state).
static constexpr NextWithShift kUnusedMarker{0};
static constexpr uint64_t kUnusedMarker = 0;
// See above. The head pointer is logically independent of the rest of
// the entry, including the chain next pointer.
BitFieldsAtomic<NextWithShift> head_next_with_shift{kUnusedMarker};
BitFieldsAtomic<NextWithShift> chain_next_with_shift{kUnusedMarker};
AcqRelAtomic<uint64_t> head_next_with_shift{kUnusedMarker};
AcqRelAtomic<uint64_t> chain_next_with_shift{kUnusedMarker};
// For supporting CreateStandalone and some fallback cases.
inline bool IsStandalone() const {
@@ -946,7 +880,7 @@ class AutoHyperClockTable : public BaseClockTable {
bool GrowIfNeeded(size_t new_occupancy, InsertState& state);
HandleImpl* DoInsert(const ClockHandleBasicData& proto,
uint32_t initial_countdown, bool take_ref,
uint64_t initial_countdown, bool take_ref,
InsertState& state);
// Runs the clock eviction algorithm trying to reclaim at least
@@ -974,7 +908,7 @@ class AutoHyperClockTable : public BaseClockTable {
}
// Release N references
void TEST_ReleaseN(HandleImpl* handle, uint32_t n);
void TEST_ReleaseN(HandleImpl* handle, size_t n);
#endif
// Maximum ratio of number of occupied slots to number of usable slots. The
@@ -1056,7 +990,7 @@ class AutoHyperClockTable : public BaseClockTable {
// To maximize parallelization of Grow() operations, this field is only
// updated opportunistically after Grow() operations and in DoInsert() where
// it is found to be out-of-date. See CatchUpLengthInfoNoWait().
Atomic<uint64_t> length_info_;
AcqRelAtomic<uint64_t> length_info_;
// An already-computed version of the usable length times the max load
// factor. Could be slightly out of date but GrowIfNeeded()/Grow() handle
@@ -1179,8 +1113,8 @@ class ALIGN_AS(CACHE_LINE_SIZE) ClockCacheShard final : public CacheShardBase {
return table_.TEST_MutableOccupancyLimit();
}
// Acquire/release N references
void TEST_RefN(HandleImpl* handle, uint32_t n);
void TEST_ReleaseN(HandleImpl* handle, uint32_t n);
void TEST_RefN(HandleImpl* handle, size_t n);
void TEST_ReleaseN(HandleImpl* handle, size_t n);
#endif
private: // data
+5 -1
View File
@@ -50,7 +50,8 @@ CompressedSecondaryCache::CompressedSecondaryCache(
std::make_shared<CacheReservationManagerImpl<CacheEntryRole::kMisc>>(
cache_))),
disable_cache_(opts.capacity == 0) {
auto mgr = GetBuiltinV2CompressionManager();
auto mgr =
GetBuiltinCompressionManager(cache_options_.compress_format_version);
compressor_ = mgr->GetCompressor(cache_options_.compression_opts,
cache_options_.compression_type);
decompressor_ =
@@ -355,6 +356,9 @@ std::string CompressedSecondaryCache::GetPrintableOptions() const {
const_cast<CompressionOptions&>(cache_options_.compression_opts))
.c_str());
ret.append(buffer);
snprintf(buffer, kBufferSize, " compress_format_version : %d\n",
cache_options_.compress_format_version);
ret.append(buffer);
return ret;
}
+3 -2
View File
@@ -856,7 +856,8 @@ TEST_P(CompressedSecondaryCacheTestWithCompressionParam, BasicTestFromString) {
if (LZ4_Supported()) {
sec_cache_uri =
"compressed_secondary_cache://"
"capacity=2048;num_shard_bits=0;compression_type=kLZ4Compression";
"capacity=2048;num_shard_bits=0;compression_type=kLZ4Compression;"
"compress_format_version=2";
} else {
ROCKSDB_GTEST_SKIP("This test requires LZ4 support.");
sec_cache_uri =
@@ -887,7 +888,7 @@ TEST_P(CompressedSecondaryCacheTestWithCompressionParam,
sec_cache_uri =
"compressed_secondary_cache://"
"capacity=2048;num_shard_bits=0;compression_type=kLZ4Compression;"
"enable_custom_split_merge=true";
"compress_format_version=2;enable_custom_split_merge=true";
} else {
ROCKSDB_GTEST_SKIP("This test requires LZ4 support.");
sec_cache_uri =
+18 -18
View File
@@ -1503,7 +1503,7 @@ TEST_P(BasicSecondaryCacheTest, FullCapacityTest) {
/*context*/ this, Cache::Priority::LOW);
ASSERT_EQ(handle1, nullptr);
// k1 promotion can fail with strict_capacity_limit=true, but Lookup still
// k1 promotion can fail with strict_capacit_limit=true, but Lookup still
// succeeds using a standalone handle
handle1 = cache->Lookup(k1.AsSlice(), GetHelper(),
/*context*/ this, Cache::Priority::LOW);
@@ -1680,7 +1680,7 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheCorrectness2) {
// After Flush is successful, RocksDB will do the paranoid check for the new
// SST file. Meta blocks are always cached in the block cache and they
// will not be evicted. When block_2 is cache miss and read out, it is
// inserted to the block cache. Therefore, block_1 is evicted from block
// inserted to the block cache. Thefore, block_1 is evicted from block
// cache and successfully inserted to the secondary cache. Here are 2
// lookups in the secondary cache for block_1 and block_2.
ASSERT_EQ(secondary_cache->num_inserts(), 1u);
@@ -1721,7 +1721,7 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheCorrectness2) {
v = Get(Key(0));
ASSERT_EQ(1007, v.size());
// This Get needs to access block_1, since block_1 is not in block cache
// there is one secondary cache lookup. Then, block_1 is cached in the
// there is one econdary cache lookup. Then, block_1 is cached in the
// block cache.
ASSERT_EQ(secondary_cache->num_inserts(), 2u);
ASSERT_EQ(secondary_cache->num_lookups(), 5u);
@@ -1785,7 +1785,7 @@ TEST_P(DBSecondaryCacheTest, NoSecondaryCacheInsertion) {
std::string v = Get(Key(0));
ASSERT_EQ(1000, v.size());
// Since the block cache is large enough, all the blocks are cached. we
// do not need to lookup the secondary cache.
// do not need to lookup the seondary cache.
ASSERT_EQ(secondary_cache->num_inserts(), 0u);
ASSERT_EQ(secondary_cache->num_lookups(), 2u);
@@ -2150,7 +2150,7 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadBasic) {
ASSERT_OK(Flush());
Compact("a", "z");
// do the read for all the key value pairs, so all the blocks should be in
// do th eread for all the key value pairs, so all the blocks should be in
// cache
uint32_t start_insert = cache->GetInsertCount();
uint32_t start_lookup = cache->GetLookupcount();
@@ -2179,7 +2179,7 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadBasic) {
&cache_dumper);
ASSERT_OK(s);
std::vector<DB*> db_list;
db_list.push_back(db_.get());
db_list.push_back(db_);
s = cache_dumper->SetDumpFilter(db_list);
ASSERT_OK(s);
s = cache_dumper->DumpCacheEntriesToWriter();
@@ -2263,11 +2263,11 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadWithFilter) {
options.env = fault_env_.get();
std::string dbname1 = test::PerThreadDBPath("db_1");
ASSERT_OK(DestroyDB(dbname1, options));
std::unique_ptr<DB> db1;
DB* db1 = nullptr;
ASSERT_OK(DB::Open(options, dbname1, &db1));
std::string dbname2 = test::PerThreadDBPath("db_2");
ASSERT_OK(DestroyDB(dbname2, options));
std::unique_ptr<DB> db2;
DB* db2 = nullptr;
ASSERT_OK(DB::Open(options, dbname2, &db2));
fault_fs_->SetFailGetUniqueId(true);
@@ -2335,7 +2335,7 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadWithFilter) {
&cache_dumper);
ASSERT_OK(s);
std::vector<DB*> db_list;
db_list.push_back(db1.get());
db_list.push_back(db1);
s = cache_dumper->SetDumpFilter(db_list);
ASSERT_OK(s);
s = cache_dumper->DumpCacheEntriesToWriter();
@@ -2377,7 +2377,7 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadWithFilter) {
ASSERT_OK(s);
ASSERT_OK(db1->Close());
db1.reset();
delete db1;
ASSERT_OK(DB::Open(options, dbname1, &db1));
// After load, we do the Get again. To validate the cache, we do not allow any
@@ -2406,8 +2406,8 @@ TEST_P(DBSecondaryCacheTest, LRUCacheDumpLoadWithFilter) {
ASSERT_EQ(256, static_cast<int>(block_lookup));
fault_fs_->SetFailGetUniqueId(false);
fault_fs_->SetFilesystemActive(true);
db1.reset();
db2.reset();
delete db1;
delete db2;
ASSERT_OK(DestroyDB(dbname1, options));
ASSERT_OK(DestroyDB(dbname2, options));
}
@@ -2464,7 +2464,7 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionBasic) {
std::string v = Get(Key(0));
ASSERT_EQ(1007, v.size());
// Check the data in first block. Cache miss, directly read from SST file.
// Check the data in first block. Cache miss, direclty read from SST file.
ASSERT_EQ(secondary_cache->num_inserts(), 0u);
ASSERT_EQ(secondary_cache->num_lookups(), 0u);
@@ -2598,7 +2598,7 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionChange) {
}
// Two DB test. We create 2 DBs sharing the same block cache and secondary
// cache. We disable the secondary cache option for DB2.
// cache. We diable the secondary cache option for DB2.
TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionTwoDB) {
if (IsHyperClock()) {
ROCKSDB_GTEST_BYPASS("Test depends on LRUCache-specific behaviors");
@@ -2619,11 +2619,11 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionTwoDB) {
options.paranoid_file_checks = true;
std::string dbname1 = test::PerThreadDBPath("db_t_1");
ASSERT_OK(DestroyDB(dbname1, options));
std::unique_ptr<DB> db1;
DB* db1 = nullptr;
ASSERT_OK(DB::Open(options, dbname1, &db1));
std::string dbname2 = test::PerThreadDBPath("db_t_2");
ASSERT_OK(DestroyDB(dbname2, options));
std::unique_ptr<DB> db2;
DB* db2 = nullptr;
Options options2 = options;
options2.lowest_used_cache_tier = CacheTier::kVolatileTier;
ASSERT_OK(DB::Open(options2, dbname2, &db2));
@@ -2700,8 +2700,8 @@ TEST_P(DBSecondaryCacheTest, TestSecondaryCacheOptionTwoDB) {
fault_fs_->SetFailGetUniqueId(false);
fault_fs_->SetFilesystemActive(true);
db1.reset();
db2.reset();
delete db1;
delete db2;
ASSERT_OK(DestroyDB(dbname1, options));
ASSERT_OK(DestroyDB(dbname2, options));
}
-535
View File
@@ -1,535 +0,0 @@
# Adding New Options to RocksDB Public API
This document provides guidance on how to add new options to RocksDB's public API. There are two main categories of options:
1. **Standard Column Family Options** (Options/DBOptions/AdvancedColumnFamilyOptions)
2. **BlockBasedTableOptions** (options specific to block-based table format)
## Overview of Files to Modify
### For Standard Column Family Options
| File | Purpose |
|------|---------|
| `include/rocksdb/advanced_options.h` | Define the option with documentation |
| `include/rocksdb/options.h` | Add reference in related option groups if needed |
| `options/cf_options.h` | Add to `MutableCFOptions` or `ImmutableCFOptions` struct |
| `options/cf_options.cc` | Register option for serialization/deserialization and logging |
| `options/options_helper.cc` | Add to `UpdateColumnFamilyOptions()` for mutable options |
| `options/options_settable_test.cc` | Add to test string for option parsing |
| `db_stress_tool/db_stress_common.h` | Declare gflag |
| `db_stress_tool/db_stress_gflags.cc` | Define gflag with default value |
| `db_stress_tool/db_stress_test_base.cc` | Apply flag to options |
| `tools/db_bench_tool.cc` | Add flag definition and apply to options |
| `tools/db_crashtest.py` | Add randomized values for stress testing |
| `unreleased_history/new_features/` | Add release note markdown file |
### For BlockBasedTableOptions
| File | Purpose |
|------|---------|
| `include/rocksdb/table.h` | Define the option in `BlockBasedTableOptions` struct |
| `table/block_based/block_based_table_factory.cc` | Register for serialization, validation, and printing |
| `options/options_settable_test.cc` | Add to `BlockBasedTableOptionsAllFieldsSettable` test |
| `options/options_test.cc` | Add to `MutableCFOptions` test if applicable |
| `db_stress_tool/db_stress_common.h` | Declare gflag |
| `db_stress_tool/db_stress_gflags.cc` | Define gflag |
| `db_stress_tool/db_stress_test_base.cc` | Apply flag to `block_based_options` |
| `tools/db_bench_tool.cc` | Add flag definition and apply to `block_based_options` |
| `tools/db_crashtest.py` | Add randomized values |
| `java/src/main/java/org/rocksdb/BlockBasedTableConfig.java` | Java API |
| `java/rocksjni/portal.h` | JNI portal for Java bindings |
| `java/rocksjni/table.cc` | JNI implementation |
| `java/src/test/java/org/rocksdb/BlockBasedTableConfigTest.java` | Java unit test |
---
## Pattern 1: Adding a Standard Column Family Option
Example reference: commit `94e65a2e0b4f817aa4bfa4c96cdf867e7980d7bc` (memtable_verify_per_key_checksum_on_seek)
### Step 1: Define the Option in Public Header
**File: `include/rocksdb/advanced_options.h`**
Add the option with documentation in `AdvancedColumnFamilyOptions` struct:
```cpp
// 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_verify_per_key_checksum_on_seek = false;
```
### Step 2: Add to Internal Options Structs
**File: `options/cf_options.h`**
Add to `MutableCFOptions` struct (or `ImmutableCFOptions` for immutable options):
```cpp
// In MutableCFOptions constructor from Options:
memtable_verify_per_key_checksum_on_seek(
options.memtable_verify_per_key_checksum_on_seek),
// In MutableCFOptions default constructor:
memtable_verify_per_key_checksum_on_seek(false),
// In MutableCFOptions struct member declarations:
bool memtable_verify_per_key_checksum_on_seek;
```
### Step 3: Register for Serialization/Deserialization
**File: `options/cf_options.cc`**
Add to the options type info map for serialization:
```cpp
{"memtable_verify_per_key_checksum_on_seek",
{offsetof(struct MutableCFOptions,
memtable_verify_per_key_checksum_on_seek),
OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
```
Add logging in `MutableCFOptions::Dump()`:
```cpp
ROCKS_LOG_INFO(log, "memtable_verify_per_key_checksum_on_seek: %d",
memtable_verify_per_key_checksum_on_seek);
```
### Step 4: Update Options Helper
**File: `options/options_helper.cc`**
Add to `UpdateColumnFamilyOptions()`:
```cpp
cf_opts->memtable_verify_per_key_checksum_on_seek =
moptions.memtable_verify_per_key_checksum_on_seek;
```
### Step 5: Add to Options Settable Test
**File: `options/options_settable_test.cc`**
Add to the test string in `ColumnFamilyOptionsAllFieldsSettable`:
```cpp
"memtable_verify_per_key_checksum_on_seek=1;"
```
### Step 6: Add db_stress Support
**File: `db_stress_tool/db_stress_common.h`**
```cpp
DECLARE_bool(memtable_verify_per_key_checksum_on_seek);
```
**File: `db_stress_tool/db_stress_gflags.cc`**
```cpp
DEFINE_bool(
memtable_verify_per_key_checksum_on_seek,
ROCKSDB_NAMESPACE::Options().memtable_verify_per_key_checksum_on_seek,
"Sets CF option memtable_verify_per_key_checksum_on_seek.");
```
**File: `db_stress_tool/db_stress_test_base.cc`**
```cpp
options.memtable_verify_per_key_checksum_on_seek =
FLAGS_memtable_verify_per_key_checksum_on_seek;
```
### Step 7: Add db_bench Support
**File: `tools/db_bench_tool.cc`**
```cpp
// Flag definition (near related flags):
DEFINE_bool(memtable_verify_per_key_checksum_on_seek, false,
"Sets CF option memtable_verify_per_key_checksum_on_seek");
// Apply flag to options (in InitializeOptionsFromFlags or similar):
options.memtable_verify_per_key_checksum_on_seek =
FLAGS_memtable_verify_per_key_checksum_on_seek;
```
### Step 8: Add Crash Test Support
**File: `tools/db_crashtest.py`**
```python
"memtable_verify_per_key_checksum_on_seek": lambda: random.choice([0] * 7 + [1]),
```
Also add constraint handling in `finalize_and_sanitize()` if needed:
```python
# only skip list memtable representation supports paranoid memory checks
if dest_params.get("memtablerep") != "skip_list":
dest_params["memtable_verify_per_key_checksum_on_seek"] = 0
```
### Step 9: Add Release Note
**File: `unreleased_history/new_features/<descriptive_name>.md`**
```markdown
A new flag memtable_verify_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.
```
---
## Pattern 2: Adding a BlockBasedTableOptions Option
Example reference: commit `742741b175c5f238374c1714f9db3340d49de569` (super_block_alignment_size)
### Step 1: Define the Option in Public Header
**File: `include/rocksdb/table.h`**
Add to `BlockBasedTableOptions` struct with documentation:
```cpp
// Align data blocks on super block alignment. Avoid a data block split across
// super block boundaries. Works with/without compression.
//
// Here a "super block" refers to an aligned unit of underlying Filesystem
// storage for which there is an extra cost when a random read involves two
// such super blocks instead of just one. Configuring that size here suggests
// inserting padding in the SST file to avoid a single SST block splitting
// across two super blocks. Only power-of-two sizes are supported. See also
// super_block_alignment_space_overhead_ratio. Default to 0, which means super
// block alignment is disabled.
size_t super_block_alignment_size = 0;
// This option controls the storage space overhead of super block alignment.
// It is used to calculate the max padding size allowed for super block
// alignment. It is calculated in this way. If super_block_alignment_size is
// 2MB, and super_block_alignment_overhead_ratio is 128, then the max padding
// size allowed for super block alignment is 2MB / 128 = 16KB.
// Note that, when it is set to 0, super block alignment is disabled.
size_t super_block_alignment_space_overhead_ratio = 128;
```
### Step 2: Register for Serialization in Table Factory
**File: `table/block_based/block_based_table_factory.cc`**
Add to the type info map:
```cpp
{"super_block_alignment_size",
{offsetof(struct BlockBasedTableOptions, super_block_alignment_size),
OptionType::kSizeT, OptionVerificationType::kNormal}},
{"super_block_alignment_space_overhead_ratio",
{offsetof(struct BlockBasedTableOptions,
super_block_alignment_space_overhead_ratio),
OptionType::kSizeT, OptionVerificationType::kNormal}},
```
Add validation in `ValidateOptions()`:
```cpp
if ((table_options_.super_block_alignment_size &
(table_options_.super_block_alignment_size - 1))) {
return Status::InvalidArgument(
"Super Block alignment requested but super block alignment size is not "
"a power of 2");
}
if (table_options_.super_block_alignment_size >
std::numeric_limits<uint32_t>::max()) {
return Status::InvalidArgument(
"Super block alignment size exceeds maximum number (4GiB) allowed");
}
```
Add printing in `GetPrintableOptions()`:
```cpp
snprintf(buffer, kBufferSize,
" super_block_alignment_size: %" ROCKSDB_PRIszt "\n",
table_options_.super_block_alignment_size);
ret.append(buffer);
```
### Step 3: Add to Options Settable Test
**File: `options/options_settable_test.cc`**
Add to `BlockBasedTableOptionsAllFieldsSettable` test:
```cpp
"super_block_alignment_size=65536;"
"super_block_alignment_space_overhead_ratio=4096;"
```
### Step 4: Add to Options Test
**File: `options/options_test.cc`**
```cpp
ASSERT_OK(GetColumnFamilyOptionsFromString(
config_options, cf_opts,
"block_based_table_factory.super_block_alignment_size=65536; "
"block_based_table_factory.super_block_alignment_space_overhead_ratio=4096;",
&cf_opts));
ASSERT_EQ(bbto->super_block_alignment_size, 65536);
ASSERT_EQ(bbto->super_block_alignment_space_overhead_ratio, 4096);
```
### Step 5: Add db_stress Support
**File: `db_stress_tool/db_stress_common.h`**
```cpp
DECLARE_uint64(super_block_alignment_size);
DECLARE_uint64(super_block_alignment_space_overhead_ratio);
```
**File: `db_stress_tool/db_stress_gflags.cc`**
```cpp
DEFINE_uint64(
super_block_alignment_size,
ROCKSDB_NAMESPACE::BlockBasedTableOptions().super_block_alignment_size,
"BlockBasedTableOptions.super_block_alignment_size");
DEFINE_uint64(
super_block_alignment_space_overhead_ratio,
ROCKSDB_NAMESPACE::BlockBasedTableOptions()
.super_block_alignment_space_overhead_ratio,
"BlockBasedTableOptions.super_block_alignment_space_overhead_ratio");
```
**File: `db_stress_tool/db_stress_test_base.cc`**
```cpp
block_based_options.super_block_alignment_size =
fLU64::FLAGS_super_block_alignment_size;
block_based_options.super_block_alignment_space_overhead_ratio =
fLU64::FLAGS_super_block_alignment_space_overhead_ratio;
```
### Step 6: Add db_bench Support
**File: `tools/db_bench_tool.cc`**
```cpp
// Flag definitions:
DEFINE_uint64(
super_block_alignment_size,
ROCKSDB_NAMESPACE::BlockBasedTableOptions().super_block_alignment_size,
"Configure super block size");
DEFINE_uint64(super_block_alignment_space_overhead_ratio,
ROCKSDB_NAMESPACE::BlockBasedTableOptions()
.super_block_alignment_space_overhead_ratio,
"Configure space overhead for super block alignment");
// Apply to block_based_options (in the block where other options are set):
block_based_options.super_block_alignment_size = FLAGS_super_block_alignment_size;
block_based_options.super_block_alignment_space_overhead_ratio =
FLAGS_super_block_alignment_space_overhead_ratio;
```
### Step 7: Add Crash Test Support
**File: `tools/db_crashtest.py`**
```python
"super_block_alignment_size": lambda: random.choice(
[0, 128 * 1024, 512 * 1024, 2 * 1024 * 1024]
),
"super_block_alignment_space_overhead_ratio": lambda: random.choice([0, 32, 4096]),
```
### Step 8: Add Java API Support
**File: `java/src/main/java/org/rocksdb/BlockBasedTableConfig.java`**
Add getter and setter methods:
```java
/**
* Get the super block alignment size.
*
* @return the super block alignment size.
*/
public long superBlockAlignmentSize() {
return superBlockAlignmentSize;
}
/**
* Set the super block alignment size.
* When set to 0, super block alignment is disabled.
*
* @param superBlockAlignmentSize the super block alignment size.
*
* @return the reference to the current option.
*/
public BlockBasedTableConfig setSuperBlockAlignmentSize(final long superBlockAlignmentSize) {
this.superBlockAlignmentSize = superBlockAlignmentSize;
return this;
}
```
Add member variable:
```java
private long superBlockAlignmentSize;
```
Update constructor and native method signature.
**File: `java/rocksjni/portal.h`**
Update `GetMethodID` signature and add fields to Java object construction.
**File: `java/rocksjni/table.cc`**
Add parameters to JNI function and apply to options.
**File: `java/src/test/java/org/rocksdb/BlockBasedTableConfigTest.java`**
Add unit tests:
```java
@Test
public void superBlockAlignmentSize() {
final BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setSuperBlockAlignmentSize(1024 * 1024);
assertThat(blockBasedTableConfig.superBlockAlignmentSize()).isEqualTo(1024 * 1024);
}
```
---
## Pattern 3: Adding C API for Existing Option
Example reference: commit `429b36c22d76403d275dd0e6877b08d4cea2bc90` (block_align C API)
If an option already exists but needs C API support:
**First decide whether the option is auto-managed.**
Many simple option fields are no longer maintained by hand in
`include/rocksdb/c.h` and `db/c.cc`. Before adding a manual wrapper:
- Check whether the option belongs to a family handled by
`tools/c_api_gen/auto_simple_bindings.py`.
- If it is a simple scalar/enum/string field in an auto-managed family, run
`python3 tools/c_api_gen/regen_all.py` and let the generator add the C API.
- After regenerating, run
`python3 tools/c_api_gen/verify_generated_up_to_date.py` to confirm the
checked-in generated fragments stay stable.
- Do not edit generated `.inc` files under `c_api_gen/` by hand.
- If the new field is not ready for C API support yet, add an entry to
`tools/c_api_gen/auto_simple_bindings_blocklist.json` with
`"policy": "deferred"` and a concrete reason so the build stays intentional
rather than silently drifting.
- If the field needs custom ownership, callback, vector, or nested-struct
marshalling, keep it manual or move it into `tools/c_api_gen/spec.json`
depending on the API shape.
If the option is not auto-managed, or the C API really is a custom/manual case,
the traditional hand-written pattern still applies:
**File: `db/c.cc`**
```cpp
void rocksdb_block_based_options_set_block_align(
rocksdb_block_based_table_options_t* options, unsigned char v) {
options->rep.block_align = v;
}
```
**File: `include/rocksdb/c.h`**
```cpp
extern ROCKSDB_LIBRARY_API void rocksdb_block_based_options_set_block_align(
rocksdb_block_based_table_options_t*, unsigned char);
```
---
## Unit Testing Guidelines
### For Standard Options
Add tests in appropriate test files (e.g., `db/db_memtable_test.cc`, `db/db_options_test.cc`):
```cpp
TEST_F(DBMemTableTest, YourOptionTest) {
Options options;
options.your_new_option = true;
Reopen(options);
// Test the behavior
}
```
### For BlockBasedTableOptions
Add tests in `db/db_flush_test.cc`, `table/block_based/block_based_table_reader_test.cc`, or `table/table_test.cc`:
```cpp
TEST_P(DBFlushYourFeatureTest, YourFeature) {
Options options;
BlockBasedTableOptions block_options;
block_options.your_new_option = some_value;
options.table_factory.reset(NewBlockBasedTableFactory(block_options));
ASSERT_OK(options.table_factory->ValidateOptions(
DBOptions(options), ColumnFamilyOptions(options)));
Reopen(options);
// Test the behavior
}
```
---
## Option Type Reference
Common option types used in serialization:
| OptionType | C++ Type | Example |
|------------|----------|---------|
| `kBoolean` | `bool` | `paranoid_memory_checks` |
| `kInt` | `int` | `max_write_buffer_number` |
| `kInt32T` | `int32_t` | `level0_file_num_compaction_trigger` |
| `kUInt32T` | `uint32_t` | `memtable_protection_bytes_per_key` |
| `kUInt64T` | `uint64_t` | `target_file_size_base` |
| `kSizeT` | `size_t` | `block_size` |
| `kDouble` | `double` | `compression_ratio` |
| `kString` | `std::string` | `db_log_dir` |
---
## Checklist Summary
- [ ] Public header file with option definition and documentation
- [ ] Internal options struct (MutableCFOptions or ImmutableCFOptions)
- [ ] Options serialization/deserialization registration
- [ ] Options logging in Dump() method
- [ ] UpdateColumnFamilyOptions() for mutable options
- [ ] options_settable_test.cc
- [ ] db_stress_common.h (DECLARE)
- [ ] db_stress_gflags.cc (DEFINE)
- [ ] db_stress_test_base.cc (apply flag)
- [ ] db_bench_tool.cc (DEFINE and apply)
- [ ] db_crashtest.py (randomized values)
- [ ] Unit tests
- [ ] unreleased_history markdown file
- [ ] Java API (for BlockBasedTableOptions)
- [ ] C API (if needed)
-545
View File
@@ -1,545 +0,0 @@
# RocksDB API Development Guide
This document provides guidance for adding new public APIs to RocksDB, following the established patterns used by existing APIs like `CompactRange`.
## API Layer Architecture
RocksDB exposes public APIs through multiple layers. Users can access RocksDB through any of the three public APIs: C++ headers, C headers, or Java bindings.
Here is an example for public header db.h:
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Level 1: Public APIs (User Entry Points) │
├───────────────────────┬─────────────────────────┬───────────────────────────┤
│ C++ Public API │ C API Bindings │ Java/JNI API │
│ include/rocksdb/db.h │ include/rocksdb/c.h │ java/src/.../RocksDB.java │
│ include/rocksdb/*.h │ │ java/src/.../*.java │
└───────────────────────┴────────────┬────────────┴───────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────────────┐
│ Level 2: C++ Implementation (Internal Core) │
│ db/db_impl/db_impl*.cc, db/c.cc, java/rocksjni/*.cc │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Step-by-Step Guide: Adding a New Public API
### Step 1: Define the C++ Public Interface
**File:** `include/rocksdb/db.h`
Add the virtual method declaration in the `DB` class:
\`\`\`cpp
// Pure virtual - must be implemented by DBImpl
virtual Status YourNewAPI(const YourAPIOptions& options,
ColumnFamilyHandle* column_family,
/* other params */) = 0;
// Convenience overload for default column family
virtual Status YourNewAPI(const YourAPIOptions& options,
/* other params */) {
return YourNewAPI(options, DefaultColumnFamily(), /* other params */);
}
\`\`\`
**Key Patterns:**
- Use `Status` return type for error handling
- Use `OptSlice` to avoid unnecessary levels of indirection and use of raw pointers.
- Use `ColumnFamilyHandle*` for column family support
- Provide convenience overloads for the default column family
### Step 2: Define Options Struct (If Needed)
**File:** `include/rocksdb/options.h`
If your API has multiple configuration options, define an options struct:
\`\`\`cpp
struct YourAPIOptions {
// Document each option with clear comments
bool some_boolean_option = false;
// Default value explanation
int some_int_option = -1;
// Pointer options require careful lifetime management
std::atomic<bool>* canceled = nullptr;
// Enum options for multi-choice settings
YourEnumType some_enum = YourEnumType::kDefault;
};
\`\`\`
**Key Patterns:**
- Use sensible default values specified inline (e.g., `= false`, `= -1`)
- Do NOT redundantly document the default value in comments; instead, document the rationale (why this default), historical context, and how different values are interpreted
- Group related options logically
- Consider thread-safety for pointer options
### Step 3: Implement in DBImpl
**Header:** `db/db_impl/db_impl.h`
\`\`\`cpp
using DB::YourNewAPI;
Status YourNewAPI(const YourAPIOptions& options,
ColumnFamilyHandle* column_family,
/* other params */) override;
// Private internal implementation if needed
Status YourNewAPIInternal(const YourAPIOptions& options,
ColumnFamilyHandle* column_family,
/* other params */);
\`\`\`
**Implementation:** `db/db_impl/db_impl_<category>.cc`
Choose the appropriate implementation file based on functionality:
- `db_impl_compaction_flush.cc` - Compaction and flush operations
- `db_impl_write.cc` - Write operations
- `db_impl_open.cc` - DB opening/closing
- `db_impl_files.cc` - File operations
- `db_impl.cc` - General operations
\`\`\`cpp
Status DBImpl::YourNewAPI(const YourAPIOptions& options,
ColumnFamilyHandle* column_family,
/* other params */) {
// 1. Input validation
if (/* invalid input */) {
return Status::InvalidArgument("Error message");
}
// 2. Check for cancellation/abort conditions
if (options.canceled && options.canceled->load(std::memory_order_acquire)) {
return Status::Incomplete(Status::SubCode::kManualCompactionPaused);
}
// 3. Get column family data
auto cfh = static_cast<ColumnFamilyHandleImpl*>(column_family);
auto cfd = cfh->cfd();
// 4. Core implementation logic
// ...
return Status::OK();
}
\`\`\`
### Step 4: Handle Special DB Types
**StackableDB (Wrapper DBs):**
**File:** `include/rocksdb/utilities/stackable_db.h`
\`\`\`cpp
using DB::YourNewAPI;
Status YourNewAPI(const YourAPIOptions& options,
ColumnFamilyHandle* column_family,
/* other params */) override {
return db_->YourNewAPI(options, column_family, /* other params */);
}
\`\`\`
**Secondary DB (Read-Only):**
**File:** `db/db_impl/db_impl_secondary.h`
\`\`\`cpp
using DBImpl::YourNewAPI;
Status YourNewAPI(const YourAPIOptions& /*options*/,
ColumnFamilyHandle* /*column_family*/,
/* other params */) override {
return Status::NotSupported("Not supported in secondary DB");
}
\`\`\`
**CompactedDB (Read-Only):**
**File:** `db/db_impl/compacted_db_impl.h`
\`\`\`cpp
using DBImpl::YourNewAPI;
Status YourNewAPI(const YourAPIOptions& /*options*/,
ColumnFamilyHandle* /*column_family*/,
/* other params */) override {
return Status::NotSupported("Not supported for read-only DB");
}
\`\`\`
### Step 5: Add C API Bindings
> **Important:** `include/rocksdb/c.h` and `db/c.cc` are `@generated` and must
> NOT be edited by hand — your changes would be overwritten on the next
> regeneration. Choose the right path first (see "Before writing C API code by
> hand" below). For hand-written (manual) wrappers, edit the source templates
> `tools/c_api_gen/c_base.h` (declarations) and `tools/c_api_gen/c_base.cc`
> (implementations), then run `python3 tools/c_api_gen/regen_all.py` to produce
> `c.h` / `c.cc`. The snippets below show the *declaration* and *implementation*
> you would add to those templates.
**Header (declaration → `tools/c_api_gen/c_base.h`):**
```c
// Basic version
extern ROCKSDB_LIBRARY_API void rocksdb_your_new_api(
rocksdb_t* db,
const char* start_key, size_t start_key_len,
const char* limit_key, size_t limit_key_len);
// Column family version
extern ROCKSDB_LIBRARY_API void rocksdb_your_new_api_cf(
rocksdb_t* db, rocksdb_column_family_handle_t* column_family,
const char* start_key, size_t start_key_len,
const char* limit_key, size_t limit_key_len);
// With options and error handling
extern ROCKSDB_LIBRARY_API void rocksdb_your_new_api_opt(
rocksdb_t* db, rocksdb_your_api_options_t* opt,
const char* start_key, size_t start_key_len,
const char* limit_key, size_t limit_key_len,
char** errptr);
\`\`\`
**Implementation (→ `tools/c_api_gen/c_base.cc`):**
\`\`\`cpp
void rocksdb_your_new_api(rocksdb_t* db, const char* start_key,
size_t start_key_len, const char* limit_key,
size_t limit_key_len) {
Slice a, b;
db->rep->YourNewAPI(
YourAPIOptions(), // Default options
(start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr),
(limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr));
}
void rocksdb_your_new_api_cf(rocksdb_t* db,
rocksdb_column_family_handle_t* column_family,
const char* start_key, size_t start_key_len,
const char* limit_key, size_t limit_key_len) {
Slice a, b;
db->rep->YourNewAPI(
YourAPIOptions(),
column_family->rep,
(start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr),
(limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr));
}
\`\`\`
**Before writing C API code by hand, choose the right path:**
- **Auto-managed simple struct fields:** If you added a new field to a managed
public struct such as `ReadOptions`, selected option structs, or managed
metadata structs, first check `tools/c_api_gen/auto_simple_bindings.py`.
Simple scalar/enum/string fields should be regenerated with
`python3 tools/c_api_gen/regen_all.py` rather than hand-editing
`include/rocksdb/c.h` / `db/c.cc`.
After regenerating, run
`python3 tools/c_api_gen/verify_generated_up_to_date.py` to confirm the
checked-in generated fragments are stable.
- **Spec-driven wrappers:** If the API is still mechanically generated but needs
an explicit C shape, naming, or `Status`/`char** errptr` policy, add it to
`tools/c_api_gen/spec.json`.
- **Fully manual wrappers:** If the API uses callbacks, ownership transfer,
vectors/maps, open flows, or otherwise irregular marshalling, keep the C API
hand-written.
**Temporary deferral for auto-managed families:**
If a new field lands in an auto-managed family but the C API shape is not ready
yet, add a checked-in entry to
`tools/c_api_gen/auto_simple_bindings_blocklist.json` with:
- `policy: "manual"` when the field is intentionally outside simple auto-gen
- `policy: "deferred"` when the field should be revisited later
- a concrete `reason`
- `tracking_issue` when available
If a field in an auto-managed family is not supported by the generator and is
not covered by the blocklist, regeneration should fail. That is intentional.
**If you have options, also add:**
\`\`\`cpp
// Options struct wrapper
struct rocksdb_your_api_options_t {
YourAPIOptions rep;
};
rocksdb_your_api_options_t* rocksdb_your_api_options_create() {
return new rocksdb_your_api_options_t;
}
void rocksdb_your_api_options_destroy(rocksdb_your_api_options_t* opt) {
delete opt;
}
void rocksdb_your_api_options_set_some_option(
rocksdb_your_api_options_t* opt, unsigned char value) {
opt->rep.some_boolean_option = value;
}
\`\`\`
### Step 6: Add Java Bindings
**Java API:** `java/src/main/java/org/rocksdb/RocksDB.java`
\`\`\`java
// Basic version
public void yourNewAPI() throws RocksDBException {
yourNewAPI(null);
}
// Column family version
public void yourNewAPI(ColumnFamilyHandle columnFamilyHandle)
throws RocksDBException {
yourNewAPI(nativeHandle_, null, -1, null, -1, 0,
columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_);
}
// Range version
public void yourNewAPI(final byte[] begin, final byte[] end)
throws RocksDBException {
yourNewAPI(null, begin, end);
}
// Full-featured version with options
public void yourNewAPI(ColumnFamilyHandle columnFamilyHandle,
final byte[] begin, final byte[] end,
final YourAPIOptions options)
throws RocksDBException {
yourNewAPI(nativeHandle_,
begin, begin == null ? -1 : begin.length,
end, end == null ? -1 : end.length,
options.nativeHandle_,
columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_);
}
// Native method declaration
private static native void yourNewAPI(final long handle,
/* @Nullable */ final byte[] begin, final int beginLen,
/* @Nullable */ final byte[] end, final int endLen,
final long optionsHandle,
final long cfHandle);
\`\`\`
**Options Class:** `java/src/main/java/org/rocksdb/YourAPIOptions.java`
\`\`\`java
public class YourAPIOptions extends RocksObject {
public YourAPIOptions() {
super(newYourAPIOptions());
}
// Builder pattern setters
public YourAPIOptions setSomeBooleanOption(boolean value) {
setSomeBooleanOption(nativeHandle_, value);
return this;
}
// Getters
public boolean someBooleanOption() {
return someBooleanOption(nativeHandle_);
}
// Native method declarations
private static native long newYourAPIOptions();
private static native void disposeInternalJni(long handle);
private static native void setSomeBooleanOption(long handle, boolean value);
private static native boolean someBooleanOption(long handle);
@Override
protected final void disposeInternal(final long handle) {
disposeInternalJni(handle);
}
}
\`\`\`
**JNI Implementation:** `java/rocksjni/rocksjni.cc`
\`\`\`cpp
void Java_org_rocksdb_RocksDB_yourNewAPI(
JNIEnv* env, jclass,
jlong jdb_handle, jbyteArray jbegin, jint jbegin_len,
jbyteArray jend, jint jend_len,
jlong joptions_handle, jlong jcf_handle) {
// 1. Convert Java byte arrays to C++ strings
jboolean has_exception = JNI_FALSE;
std::string str_begin;
if (jbegin_len > 0) {
str_begin = ROCKSDB_NAMESPACE::JniUtil::byteString<std::string>(
env, jbegin, jbegin_len,
[](const char* str, const size_t len) { return std::string(str, len); },
&has_exception);
if (has_exception == JNI_TRUE) return;
}
std::string str_end;
if (jend_len > 0) {
str_end = ROCKSDB_NAMESPACE::JniUtil::byteString<std::string>(
env, jend, jend_len,
[](const char* str, const size_t len) { return std::string(str, len); },
&has_exception);
if (has_exception == JNI_TRUE) return;
}
// 2. Get or create options
ROCKSDB_NAMESPACE::YourAPIOptions* options = nullptr;
if (joptions_handle == 0) {
options = new ROCKSDB_NAMESPACE::YourAPIOptions();
} else {
options = reinterpret_cast<ROCKSDB_NAMESPACE::YourAPIOptions*>(joptions_handle);
}
// 3. Unwrap handles
auto* db = reinterpret_cast<ROCKSDB_NAMESPACE::DB*>(jdb_handle);
ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf_handle =
jcf_handle == 0 ? db->DefaultColumnFamily()
: reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>(jcf_handle);
// 4. Create Slices
std::unique_ptr<ROCKSDB_NAMESPACE::Slice> begin;
std::unique_ptr<ROCKSDB_NAMESPACE::Slice> end;
if (jbegin_len > 0) begin.reset(new ROCKSDB_NAMESPACE::Slice(str_begin));
if (jend_len > 0) end.reset(new ROCKSDB_NAMESPACE::Slice(str_end));
// 5. Call C++ API
ROCKSDB_NAMESPACE::Status s = db->YourNewAPI(*options, cf_handle, begin.get(), end.get());
// 6. Cleanup if we created options
if (joptions_handle == 0) delete options;
// 7. Throw Java exception on error
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
}
\`\`\`
**Options JNI:** `java/rocksjni/your_api_options.cc`
\`\`\`cpp
jlong Java_org_rocksdb_YourAPIOptions_newYourAPIOptions(JNIEnv*, jclass) {
auto* options = new ROCKSDB_NAMESPACE::YourAPIOptions();
return GET_CPLUSPLUS_POINTER(options);
}
void Java_org_rocksdb_YourAPIOptions_disposeInternalJni(JNIEnv*, jclass, jlong jhandle) {
auto* options = reinterpret_cast<ROCKSDB_NAMESPACE::YourAPIOptions*>(jhandle);
delete options;
}
void Java_org_rocksdb_YourAPIOptions_setSomeBooleanOption(
JNIEnv*, jclass, jlong jhandle, jboolean value) {
auto* options = reinterpret_cast<ROCKSDB_NAMESPACE::YourAPIOptions*>(jhandle);
options->some_boolean_option = static_cast<bool>(value);
}
jboolean Java_org_rocksdb_YourAPIOptions_someBooleanOption(JNIEnv*, jclass, jlong jhandle) {
auto* options = reinterpret_cast<ROCKSDB_NAMESPACE::YourAPIOptions*>(jhandle);
return static_cast<jboolean>(options->some_boolean_option);
}
\`\`\`
### Step 7: Update Build Files
**Java CMakeLists.txt:** `java/CMakeLists.txt`
Add your new Java source files:
\`\`\`cmake
src/main/java/org/rocksdb/YourAPIOptions.java
src/test/java/org/rocksdb/YourAPIOptionsTest.java
\`\`\`
### Step 8: Add Release Notes
**Directory:** `unreleased_history/`
RocksDB uses individual files in the `unreleased_history/` directory rather than directly editing `HISTORY.md`. This avoids merge conflicts and ensures changes are attributed to the correct release version.
Add a file to the appropriate subdirectory:
- `unreleased_history/new_features/` - For new functionality
- `unreleased_history/public_api_changes/` - For API changes
- `unreleased_history/behavior_changes/` - For behavior modifications
- `unreleased_history/bug_fixes/` - For bug fixes
**Example:** `unreleased_history/new_features/your_new_api.md`
\`\`\`markdown
Added `YourNewAPI()` to support [describe functionality]. See `YourAPIOptions` for configuration.
\`\`\`
**Example:** `unreleased_history/public_api_changes/your_api_options.md`
**Note:** Files should contain one line of markdown. The "* " prefix is automatically added if not included. These files are compiled into `HISTORY.md` during the release process.
### Step 9: Add Tests
**C++ Unit Tests:** `db/db_your_api_test.cc` or add to existing test file
\`\`\`cpp
TEST_F(DBTest, YourNewAPIBasic) {
Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu"}, options);
// Setup test data
ASSERT_OK(Put(1, "key1", "value1"));
ASSERT_OK(Put(1, "key2", "value2"));
// Test your API
YourAPIOptions api_options;
api_options.some_boolean_option = true;
ASSERT_OK(db_->YourNewAPI(api_options, handles_[1], nullptr, nullptr));
// Verify results
// ...
}
\`\`\`
**Java Tests:** `java/src/test/java/org/rocksdb/YourAPIOptionsTest.java`
\`\`\`java
public class YourAPIOptionsTest {
@Test
public void yourAPIOptions() {
try (final YourAPIOptions options = new YourAPIOptions()) {
assertFalse(options.someBooleanOption());
options.setSomeBooleanOption(true);
assertTrue(options.someBooleanOption());
}
}
}
\`\`\`
## File Summary Checklist
| Component | File(s) | Required |
|-----------|---------|----------|
| C++ Public Interface | `include/rocksdb/db.h` | ✓ |
| Options Struct | `include/rocksdb/options.h` | If needed |
| DBImpl Declaration | `db/db_impl/db_impl.h` | ✓ |
| DBImpl Implementation | `db/db_impl/db_impl_*.cc` | ✓ |
| StackableDB | `include/rocksdb/utilities/stackable_db.h` | ✓ |
| Secondary DB | `db/db_impl/db_impl_secondary.h` | If not supported |
| Compacted DB | `db/db_impl/compacted_db_impl.h` | If not supported |
| C API Header (manual wrappers) | `tools/c_api_gen/c_base.h` → regen → `include/rocksdb/c.h` (`@generated`) | ✓ |
| C API Implementation (manual wrappers) | `tools/c_api_gen/c_base.cc` → regen → `db/c.cc` (`@generated`) | ✓ |
| Java API | `java/src/main/java/org/rocksdb/RocksDB.java` | ✓ |
| Java Options | `java/src/main/java/org/rocksdb/YourAPIOptions.java` | If needed |
| JNI Implementation | `java/rocksjni/rocksjni.cc` | ✓ |
| JNI Options | `java/rocksjni/your_api_options.cc` | If needed |
| Java CMake | `java/CMakeLists.txt` | If new files |
| Changelog | `unreleased_history/*.md` | ✓ |
| C++ Tests | `db/db_*_test.cc` | ✓ |
| Java Tests | `java/src/test/java/org/rocksdb/*Test.java` | ✓ |
## Best Practices
1. **Error Handling**: Always return `Status` objects in C++, throw exceptions in Java
2. **Default Values**: Provide sensible defaults for all options
3. **Documentation**: Add clear comments for all public methods and options
4. **Column Family Support**: Always support column family operations
5. **Thread Safety**: Document thread-safety guarantees
6. **Backward Compatibility**: Avoid breaking existing API contracts
7. **Testing**: Add comprehensive unit tests for all code paths
-61
View File
@@ -1,61 +0,0 @@
# PR Complexity Classifier — CI Triage Prompt
## Purpose
Quickly classify a RocksDB pull request as **simple** or **complex** so the
downstream reviewer can pick an appropriate thinking budget.
## Output Contract (STRICT)
Your final response MUST be exactly one of these two lowercase tokens, on a
line by itself, with no other text:
```
simple
```
or
```
complex
```
If you are unsure, output `complex`. The downstream review will use this token
to set its thinking budget — when in doubt, prefer the more thorough budget.
## Classification Heuristics
Treat a PR as **simple** when ALL of the following hold:
- Diff touches < ~200 lines of non-test code
- No changes to public headers under `include/rocksdb/`
- No changes to on-disk format (SST block layout, WAL record layout,
manifest, options file format, version edit encoding)
- No changes to compaction picker, write-path locking, recovery, or
WAL/memtable lifecycle
- No new public option, no new statistics counter, no new RPC/serialized
message
- Tests-only or docs-only changes
- Trivial refactors (rename, comment, dead-code removal, lint fixes)
- One-line bug fix with obvious root cause and a focused regression test
Treat a PR as **complex** when ANY of the following hold:
- Touches files in `db/`, `db/compaction/`, `db/blob/`, `cache/`,
`table/block_based/`, `file/`, `env/io_*` with > ~50 lines of logic change
- Modifies thread-safety/synchronization (mutexes, atomics, memory ordering,
refcounting, condvars)
- Changes serialization or on-disk format
- Changes public API surface in `include/rocksdb/`
- Adds a new feature flag, option, or compaction style
- Touches transactions (`utilities/transactions/`), backup/checkpoint,
user-defined timestamps, or remote compaction
- Cross-cutting refactor spanning > 5 directories
## How To Decide
1. Read the diff summary and changed-file list provided below.
2. Skim the diff hunks — focus on which subsystems are touched and whether
the change is mechanical vs. semantic.
3. Apply the heuristics above. Default to `complex` if the rules conflict.
4. Output the single token. No preamble. No explanation.
## Tool Use
You may use `View`, `GlobTool`, and `GrepTool` to peek at one or two files
if the diff snippet alone is ambiguous, but keep this fast — this is a
triage step, not a review. Do NOT spawn sub-agents.
-3
View File
@@ -1,3 +0,0 @@
You are an expert C++ engineer for RocksDB.
Read CLAUDE.md in the repo root and claude_md/ files for project context.
Answer thoroughly with exact file paths and line numbers.
-54
View File
@@ -1,54 +0,0 @@
Read review-findings.md. This file contains partial code review findings
from a session that ran out of turns before finishing. Reformat them into
a clean final review comment.
## Required Output Structure
Use this exact structure so the PR page stays scrollable:
```markdown
## Summary
> **Partial review** — the analysis was interrupted before all perspectives
> were completed. Findings below cover only the perspectives that finished.
> You can request a fresh full review with `/claude-review`.
<!-- One or two sentences of overall assessment. -->
**High-severity findings (N):**
- **[file.cc:123]** One-line description. <!-- repeat per HIGH finding -->
<!-- If no HIGH findings were salvaged, write: -->
<!-- _No high-severity findings recovered._ -->
<details>
<summary>Recovered findings (click to expand)</summary>
### Findings
#### :red_circle: HIGH
... (H1, H2, ...)
#### :yellow_circle: MEDIUM
... (M1, M2, ...)
#### :green_circle: LOW / NIT
... (L1, L2, ...)
### Cross-Component Analysis
<!-- Whatever cross-component results were captured. -->
### Positive Observations
<!-- Optional. -->
</details>
```
## Rules
- The `## Summary`, the partial-review notice, and the HIGH bullet list MUST
stay outside the `<details>` block.
- All per-finding detail and analysis MUST live inside the `<details>` block.
- Do NOT nest `<details>` blocks.
- Do NOT add any text after the closing `</details>` — the comment-builder
appends its own footer.
- Output ONLY the formatted review. No commentary, no explanation.
-679
View File
@@ -1,679 +0,0 @@
# Code Review Workflow — CI Prompt
## Purpose
Thorough multi-agent code review for RocksDB commits following CLAUDE.md guidelines,
with structured codebase exploration, inter-agent debate, and verification.
IMPORTANT — Where the review goes: Your FINAL RESPONSE TEXT is the review.
The PR comment is generated verbatim from your final response, so the
complete, polished review MUST appear there in full. Do NOT end your turn with
a meta-summary such as "the review has been written to review-findings.md" —
paste the entire review as your response.
review-findings.md is a RECOVERY BACKSTOP, not the primary output: after
completing EACH major phase (Setup, Codebase Context, Initial Review, Debate,
Synthesis), append your current findings to it with the Write tool, and after
the final synthesis overwrite it with the complete review. This preserves
partial results if the turn limit interrupts the run (a recovery step reads
this file); it does NOT substitute for outputting the full review as your
final response.
## Workflow Steps
### 1. Setup Phase
- Read CLAUDE.md to understand review guidelines
- Identify the commit/diff/PR to review
- The PR diff is provided below in this prompt. The repository is already
checked out — use local file search tools (Grep, Glob, Read) to explore.
- Parse the changed files and categorize them (API, core logic, tests, etc.)
- Read all changed files to build full context
### 2. Codebase Context Phase (CRITICAL — Do Not Skip)
**Why this matters**: Review agents that only see the diff miss systemic bugs.
For example, a change to an iterator's return value might look correct in
isolation but break multi-SST iteration 5 layers up the call stack. A change
to error handling might silently drop errors that a caller 3 levels up relies
on for recovery. This phase builds the context that prevents those blind spots.
Go deep. Surface-level reading leads to reviews that miss caching layers,
existing helper functions, or concurrency requirements. The most expensive
failure mode is findings that look correct in isolation but miss how the
change breaks the surrounding system.
The team lead spawns one or more research agents to perform the following
analyses using local file search tools (Grep, Glob, Read). The research
must be written to `context.md` BEFORE any review agent is spawned.
#### 2a. Subsystem Deep-Read
Read the changed files AND their surrounding subsystem **in depth** — not just
signatures, but actual logic, edge cases, data flows, locking protocols,
concurrency patterns, and interactions between components.
For each changed file, also read:
- The header that declares its interface (if the change is in a .cc file)
- The sibling implementation that does the same thing the "standard" way
(e.g., for a UDI iterator change, read how `IndexBlockIter` handles the
same scenario — it's the reference implementation)
- The wrapper/adapter layer that sits between this code and its callers
- Any existing tests to understand what behaviors are currently guaranteed
#### 2b. Caller-Chain Analysis (upstream impact)
For each changed function/method, trace the call chain UPWARD 3-5 levels to
understand who consumes the changed behavior and what invariants they rely on.
**Focus on control flow decisions** — if/else branches, while loop conditions,
early returns — that depend on the changed return values or state.
**How to do this**:
- Search for callers of each changed function (search for the function name, the
class method, virtual overrides)
- For each caller, search for ITS callers, repeating 3-5 levels up
- At each level, read the actual code to understand the control flow decision
- Stop when you reach a "terminal" caller (e.g., user-facing API, top-level
iterator) or when the propagation is clearly safe
#### 2c. Callee-Chain Analysis (downstream dependencies AND side effects)
For each changed function, trace what it calls and whether those calls have
new preconditions or changed semantics. **Critically, trace SIDE EFFECTS —
not just return values.** Many bugs hide in side effects on shared state
(counters, sequence numbers, flags) that are invisible if you only check
return values.
**For each callee, ask:**
1. What does it RETURN? (the obvious check)
2. What shared state does it MUTATE? (the non-obvious check)
3. Under what PRECONDITIONS does it operate correctly?
4. Are those preconditions met in the new calling context?
#### 2d. Sibling Implementation Comparison
Identify the "reference" or "standard" implementation that does the same thing
the changed code does, and compare their behavior. This is critical for plugin/
extension APIs where the implementation must match an implicit contract.
#### 2e. Invariant Documentation
Document the key invariants that the changed code must maintain. Read existing
comments, assertions, and test expectations to discover these invariants.
#### 2f. Related Functionality and Existing Conventions
Identify related functionality that already exists in the codebase:
- Are there existing helper functions the change should use (or is duplicating)?
- Are there existing patterns for the same kind of change (e.g., how other
Customizable subclasses handle deprecation)?
- Are there existing tests that test similar scenarios (e.g., multi-SST
iteration tests that could be extended)?
#### 2g. Cross-Component Data Consumer Analysis (CRITICAL — common blind spot)
**Why this is separate from caller-chain analysis:** Sections 2b-2c trace
who CALLS the changed functions. This section traces who CONSUMES the data
that the changed code PRODUCES. These are often completely different
subsystems.
When the change writes data to a shared structure (memtable, SST block, cache
entry, statistics counter), ask: **"Who reads this data, under what rules,
and do those rules match the writer's assumptions?"**
**How to do this:**
1. Identify every piece of data the change WRITES (e.g., a range tombstone
entry, a counter update, a metadata field)
2. For each, search the codebase for ALL readers of that data structure
3. For each reader, check:
- Does the reader apply visibility rules (seqno, read_callback, snapshot)?
- Are those rules compatible with the writer's assumptions?
- Does the reader assume invariants about the data (e.g., seqno ordering,
monotonicity) that the writer might violate?
#### 2h. Alternative Execution Contexts
The same code path may run in different contexts with different assumptions.
**Enumerate all contexts and check each one.** This is where "works in the
common case but breaks in edge configurations" bugs hide.
For RocksDB, always check whether the changed code interacts differently with:
| Context | Key difference | Common failure mode |
|---------|---------------|-------------------|
| WritePreparedTxnDB / WriteUnpreparedTxnDB | `read_callback_` controls visibility, not just seqno | Visibility bypass |
| ReadOnly DB / SecondaryInstance | No mutable memtable, writes not allowed | Null pointer or no-op needed |
| CompactionService / Remote compaction | Different process, serialized state | Serialization mismatch |
| User-defined timestamps | Extra dimension in key comparison and visibility | Wrong ordering |
| MemPurge | Memtable-to-memtable, not memtable-to-SST | Missing data |
| Column family with BlobDB | Values may be in blob files, not inline | Missing dereference |
| Snapshots (old, held long-term) | Snapshot seqno may be far behind current state | Metadata corruption |
| Concurrent writers (allow_concurrent_memtable_write) | Lock-free paths vs locked paths | Lost updates |
| FIFO / Universal compaction | Different compaction invariants than Level | Wrong assumptions |
| Prefix seek / total order seek | Different iterator behavior | Wrong iteration results |
**For each context, ask:**
1. Does the code execute in this context? (Check constructor, feature flags)
2. If yes, do the assumptions still hold?
3. If not, should the feature be disabled in this context?
#### 2i. Assumption Stress-Testing (the "logically X" audit)
When the change claims a property (e.g., "logically redundant," "no-op in
this case," "safe because X"), **systematically break it:**
1. **State the claim precisely.** E.g., "The inserted range tombstone is
logically redundant — it covers only keys already deleted by point
tombstones."
2. **List the preconditions** that must be true for the claim to hold.
3. **For each precondition, construct a counterexample** — a concrete scenario
where the precondition is violated.
4. **Verify each counterexample against the code.** Does the code guard
against it? If not, it's a bug.
**Anti-pattern: treating asserts as proofs.** When you see an assert, do NOT
conclude "the invariant holds." Instead ask: "Can I construct an input where
this assert fires?" If yes, it's a bug (the assert catches it in debug but
release builds silently corrupt). If you cannot construct a counterexample
after trying, document WHY it's impossible.
#### 2j. Write Context Document
Write the complete analysis to `context.md` in the review folder. This document
is provided to ALL review agents as part of their prompt.
**Context document template**:
```markdown
# Codebase Context for Review
## How the Relevant Subsystem Works Today
[Detailed description of the subsystem architecture, data flows,
and component interactions. Not just "what" but "how" and "why."]
## Changed Functions and Their Call Chains
### function_name() (file:line)
**What changed**: [brief description of the behavioral change]
**Upstream callers** (who depends on this):
1. CallerA::method() (file:line) — uses return value to decide X
2. CallerB::method() (file:line) — passes result to CallerC
3. CallerC::method() (file:line) — THE CRITICAL DECISION POINT: ...
**Downstream callees** (what this depends on):
1. calleeA() — behavior unchanged
2. calleeB() — NEW dependency, requires X
**Sibling implementation** (how the "standard" version handles this):
- StandardImpl::method() does Y at file:line, which ensures invariant Z
- The changed code must match or document any deviation
**Key invariants**:
- Must never return X when Y is true because CallerC will...
- Must always set Z before returning because CallerB assumes...
## System Architecture Context
[How the changed components fit into the overall system]
## Known Invariants That Must Be Preserved
1. ...
2. ...
## Existing Conventions and Related Code
- [helper functions, patterns, existing tests that are relevant]
## Cross-Component Data Consumers
For each piece of data the change WRITES to a shared structure:
### [data item] written to [structure]
**Writer assumptions**: [what the writer assumes about how this data is consumed]
**All readers**:
1. ReaderA::method() (file:line) — reads under [visibility rules]
- Compatible with writer? YES/NO. If NO, explain the mismatch.
2. ReaderB::method() (file:line) — reads under [different rules]
- Compatible with writer? YES/NO.
## Alternative Execution Contexts
| Context | Does code execute? | Assumptions hold? | Action needed? |
|---------|-------------------|-------------------|----------------|
| WritePreparedTxnDB | YES/NO | YES/NO | [disable/guard/safe] |
| Old snapshots | YES/NO | YES/NO | ... |
| User-defined timestamps | YES/NO | YES/NO | ... |
| ReadOnly DB | YES/NO | YES/NO | ... |
| ... | ... | ... | ... |
## Assumption Stress Test
### Claim: "[the design claim, e.g., logically redundant]"
**Preconditions for claim to hold:**
1. [precondition] — counterexample: [scenario]. Guarded? YES/NO.
2. [precondition] — counterexample: [scenario]. Guarded? YES/NO.
## Potential Pitfalls
- [specific scenarios where the change could interact badly with
the surrounding system, identified from the caller-chain analysis]
```
### 3. Initial Review Phase (Parallel)
Create a team and spawn 5 review agents in parallel. **Include the context
document from Phase 2 in each agent's prompt.** Each agent writes findings
to its own file and sends a summary message to the team lead.
Each agent's prompt should include:
```
## Codebase Context (READ THIS FIRST)
[paste or reference the context.md file]
You MUST consider how your findings interact with the upstream callers
and system invariants documented above. A finding that looks correct
in isolation may be a critical bug when you consider the full call chain.
```
#### Agent: Design & Approach Reviewer
- Read the commit message deeply to understand the problem being solved
- Analyze whether this is the right approach to the problem
- Consider alternative designs and trade-offs:
- Are there simpler solutions that achieve the same goal?
- Does the approach introduce unnecessary complexity?
- Would a different data structure or algorithm be more appropriate?
- Evaluate whether the change follows existing architectural patterns or
introduces new patterns that may be inconsistent
- Assess the scope: is the change too large? Should it be split into
smaller, independently reviewable pieces?
- Check if the approach has precedent in the codebase or in the academic
literature it references (e.g., SuRF paper)
#### Agent: Correctness Reviewer
- Thread safety and concurrency analysis
- Error handling and propagation via Status type
- Edge cases (empty inputs, overflow, boundary conditions)
- Data corruption scenarios
- Logic correctness of new algorithms
- **Behavioral contract changes**: Do return value semantics match what
upstream callers expect? (Use the caller-chain analysis from context.md)
- **Callee side effects**: Does the change call functions that mutate shared
state (counters, seqnos, metadata)? Are the mutations correct for the new
calling context? (Use the callee-chain analysis from context.md)
#### Agent: Cross-Component & Adversarial Reviewer
This agent exists because the most critical bugs hide at component boundaries,
not within a single component. It uses a fundamentally different methodology
than the correctness reviewer: instead of verifying "does the code do what it
intends?", it asks "what breaks when we change the assumptions?"
**Data-flow analysis:** Perform the cross-component data consumer analysis
described in section 2g. For every piece of data the change WRITES to a shared
structure, trace ALL READERS and verify their visibility rules are compatible
with the writer's assumptions. This is a DATA-FLOW question, not a
CONTROL-FLOW question — readers may be in completely different subsystems.
**Alternative execution contexts:** Use the canonical table from section 2h.
Enumerate all contexts where the changed code executes and verify assumptions
hold in each.
**Assumption stress-testing and assert-breaking:** Follow the methodology from
section 2i. Identify every design claim, enumerate preconditions, construct
counterexamples. Treat asserts as hypotheses to break, not proofs.
**Red flag words**: "logically redundant", "safe because", "no-op",
"always true", "cannot happen", "invariant holds"
**Callee side-effect audit:** Perform the callee side-effect audit described
in section 2c. For every callee, ask what it RETURNS and what it MUTATES.
Write findings to `findings-cross-component.md`.
#### Agent: Invariant Adversary
This agent does NOT read the diff in detail. It takes the feature summary and
systematically tries to break it. While other agents verify "does the code do
what it says?", this agent asks "what existing system invariants does this
feature violate?" and "under what inputs do the design claims fail?"
**Steps 1-4: Assumption stress-testing.** Follow the methodology from section
2i: extract design claims, enumerate preconditions, construct counterexamples,
and attempt to break every assert. Be exhaustive about input parameter ranges,
shared state configurations, and concurrent interleaving.
**Step 5: Callee side-effect audit.** Perform the callee side-effect audit
described in section 2c. For every function the changed code calls, list ALL
mutations to shared state (atomic CAS loops, counter increments, flag/metadata
updates, cache invalidation). A function returning `Status::OK()` does NOT
mean its side effects are correct.
Write findings to `findings-invariant-adversary.md`.
#### Agent: Caller-Context Auditor
This agent traces BACKWARD from every entry point the changed code hooks into.
While other agents read the changed code forward ("what does it do?"), this
agent enumerates WHO invokes it and WITH WHAT parameter ranges.
The key insight: a function that is correct for all *typical* inputs may be
catastrophically wrong for *atypical-but-reachable* inputs. This agent's job
is to find the atypical inputs.
**Step 1: Identify entry points.** List every function/constructor/method in
the changed code that receives external input (parameters, config values,
pointers to shared state). Include:
- Constructor parameters (e.g., `active_mem`, `read_callback`, `sequence`)
- Virtual method overrides that callers invoke polymorphically
- Functions called from multiple subsystems
**Step 2: Enumerate all callers (3-5 levels up).** For each entry point,
search the codebase for ALL callers. Do NOT stop at the first caller — trace
the full call chain. Use `Grep` and `Glob` to find:
- Direct callers of the function
- Callers of wrapper/adapter functions that forward to it
- Factory functions that construct the object
- Virtual dispatch sites (search for the base class method name)
**Step 3: Parameter range analysis.** For each caller, determine:
- What values does it pass for each parameter?
- Under what conditions does it call this function?
- Are there callers that pass unusual values? (e.g., `kMaxSequenceNumber`,
`nullptr`, old snapshot seqnos, non-null `read_callback_`)
Build a parameter range table for each entry point, listing all callers
and the values they pass for each parameter.
**Step 4: Configuration matrix.** Enumerate option/config combinations that
affect the changed code path:
- Which options enable/disable the feature?
- Which options change the execution context? (e.g.,
`allow_concurrent_memtable_write`, `use_trie_index`)
- Are there option combinations that create contradictions?
**Step 5: Cross-reference with context.md.** Compare your caller analysis
with the invariants and execution contexts documented in context.md. Flag
any caller that violates an assumed precondition.
Write findings to `findings-caller-audit.md`.
#### Agent: Performance Reviewer
- Memory allocation on hot paths
- Unnecessary copies (string, buffer)
- Cache efficiency and data locality
- Loop optimization opportunities
- Branch prediction (LIKELY/UNLIKELY)
- Zero-overhead design verification
#### Agent: API & Compatibility Reviewer
- Public API backwards compatibility
- API consistency with existing patterns
- Documentation completeness
- Deprecation policy compliance
- Forward compatibility (struct extensibility)
- **Behavioral compatibility**: Do changed semantics (e.g., kOutOfBound vs
kUnknown) break implicit contracts with callers?
#### Agent: Serialization & Deserialization Reviewer
- Format correctness and versioning
- Alignment requirements
- Integer overflow in size computations
- Bounds checking on untrusted data
- Crafted input attack vectors
#### Agent: Test Coverage Reviewer
- Edge case coverage
- Failure mode testing (corruption, truncation)
- Round-trip testing (build → serialize → deserialize → verify)
- Integration test coverage
- **System-level test coverage**: Are the caller-chain interactions tested?
(e.g., multi-SST iteration with UDI, level compaction with new behavior)
- Test quality (no flaky patterns, good assertions)
### 4. Round-Robin Debate Phase
After all 5 agents complete their initial review, the team lead orchestrates
a structured debate:
#### Step 4a: Share findings
- Team lead sends each agent a summary of ALL other agents' findings
(or instructs each agent to read the other agents' findings files)
#### Step 4b: Critique round (2 rounds)
Each agent reviews the findings from the other agents and sends messages to
challenge, support, or refine them:
- **Challenge**: "I disagree with [agent] [finding] because [evidence]."
- **Support**: "I independently found the same issue — this confirms it."
- **Refine**: "[Finding A] is actually a consequence of [Finding B].
The root cause is the same."
The debate assignment follows a round-robin pattern:
```
correctness-reviewer → critiques → invariant-adversary, serialization
cross-component-reviewer → critiques → correctness, caller-audit
invariant-adversary → critiques → correctness, cross-component
caller-audit → critiques → invariant-adversary, cross-component
performance-reviewer → critiques → api, cross-component
api-reviewer → critiques → correctness, performance
serialization-reviewer → critiques → correctness, invariant-adversary
test-reviewer → critiques → serialization, caller-audit
design-reviewer → critiques → cross-component, invariant-adversary
```
**Note:** The invariant-adversary and caller-audit agents are deliberately
cross-linked with correctness and cross-component because their findings
often reveal the same underlying bug from different angles (invariant
violation vs reachable bad input vs data-flow mismatch).
Each agent should:
1. Read the assigned agents' findings files
2. Send a critique message to each assigned agent
3. Respond to critiques received from other agents
4. Update their own findings file with any revisions (upgraded/downgraded severity,
withdrawn findings, new findings inspired by others)
#### Step 4c: Team lead collects debate results
- Read all updated findings files
- Review the debate messages
- Build consensus: findings supported by 2+ agents → HIGH confidence
- Write consensus document with final severity classifications
### 5. Consensus Phase
Team lead synthesizes the debate into a consensus document:
- Cross-reference overlapping findings across agents
- Count agreement (majority = 2+ agents independently flagging or supporting)
- Note disagreements and how they were resolved
- Classify findings as HIGH/MEDIUM/LOW severity
- Write consensus document
### 6. Summary Phase
- Compile all validated findings ordered by severity
- Include detailed bug analysis (root cause, vulnerable code paths)
- Include suggested fixes
- Note which findings were debated and the outcome
- Output the complete review as your final response text (this becomes the PR
comment verbatim), and also overwrite review-findings.md with the identical
content as a recovery backstop
**Final report quality rules:**
- The final report must be CLEAN and POLISHED. No stream-of-consciousness,
no "Wait, actually...", no "on closer re-examination". Those belong in
the working notes, not the output.
- If a finding was raised during review but later disproven during debate
or deeper analysis, REMOVE IT entirely from the final report. Do not
include it with a retraction — just drop it.
- If a finding was downgraded (e.g., Critical → Suggestion), present it
at the final severity only. Do not narrate the severity change.
- Each finding in the final report should read as a confident, verified
conclusion — not a record of the analysis process.
- The reader should never see the reviewer arguing with itself.
**REQUIRED output structure (so the PR page stays scrollable):**
Your final response — which becomes the PR comment verbatim — (and the
identical contents of `review-findings.md`) MUST follow this exact structure.
The summary appears first so reviewers can see HIGH findings at a glance;
everything else is hidden behind a `<details>` block.
```markdown
## Summary
<!-- One or two sentences of overall assessment. -->
**High-severity findings (N):**
- **[file.cc:123]** One-line description of the issue. <!-- repeat per HIGH finding -->
<!-- If there are NO high-severity findings, write exactly: -->
<!-- _No high-severity findings._ -->
<details>
<summary>Full review (click to expand)</summary>
### Findings
#### :red_circle: HIGH
##### H1. <Title> — `file.cc:123`
- **Issue:** ...
- **Root cause:** ...
- **Suggested fix:** ...
#### :yellow_circle: MEDIUM
... (same structure: M1, M2, ...)
#### :green_circle: LOW / NIT
... (same structure: L1, L2, ...)
### Cross-Component Analysis
<!-- Execution-context table and assumption stress-test results. -->
### Positive Observations
<!-- Optional: good patterns, clever optimizations. -->
</details>
```
Rules for this structure:
- The top-level `## Summary` and the bullet list of HIGH findings MUST stay
outside the `<details>` block — they are always visible.
- Every detail (per-finding root cause, fix, debate outcomes, cross-component
analysis, positive observations) MUST live inside the `<details>` block.
- Do NOT nest a `<details>` inside another `<details>`.
- Do NOT add any text after the closing `</details>` — the comment-builder
appends its own footer.
- Your final response MUST be the review itself in this structure — never a
meta-summary like "the review has been written to review-findings.md". The
PR comment is generated verbatim from your final response.
- If the review is partial (recovery path), still produce the summary block
first, and put whatever was salvaged inside the `<details>` block.
## Review Checklist
### Context Phase (must be completed before agents spawn)
- [ ] Subsystem deep-read — read changed files AND surrounding subsystem
in depth (logic, edge cases, data flows, locking, concurrency)
- [ ] Caller chain for every changed public/virtual method (3-5 levels up)
- [ ] Critical decision points where callers branch on changed behavior
- [ ] Callee chain with SIDE EFFECTS — downstream dependencies, new
preconditions, AND mutations to shared state (section 2c)
- [ ] Sibling implementations — how does the standard version handle same scenarios?
- [ ] Invariants that callers rely on
- [ ] Related functionality — existing helpers, patterns, conventions
- [ ] Cross-component data consumers — for every data WRITTEN, find ALL readers
and verify visibility rules match (section 2g)
- [ ] Alternative execution contexts verified (section 2h table)
- [ ] Assumption stress-test — for every design claim, list preconditions
and construct counterexamples (section 2i)
- [ ] Multi-component interactions (compaction, recovery, snapshots, iterators)
- [ ] Configuration dependencies and unexpected option combinations
- [ ] Potential pitfalls from caller-chain analysis
### Review Phase (verified by agents)
- [ ] Database semantics preserved (snapshot isolation, key ordering)
- [ ] All error cases handled
- [ ] Thread-safe with correct synchronization
- [ ] No data races or deadlocks
- [ ] Appropriate test coverage (edge cases, failure modes, system-level)
- [ ] No unnecessary allocations or copies in hot paths
- [ ] Backwards compatible
- [ ] New APIs consistent with existing patterns and documented
- [ ] Code follows RocksDB style conventions
- [ ] Behavioral contracts with upstream callers preserved
- [ ] All callers enumerated with parameter range table
## Output Structure
Your **final response text is the primary output** — it becomes the PR comment
verbatim. The files below are working artifacts and recovery backstops only;
they are NOT a substitute for outputting the full review in your final response.
Write these artifacts to the working directory root:
- `review-findings.md` — Recovery backstop: incremental findings appended after
each phase, overwritten with the final synthesized review at the end. Used
only if the turn limit interrupts the run.
- `context.md` — Codebase context (call chains, invariants)
- `findings-*.md` — Per-agent findings (design, correctness, cross-component,
invariant-adversary, caller-audit, performance, api, serialization, tests)
- `consensus.md` — Cross-review consensus (post-debate)
## Team Structure
```
Team Lead (you)
│
├── Phase 2: Codebase Context (team lead or dedicated research agent)
│ └── context-researcher (general-purpose agent)
│ ├── Trace caller chains (3-5 levels up)
│ ├── Trace callee chains (dependencies AND side effects)
│ ├── Trace data consumers (who reads what the change writes?)
│ └── Document invariants
│
├── Phase 3: Initial Review (parallel, run_in_background)
│ │ (all agents receive context.md in their prompt)
│ ├── design-reviewer (general-purpose agent)
│ ├── correctness-reviewer (general-purpose agent)
│ ├── cross-component-reviewer (general-purpose agent)
│ ├── invariant-adversary (general-purpose agent) ← NEW
│ ├── caller-audit (general-purpose agent) ← NEW
│ ├── performance-reviewer (general-purpose agent)
│ ├── api-reviewer (general-purpose agent)
│ ├── serialization-reviewer (general-purpose agent)
│ └── test-reviewer (general-purpose agent)
│
├── Phase 4: Debate (agents message each other)
│ ├── correctness ↔ invariant-adversary, serialization
│ ├── cross-component ↔ correctness, caller-audit
│ ├── invariant-adversary ↔ correctness, cross-component
│ ├── caller-audit ↔ invariant-adversary, cross-component
│ ├── performance ↔ api, cross-component
│ ├── api ↔ correctness, performance
│ ├── serialization ↔ correctness, invariant-adversary
│ ├── test-coverage ↔ serialization, caller-audit
│ └── design ↔ cross-component, invariant-adversary
│
```
## Agent Communication Protocol
### During Initial Review (Phase 3)
- Each agent writes findings to its own file
- Each agent sends a summary message to team lead when done
- Agents do NOT communicate with each other yet
### During Debate (Phase 4)
- Team lead sends each agent a message with instructions to:
1. Read the assigned agents' findings files
2. Send critique messages to those agents
3. Respond to incoming critiques
4. Update their own findings file with revisions
- Each critique message should include:
- Which finding they're addressing (e.g., "Correctness F1")
- Whether they AGREE, DISAGREE, or want to REFINE
- Their reasoning with code evidence
- Suggested severity adjustment (if any)
### Message format example
```
To: correctness-reviewer
Re: Your Finding F1
AGREE/DISAGREE/REFINE - [reasoning with code evidence].
[Suggested severity adjustment if any.]
```
## Review Anti-Patterns
These recurring failure modes lead to missed bugs. Each is detailed in the
referenced section; this table is a quick-reference checklist.
| Anti-Pattern | Fix | Reference |
|---|---|---|
| Return-Value Tunnel Vision | Trace callee MUTATIONS, not just returns | Section 2c |
| Default-Configuration Bias | Enumerate all execution contexts | Section 2h |
| Assert-as-Proof | Try to BREAK every assert | Section 2i |
| Write-Path-Only Analysis | Trace data readers, not just writers | Section 2g |
| Confirmation-Seeking Research | Use adversarial prompts ("find where X fails") | Invariant Adversary agent |
| Data-Flow vs Control-Flow Confusion | Separate who CALLS from who READS the data | Section 2g |
-67
View File
@@ -1,67 +0,0 @@
# Manual (Local) Code Review — Lightweight Wrapper
## What this is
A resource-light, **single-reviewer** variant of `claude_md/ci_review_prompt.md`
for running a review by hand in a local Claude Code / Devmate session. It reuses
the full CI review *methodology* but drops the multi-agent orchestration and the
CI-only file-persistence machinery, to approximate the heavyweight result at a
fraction of the cost.
**Scope: LOCAL manual review only. This file is NOT used by CI.** CI uses
`claude_md/ci_review_prompt.md`.
## How to use
Read `claude_md/ci_review_prompt.md` for the complete methodology — the analysis
techniques (caller-chain, callee side-effects, cross-component data consumers,
alternative execution contexts, assumption stress-testing), the per-perspective
reviewer instructions, the review checklist, and the anti-patterns table.
Then apply that methodology with the OVERRIDES below. **Where this file
conflicts with `ci_review_prompt.md`, this file wins.**
## Overrides (this is what makes it lightweight)
### 1. Single reviewer — no team, no subagents
- Do NOT create a team, spawn subagents, or run parallel/background agents.
- Do NOT run the round-robin Debate phase or the Consensus phase.
- Instead, YOU personally apply each reviewer role from `ci_review_prompt.md`
(Design, Correctness, Cross-Component & Adversarial, Invariant Adversary,
Caller-Context, Performance, API/Compat, Serialization, Test Coverage) as
sequential *lenses* in one pass. Spend a few focused minutes per lens. Skip
lenses that plainly don't apply (e.g., Serialization when there is no on-disk
or wire-format change) and note the skip in one line.
### 2. No intermediate files
- Do NOT write `context.md`, `findings-*.md`, `consensus.md`, or
`review-findings.md`. Keep working notes in your reasoning, not on disk.
- Rationale: those files exist only so CI can recover partial results when an
ephemeral runner hits the turn limit — a local session has neither problem.
`ci_review_prompt.md` already outputs the review as its final response, so
skipping the file loses nothing here.
### 3. Right-size the effort
- Do the Codebase Context phase, but proportionally: trace the 2-3 most
load-bearing call chains and the highest-risk cross-component data consumers,
rather than exhaustively enumerating every caller 3-5 levels up.
- Prioritize the highest-signal lenses for RocksDB: **Correctness**,
**Cross-Component & Adversarial**, and **Assumption Stress-Testing**. These
catch the bugs that matter most; give them the most attention.
- Escalation clause: if a thread looks dangerous, go deep on that specific
thread even though the overall pass is modest. Modest is the default, not a cap.
### 4. Identify the review target locally
- Unlike CI, the diff is NOT pre-pasted into this prompt. Determine what to
review from the user's request against the local worktree — e.g. the current
commit (`git show`), uncommitted changes (`git diff` / `git diff --staged`),
a named commit range, or a PR — and read the changed files plus their
surrounding context directly from the repo. When in doubt, include all changes
not yet upstream, as in
`git diff "$(git merge-base upstream/main HEAD 2> /dev/null || git merge-base origin/main HEAD 2> /dev/null)"`
plus any untracked files (`git status`) that seem relevant.
## Reminder
The goal is a thorough *single* reviewer, not a 9-agent debate: depth where it
matters, brevity everywhere else.
Loaded 100 of 875 files, more files were not shown because too many files have changed in this diff. Show more